Merge branch 'linux'

This commit is contained in:
Lion Kortlepel 2024-06-17 21:57:41 +02:00
commit 05ffa0b638
No known key found for this signature in database
GPG Key ID: 4322FF2B4C71259B
20 changed files with 1661 additions and 551 deletions

34
.github/workflows/cmake-linux.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: CMake Linux Build
on: [push, pull_request, workflow_dispatch]
env:
BUILD_TYPE: Release
jobs:
linux-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: 'true'
- name: Create Build Environment
run: cmake -E make_directory ${{github.workspace}}/build-linux
- name: Configure CMake
shell: bash
working-directory: ${{github.workspace}}/build-linux
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE
- name: Build
working-directory: ${{github.workspace}}/build-linux
shell: bash
run: cmake --build . --config $BUILD_TYPE
- name: Archive artifacts
uses: actions/upload-artifact@v2
with:
name: BeamMP-Launcher
path: ${{github.workspace}}/build-linux/BeamMP-Launcher

View File

@ -1,6 +1,6 @@
name: CMake Windows Build name: CMake Windows Build
on: [push, pull_request] on: [push, pull_request, workflow_dispatch]
env: env:
BUILD_TYPE: Release BUILD_TYPE: Release

View File

@ -28,6 +28,7 @@ jobs:
body: | body: |
Files included in this release: Files included in this release:
- `BeamMP-Launcher.exe` windows build - `BeamMP-Launcher.exe` windows build
- `BeamMP-Launcher` linux build
upload-release-files-windows: upload-release-files-windows:
name: Upload Windows Release Files name: Upload Windows Release Files
@ -70,3 +71,34 @@ jobs:
asset_path: ${{github.workspace}}/build-windows/Release/BeamMP-Launcher.exe asset_path: ${{github.workspace}}/build-windows/Release/BeamMP-Launcher.exe
asset_name: BeamMP-Launcher.exe asset_name: BeamMP-Launcher.exe
asset_content_type: application/vnd.microsoft.portable-executable asset_content_type: application/vnd.microsoft.portable-executable
upload-release-files-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: 'true'
- name: Create Build Environment
run: cmake -E make_directory ${{github.workspace}}/build-linux
- name: Configure CMake
shell: bash
working-directory: ${{github.workspace}}/build-linux
run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE
- name: Build
working-directory: ${{github.workspace}}/build-linux
shell: bash
run: cmake --build . --config $BUILD_TYPE
- name: Upload Release Asset
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps
asset_path: ${{github.workspace}}/build-linux/BeamMP-Launcher
asset_name: BeamMP-Launcher
asset_content_type: application/octet-stream

View File

@ -12,7 +12,7 @@ set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
file(GLOB source_files "src/*.cpp" "src/*/*.cpp" "src/*/*.hpp" "include/*.h" "include/*/*.h" "include/*/*/*.h") file(GLOB source_files "src/*.cpp" "src/*/*.cpp" "src/*/*.hpp" "include/*.h" "include/*/*.h" "include/*/*/*.h" "include/*.hpp" "include/*/*.hpp" "include/*/*/*.hpp")
find_package(httplib CONFIG REQUIRED) find_package(httplib CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED) find_package(nlohmann_json CONFIG REQUIRED)
@ -24,6 +24,11 @@ if (WIN32)
find_package(OpenSSL REQUIRED) find_package(OpenSSL REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE target_link_libraries(${PROJECT_NAME} PRIVATE
ZLIB::ZLIB OpenSSL::SSL OpenSSL::Crypto ws2_32 httplib::httplib nlohmann_json::nlohmann_json) ZLIB::ZLIB OpenSSL::SSL OpenSSL::Crypto ws2_32 httplib::httplib nlohmann_json::nlohmann_json)
elseif (LINUX)
find_package(ZLIB REQUIRED)
find_package(OpenSSL REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE
ZLIB::ZLIB OpenSSL::SSL OpenSSL::Crypto)
else(WIN32) #MINGW else(WIN32) #MINGW
add_definitions("-D_WIN32_WINNT=0x0600") add_definitions("-D_WIN32_WINNT=0x0600")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Os -s --static") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Os -s --static")

View File

@ -9,6 +9,16 @@
#pragma once #pragma once
#include <string> #include <string>
#ifdef __linux__
#include <cstdint>
#include "linuxfixes.h"
#include <bits/types/siginfo_t.h>
#include <sys/ucontext.h>
#endif
void NetReset(); void NetReset();
extern bool Dev; extern bool Dev;
extern int ping; extern int ping;

19
include/linuxfixes.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef _LINUXFIXES_H
#define _LINUXFIXES_H
#include <stdint.h>
// Translate windows sockets stuff to linux sockets
#define SOCKET uint64_t
#define SOCKADDR sockaddr
#define SOCKADDR_IN sockaddr_in
#define WSAGetLastError() errno
#define closesocket close
#define SD_BOTH SHUT_RDWR
// We dont need wsacleanup
#define WSACleanup()
#define SOCKET_ERROR -1
#define ZeroMemory(mem, len) memset(mem, 0, len)
#endif

730
include/vdf_parser.hpp Normal file
View File

@ -0,0 +1,730 @@
//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__
#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 tyti
{
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
//forward decl
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 mailformatted, parser will try to read it until it can.
@param first begin iterator
@param end end iterator
@param exclude_files list of files which cant be included anymore.
prevents circular includes
can thow:
- "std::runtime_error" if a parsing error occured
- "std::bad_alloc" if not enough memory coup 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: iterator poition to the position after a '/'
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 not 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 wasnt 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 = conditional_fullfilled(curIter, last);
if (!conditional)
continue;
while (*curIter == TYTI_L(charT, '/'))
{
curIter = skip_comments(curIter, last);
if (curIter == last || *curIter == '}')
throw std::runtime_error{ "key declared, but no value" };
curIter = skip_whitespaces(curIter, last);
if (curIter == last || *curIter == '}')
throw std::runtime_error{ "key declared, but no 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 = conditional_fullfilled(curIter, last);
if (!conditional)
continue;
// process value
if (key != TYTI_L(charT, "#include") && key != TYTI_L(charT, "#base"))
{
if (curObj)
{
curObj->add_attribute(std::move(key), std::move(value));
}
else
{
throw std::runtime_error{ "unexpected key without object" };
}
}
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 (curObj && *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;
}
else
{
throw std::runtime_error{ "unexpected '}'" };
}
}
if (curObj != nullptr || !lvls.empty())
{
throw std::runtime_error{ "object is not closed with '}'" };
}
return roots;
}
} // namespace detail
/** \brief Read VDF formatted sequences defined by the range [first, last).
If the file is mailformatted, parser will try to read it until it can.
@param first begin iterator
@param end end iterator
can thow:
- "std::runtime_error" if a parsing error occured
- "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 mailformatted, parser will try to read it until it can.
@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 mailformatted
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 mailformatted, parser will try to read it until it can.
@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
} // namespace tyti
#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__

View File

@ -8,6 +8,9 @@
#include <iostream> #include <iostream>
#include <zlib.h> #include <zlib.h>
#ifdef __linux__
#include <cstring>
#endif
#define Biggest 30000 #define Biggest 30000
std::string Comp(std::string Data){ std::string Comp(std::string Data){
@ -27,7 +30,7 @@ std::string Comp(std::string Data){
deflateEnd(&defstream); deflateEnd(&defstream);
int TO = defstream.total_out; int TO = defstream.total_out;
std::string Ret(TO,0); std::string Ret(TO,0);
memcpy_s(&Ret[0],TO,C,TO); memcpy(&Ret[0],C,TO);
delete [] C; delete [] C;
return Ret; return Ret;
} }
@ -48,7 +51,7 @@ std::string DeComp(std::string Compressed){
inflateEnd(&infstream); inflateEnd(&infstream);
int TO = infstream.total_out; int TO = infstream.total_out;
std::string Ret(TO,0); std::string Ret(TO,0);
memcpy_s(&Ret[0],TO,C,TO); memcpy(&Ret[0],C,TO);
delete [] C; delete [] C;
return Ret; return Ret;
} }

View File

@ -3,7 +3,7 @@
/// ///
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "Network/network.h" #include "Network/network.hpp"
#include <filesystem> #include <filesystem>
#include "Logger.h" #include "Logger.h"
#include <fstream> #include <fstream>

View File

@ -6,13 +6,26 @@
/// Created by Anonymous275 on 7/19/2020 /// Created by Anonymous275 on 7/19/2020
/// ///
#include <Security/Init.h>
#if defined(_WIN32)
#include <windows.h> #include <windows.h>
#elif defined(__linux__)
#include "vdf_parser.hpp"
#include <pwd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <spawn.h>
#endif
#include <Security/Init.h>
#include <filesystem>
#include "Startup.h" #include "Startup.h"
#include "Logger.h" #include "Logger.h"
#include <thread> #include <thread>
unsigned long GamePID = 0; unsigned long GamePID = 0;
#if defined(_WIN32)
std::string QueryKey(HKEY hKey,int ID); std::string QueryKey(HKEY hKey,int ID);
std::string GetGamePath(){ std::string GetGamePath(){
static std::string Path; static std::string Path;
@ -40,7 +53,21 @@ std::string GetGamePath(){
Path += Ver + "\\"; Path += Ver + "\\";
return Path; return Path;
} }
#elif defined(__linux__)
std::string GetGamePath(){
// Right now only steam is supported
struct passwd *pw = getpwuid(getuid());
std::string homeDir = pw->pw_dir;
std::string Path = homeDir + "/.local/share/BeamNG.drive/";
std::string Ver = CheckVer(GetGameDir());
Ver = Ver.substr(0,Ver.find('.',Ver.find('.')+1));
Path += Ver + "/";
return Path;
}
#endif
#if defined(_WIN32)
void StartGame(std::string Dir){ void StartGame(std::string Dir){
BOOL bSuccess = FALSE; BOOL bSuccess = FALSE;
PROCESS_INFORMATION pi; PROCESS_INFORMATION pi;
@ -61,6 +88,45 @@ void StartGame(std::string Dir){
std::this_thread::sleep_for(std::chrono::seconds(5)); std::this_thread::sleep_for(std::chrono::seconds(5));
exit(2); exit(2);
} }
#elif defined(__linux__)
void StartGame(std::string Dir) {
int status;
std::string filename = (Dir + "/BinLinux/BeamNG.drive.x64");
char *argv[] = {filename.data(), NULL};
pid_t pid;
int result = posix_spawn(&pid, filename.c_str(), NULL, NULL, argv, environ);
if (result != 0) {
error("Failed to Launch the game! launcher closing soon");
return;
} else {
waitpid(pid, &status, 0);
error("Game Closed! launcher closing soon");
}
std::this_thread::sleep_for(std::chrono::seconds(5));
exit(2);
}
#endif
void StartGame(std::string Dir) {
int status;
std::string filename = (Dir + "/BinLinux/BeamNG.drive.x64");
char *argv[] = {filename.data(), NULL};
pid_t pid;
int result = posix_spawn(&pid, filename.c_str(), NULL, NULL, argv, environ);
if (result != 0) {
error("Failed to Launch the game! launcher closing soon");
return;
} else {
waitpid(pid, &status, 0);
error("Game Closed! launcher closing soon");
}
std::this_thread::sleep_for(std::chrono::seconds(5));
exit(2);
}
#endif
void InitGame(const std::string& Dir){ void InitGame(const std::string& Dir){
if(!Dev){ if(!Dev){

View File

@ -5,13 +5,22 @@
/// ///
/// Created by Anonymous275 on 7/20/2020 /// Created by Anonymous275 on 7/20/2020
/// ///
#include "Network/network.hpp"
#include "Network/network.h"
#include "Security/Init.h" #include "Security/Init.h"
#include <regex> #include <regex>
#include "Http.h" #include "Http.h"
#if defined(_WIN32)
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#elif defined(__linux__)
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <cstring>
#include <errno.h>
#endif
#include "Startup.h" #include "Startup.h"
#include "Logger.h" #include "Logger.h"
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
@ -207,13 +216,18 @@ void localRes(){
} }
void CoreMain() { void CoreMain() {
debug("Core Network on start!"); debug("Core Network on start!");
WSADATA wsaData;
SOCKET LSocket,CSocket; SOCKET LSocket,CSocket;
struct addrinfo *res = nullptr; struct addrinfo *res = nullptr;
struct addrinfo hints{}; struct addrinfo hints{};
int iRes = WSAStartup(514, &wsaData); //2.2 int iRes;
#ifdef _WIN32
WSADATA wsaData;
iRes = WSAStartup(514, &wsaData); //2.2
if (iRes)debug("WSAStartup failed with error: " + std::to_string(iRes)); if (iRes)debug("WSAStartup failed with error: " + std::to_string(iRes));
#endif
ZeroMemory(&hints, sizeof(hints)); ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET; hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP; hints.ai_protocol = IPPROTO_TCP;
@ -261,6 +275,8 @@ void CoreMain() {
KillSocket(LSocket); KillSocket(LSocket);
WSACleanup(); WSACleanup();
} }
#if defined(_WIN32)
int Handle(EXCEPTION_POINTERS *ep){ int Handle(EXCEPTION_POINTERS *ep){
char* hex = new char[100]; char* hex = new char[100];
sprintf_s(hex,100, "%lX", ep->ExceptionRecord->ExceptionCode); sprintf_s(hex,100, "%lX", ep->ExceptionRecord->ExceptionCode);
@ -268,17 +284,24 @@ int Handle(EXCEPTION_POINTERS *ep){
delete [] hex; delete [] hex;
return 1; return 1;
} }
#endif
[[noreturn]] void CoreNetwork(){ [[noreturn]] void CoreNetwork(){
while(true) { while(true) {
#ifndef __MINGW32__ #if not defined(__MINGW32__)
__try{ __try{
#endif #endif
CoreMain(); CoreMain();
#ifndef __MINGW32__
#if not defined(__MINGW32__) and not defined(__linux__)
}__except(Handle(GetExceptionInformation())){} }__except(Handle(GetExceptionInformation())){}
#elif not defined(__MINGW32__) and defined(__linux__)
} catch(...){
except("(Core) Code : " + std::string(strerror(errno)));
}
#endif #endif
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));
} }
} }

View File

@ -7,18 +7,29 @@
/// ///
#include <string> #include <string>
#if defined(_WIN32)
#include <winsock2.h> #include <winsock2.h>
#elif defined(__linux__)
#include "linuxfixes.h"
#include <netdb.h>
#include <arpa/inet.h>
#endif
#include "Logger.h" #include "Logger.h"
std::string GetAddr(const std::string&IP){ std::string GetAddr(const std::string&IP){
if(IP.find_first_not_of("0123456789.") == -1)return IP; if(IP.find_first_not_of("0123456789.") == -1)return IP;
WSADATA wsaData;
hostent *host; hostent *host;
#ifdef _WIN32
WSADATA wsaData;
if(WSAStartup(514, &wsaData) != 0){ if(WSAStartup(514, &wsaData) != 0){
error("WSA Startup Failed!"); error("WSA Startup Failed!");
WSACleanup(); WSACleanup();
return ""; return "";
} }
#endif
host = gethostbyname(IP.c_str()); host = gethostbyname(IP.c_str());
if(!host){ if(!host){
error("DNS lookup failed! on " + IP); error("DNS lookup failed! on " + IP);

View File

@ -5,9 +5,20 @@
/// ///
/// Created by Anonymous275 on 7/25/2020 /// Created by Anonymous275 on 7/25/2020
/// ///
#include "Network/network.h" #include "Network/network.hpp"
#if defined(_WIN32)
#include <winsock2.h> #include <winsock2.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>
#elif defined(__linux__)
#include "linuxfixes.h"
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <cstring>
#endif
#include "Logger.h" #include "Logger.h"
#include <charconv> #include <charconv>
#include <string> #include <string>
@ -117,12 +128,16 @@ SOCKET SetupListener(){
if(GSocket != -1)return GSocket; if(GSocket != -1)return GSocket;
struct addrinfo *result = nullptr; struct addrinfo *result = nullptr;
struct addrinfo hints{}; struct addrinfo hints{};
int iRes;
#ifdef _WIN32
WSADATA wsaData; WSADATA wsaData;
int iRes = WSAStartup(514, &wsaData); //2.2 iRes = WSAStartup(514, &wsaData); //2.2
if (iRes != 0) { if (iRes != 0) {
error("(Proxy) WSAStartup failed with error: " + std::to_string(iRes)); error("(Proxy) WSAStartup failed with error: " + std::to_string(iRes));
return -1; return -1;
} }
#endif
ZeroMemory(&hints, sizeof(hints)); ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET; hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;

View File

@ -6,8 +6,19 @@
/// Created by Anonymous275 on 4/11/2020 /// Created by Anonymous275 on 4/11/2020
/// ///
#include "Network/network.h" #include "Network/network.hpp"
#if defined(_WIN32)
#include <ws2tcpip.h> #include <ws2tcpip.h>
#elif defined(__linux__)
#include <sys/socket.h>
#include <sys/types.h>
#include <cstring>
#include <errno.h>
#include <netdb.h>
#include <arpa/inet.h>
#endif
#include <filesystem> #include <filesystem>
#include "Startup.h" #include "Startup.h"
#include "Logger.h" #include "Logger.h"
@ -38,7 +49,12 @@ std::vector<std::string> Split(const std::string& String,const std::string& deli
void CheckForDir(){ void CheckForDir(){
if(!fs::exists("Resources")){ if(!fs::exists("Resources")){
// Could we just use fs::create_directory instead?
#if defined(_WIN32)
_wmkdir(L"Resources"); _wmkdir(L"Resources");
#elif defined(__linux__)
fs::create_directory(L"Resources");
#endif
} }
} }
void WaitForConfirm(){ void WaitForConfirm(){
@ -202,10 +218,10 @@ std::string MultiDownload(SOCKET MSock,SOCKET DSock, uint64_t Size, const std::s
///omg yes very ugly my god but i was in a rush will revisit ///omg yes very ugly my god but i was in a rush will revisit
std::string Ret(Size,0); std::string Ret(Size,0);
memcpy_s(&Ret[0],MSize,MData,MSize); memcpy(&Ret[0],MData,MSize);
delete[]MData; delete[]MData;
memcpy_s(&Ret[MSize],DSize,DData,DSize); memcpy(&Ret[MSize],DData,DSize);
delete[]DData; delete[]DData;
return Ret; return Ret;
@ -268,9 +284,21 @@ void SyncResources(SOCKET Sock){
fs::create_directories(GetGamePath() + "mods/multiplayer"); fs::create_directories(GetGamePath() + "mods/multiplayer");
} }
auto name = GetGamePath() + "mods/multiplayer" + a.substr(a.find_last_of('/')); auto name = GetGamePath() + "mods/multiplayer" + a.substr(a.find_last_of('/'));
#if defined(__linux__)
// Linux version of the game doesnt support uppercase letters in mod names
for(char &c : name){
c = ::tolower(c);
}
#endif
auto tmp_name = name + ".tmp"; auto tmp_name = name + ".tmp";
fs::copy_file(a,tmp_name,fs::copy_options::overwrite_existing); fs::copy_file(a,tmp_name,fs::copy_options::overwrite_existing);
fs::rename(tmp_name, name); fs::rename(tmp_name, name);
for(char &c : FName){
c = ::tolower(c);
}
#endif
fs::copy_file(a, GetGamePath() + "mods/multiplayer" + FName,
} catch (std::exception& e) { } catch (std::exception& e) {
error("Failed copy to the mods folder! " + std::string(e.what())); error("Failed copy to the mods folder! " + std::string(e.what()));
Terminate = true; Terminate = true;
@ -310,6 +338,14 @@ void SyncResources(SOCKET Sock){
if(!fs::exists(GetGamePath() + "mods/multiplayer")){ if(!fs::exists(GetGamePath() + "mods/multiplayer")){
fs::create_directories(GetGamePath() + "mods/multiplayer"); fs::create_directories(GetGamePath() + "mods/multiplayer");
} }
// Linux version of the game doesnt support uppercase letters in mod names
#if defined(__linux__)
for(char &c : FName){
c = ::tolower(c);
}
#endif
fs::copy_file(a,GetGamePath() + "mods/multiplayer" + FName, fs::copy_options::overwrite_existing); fs::copy_file(a,GetGamePath() + "mods/multiplayer" + FName, fs::copy_options::overwrite_existing);
} }
WaitForConfirm(); WaitForConfirm();

View File

@ -6,9 +6,20 @@
/// Created by Anonymous275 on 5/8/2020 /// Created by Anonymous275 on 5/8/2020
/// ///
#include "Zlib/Compressor.h" #include "Zlib/Compressor.h"
#include "Network/network.h" #include "Network/network.hpp"
#if defined(_WIN32)
#include <ws2tcpip.h> #include <ws2tcpip.h>
#elif defined(__linux__)
#include <sys/socket.h>
#include <sys/types.h>
#include <cstring>
#include <errno.h>
#include <netdb.h>
#include <arpa/inet.h>
#include "linuxfixes.h"
#endif
#include "Logger.h" #include "Logger.h"
#include <string> #include <string>
#include <set> #include <set>
@ -44,7 +55,11 @@ void UDPParser(std::string Packet){
} }
void UDPRcv(){ void UDPRcv(){
sockaddr_in FromServer{}; sockaddr_in FromServer{};
#if defined(_WIN32)
int clientLength = sizeof(FromServer); int clientLength = sizeof(FromServer);
#elif defined(__linux__)
socklen_t clientLength = sizeof(FromServer);
#endif
ZeroMemory(&FromServer, clientLength); ZeroMemory(&FromServer, clientLength);
std::string Ret(10240,0); std::string Ret(10240,0);
if(UDPSock == -1)return; if(UDPSock == -1)return;
@ -53,11 +68,14 @@ void UDPRcv(){
UDPParser(Ret.substr(0,Rcv)); UDPParser(Ret.substr(0,Rcv));
} }
void UDPClientMain(const std::string& IP,int Port){ void UDPClientMain(const std::string& IP,int Port){
#ifdef _WIN32
WSADATA data; WSADATA data;
if (WSAStartup(514, &data)){ if (WSAStartup(514, &data)){
error("Can't start Winsock!"); error("Can't start Winsock!");
return; return;
} }
#endif
delete ToServer; delete ToServer;
ToServer = new sockaddr_in; ToServer = new sockaddr_in;
ToServer->sin_family = AF_INET; ToServer->sin_family = AF_INET;

View File

@ -10,11 +10,20 @@
#include <vector> #include <vector>
#include "Logger.h" #include "Logger.h"
#include <iostream> #include <iostream>
#include <ws2tcpip.h>
#include <Zlib/Compressor.h> #include <Zlib/Compressor.h>
#include "Network/network.h" #if defined(_WIN32)
#include <ws2tcpip.h>
#elif defined(__linux__)
#include <sys/socket.h>
#include <sys/types.h>
#include <cstring>
#include <errno.h>
#include <netdb.h>
#include <arpa/inet.h>
#endif
#include "Network/network.hpp"
int LastPort; int LastPort;
std::string LastIP; std::string LastIP;
@ -116,10 +125,12 @@ std::string TCPRcv(SOCKET Sock){
void TCPClientMain(const std::string& IP,int Port){ void TCPClientMain(const std::string& IP,int Port){
LastIP = IP; LastIP = IP;
LastPort = Port; LastPort = Port;
WSADATA wsaData;
SOCKADDR_IN ServerAddr; SOCKADDR_IN ServerAddr;
int RetCode; int RetCode;
#ifdef _WIN32
WSADATA wsaData;
WSAStartup(514, &wsaData); //2.2 WSAStartup(514, &wsaData); //2.2
#endif
TCPSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); TCPSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(TCPSock == -1){ if(TCPSock == -1){
@ -127,6 +138,7 @@ void TCPClientMain(const std::string& IP,int Port){
WSACleanup(); WSACleanup();
return; return;
} }
ServerAddr.sin_family = AF_INET; ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(Port); ServerAddr.sin_port = htons(Port);
inet_pton(AF_INET, IP.c_str(), &ServerAddr.sin_addr); inet_pton(AF_INET, IP.c_str(), &ServerAddr.sin_addr);
@ -152,6 +164,9 @@ void TCPClientMain(const std::string& IP,int Port){
if(KillSocket(TCPSock) != 0) if(KillSocket(TCPSock) != 0)
debug("(TCP) Cannot close socket. Error code: " + std::to_string(WSAGetLastError())); debug("(TCP) Cannot close socket. Error code: " + std::to_string(WSAGetLastError()));
#ifdef _WIN32
if(WSACleanup() != 0) if(WSACleanup() != 0)
debug("(TCP) Client: WSACleanup() failed!..."); debug("(TCP) Client: WSACleanup() failed!...");
#endif
} }

View File

@ -7,7 +7,14 @@
/// ///
#include <filesystem> #include <filesystem>
#if defined(_WIN32)
#include <windows.h> #include <windows.h>
#elif defined(__linux__)
#include "vdf_parser.hpp"
#include <vector>
#include <pwd.h>
#include <unistd.h>
#endif
#include "Logger.h" #include "Logger.h"
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
@ -46,8 +53,13 @@ void SteamExit(int code){
}*/ }*/
std::string GetGameDir(){ std::string GetGameDir(){
//if(TraceBack != 4)Exit(0); //if(TraceBack != 4)Exit(0);
#if defined(_WIN32)
return GameDir.substr(0,GameDir.find_last_of('\\')); return GameDir.substr(0,GameDir.find_last_of('\\'));
#elif defined(__linux__)
return GameDir.substr(0,GameDir.find_last_of('/'));
#endif
} }
#ifdef _WIN32
LONG OpenKey(HKEY root,const char* path,PHKEY hKey){ LONG OpenKey(HKEY root,const char* path,PHKEY hKey){
return RegOpenKeyEx(root, reinterpret_cast<LPCSTR>(path), 0, KEY_READ, hKey); return RegOpenKeyEx(root, reinterpret_cast<LPCSTR>(path), 0, KEY_READ, hKey);
} }
@ -129,6 +141,8 @@ std::string QueryKey(HKEY hKey,int ID){
delete [] buffer; delete [] buffer;
return ""; return "";
} }
#endif
namespace fs = std::filesystem; namespace fs = std::filesystem;
bool NameValid(const std::string& N){ bool NameValid(const std::string& N){
@ -286,6 +300,7 @@ void LegitimacyCheck(){
}else lowExit(2); }else lowExit(2);
K2.clear(); K2.clear();
RegCloseKey(hKey);*/ RegCloseKey(hKey);*/
#if defined(_WIN32)
std::string Result; std::string Result;
std::string K3 = R"(Software\BeamNG\BeamNG.drive)"; std::string K3 = R"(Software\BeamNG\BeamNG.drive)";
HKEY hKey; HKEY hKey;
@ -301,9 +316,27 @@ void LegitimacyCheck(){
Result.clear(); Result.clear();
RegCloseKey(hKey); RegCloseKey(hKey);
//if(TraceBack < 3)exit(-1); //if(TraceBack < 3)exit(-1);
#elif defined(__linux__)
struct passwd *pw = getpwuid(getuid());
std::string homeDir = pw->pw_dir;
// Right now only steam is supported
std::ifstream libraryFolders(homeDir + "/.steam/root/steamapps/libraryfolders.vdf");
auto root = tyti::vdf::read(libraryFolders);
for (auto folderInfo: root.childs){
if (std::filesystem::exists(folderInfo.second->attribs["path"] + "/steamapps/common/BeamNG.drive/")){
GameDir = folderInfo.second->attribs["path"] + "/steamapps/common/BeamNG.drive/";
break;
}
}
#endif
} }
std::string CheckVer(const std::string &dir){ std::string CheckVer(const std::string &dir){
#if defined(_WIN32)
std::string temp,Path = dir + "\\integrity.json"; std::string temp,Path = dir + "\\integrity.json";
#elif defined(__linux__)
std::string temp,Path = dir + "/integrity.json";
#endif
std::ifstream f(Path.c_str(), std::ios::binary); std::ifstream f(Path.c_str(), std::ios::binary);
int Size = int(std::filesystem::file_size(Path)); int Size = int(std::filesystem::file_size(Path));
std::string vec(Size,0); std::string vec(Size,0);

View File

@ -9,8 +9,13 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <httplib.h> #include <httplib.h>
#include "zip_file.h" #include "zip_file.h"
#include <string>
#if defined(_WIN32)
#include <windows.h> #include <windows.h>
#include "Network/network.h" #elif defined(__linux__)
#include <unistd.h>
#endif
#include "Network/network.hpp"
#include "Security/Init.h" #include "Security/Init.h"
#include <filesystem> #include <filesystem>
#include "Startup.h" #include "Startup.h"
@ -53,10 +58,14 @@ bool VersionParser::operator==(const VersionParser& rhs) const noexcept {
return std::is_eq(*this <=> rhs); return std::is_eq(*this <=> rhs);
} }
std::string GetEN(){ std::string GetEN(){
#if defined(_WIN32)
return "BeamMP-Launcher.exe"; return "BeamMP-Launcher.exe";
#elif defined(__linux__)
return "BeamMP-Launcher";
#endif
} }
std::string GetVer(){ std::string GetVer(){
return "2.0"; return "2.0";
} }
@ -71,6 +80,7 @@ std::string GetEP(char*P){
} (); } ();
return Ret; return Ret;
} }
#if defined(_WIN32)
void ReLaunch(int argc,char*args[]){ void ReLaunch(int argc,char*args[]){
std::string Arg; std::string Arg;
for(int c = 2; c <= argc; c++){ for(int c = 2; c <= argc; c++){
@ -94,8 +104,36 @@ void URelaunch(int argc,char* args[]){
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));
exit(1); exit(1);
} }
#elif defined(__linux__)
void ReLaunch(int argc,char*args[]){
std::string Arg;
for(int c = 2; c <= argc; c++){
Arg += " ";
Arg += args[c-1];
}
system("clear");
execl((GetEP() + GetEN()).c_str(), Arg.c_str(), NULL);
std::this_thread::sleep_for(std::chrono::seconds(1));
exit(1);
}
void URelaunch(int argc,char* args[]){
std::string Arg;
for(int c = 2; c <= argc; c++){
Arg += " ";
Arg += args[c-1];
}
execl((GetEP() + GetEN()).c_str(), Arg.c_str(), NULL);
std::this_thread::sleep_for(std::chrono::seconds(1));
exit(1);
}
#endif
void CheckName(int argc,char* args[]){ void CheckName(int argc,char* args[]){
#if defined(_WIN32)
std::string DN = GetEN(),CDir = args[0],FN = CDir.substr(CDir.find_last_of('\\')+1); std::string DN = GetEN(),CDir = args[0],FN = CDir.substr(CDir.find_last_of('\\')+1);
#elif defined(__linux__)
std::string DN = GetEN(),CDir = args[0],FN = CDir.substr(CDir.find_last_of('/')+1);
#endif
if(FN != DN){ if(FN != DN){
if(fs::exists(DN))remove(DN.c_str()); if(fs::exists(DN))remove(DN.c_str());
if(fs::exists(DN))ReLaunch(argc,args); if(fs::exists(DN))ReLaunch(argc,args);
@ -113,6 +151,10 @@ void CheckForUpdates(int argc, char* args[], const std::string& CV) {
std::string EP(GetEP() + GetEN()), Back(GetEP() + "BeamMP-Launcher.back"); std::string EP(GetEP() + GetEN()), Back(GetEP() + "BeamMP-Launcher.back");
std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, EP); std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, EP);
#if defined(_WIN32)
#elif defined(__linux__)
system("clear");
#endif
if (FileHash != LatestHash && VersionParser(LatestVersion) > VersionParser(GetVer()+GetPatch())) { if (FileHash != LatestHash && VersionParser(LatestVersion) > VersionParser(GetVer()+GetPatch())) {
info("Launcher update found!"); info("Launcher update found!");
@ -142,6 +184,7 @@ void CustomPort(int argc, char* argv[]){
} }
} }
#ifdef _WIN32
void LinuxPatch(){ void LinuxPatch(){
HKEY hKey = nullptr; HKEY hKey = nullptr;
LONG result = RegOpenKeyEx(HKEY_CURRENT_USER, R"(Software\Wine)", 0, KEY_READ, &hKey); LONG result = RegOpenKeyEx(HKEY_CURRENT_USER, R"(Software\Wine)", 0, KEY_READ, &hKey);
@ -167,7 +210,9 @@ void LinuxPatch(){
info("Patched!"); info("Patched!");
} }
#endif
#if defined(_WIN32)
void InitLauncher(int argc, char* argv[]) { void InitLauncher(int argc, char* argv[]) {
system("cls"); system("cls");
SetConsoleTitleA(("BeamMP Launcher v" + std::string(GetVer()) + GetPatch()).c_str()); SetConsoleTitleA(("BeamMP Launcher v" + std::string(GetVer()) + GetPatch()).c_str());
@ -179,6 +224,17 @@ void InitLauncher(int argc, char* argv[]) {
CustomPort(argc, argv); CustomPort(argc, argv);
CheckForUpdates(argc, argv, std::string(GetVer()) + GetPatch()); CheckForUpdates(argc, argv, std::string(GetVer()) + GetPatch());
} }
#elif defined(__linux__)
void InitLauncher(int argc, char* argv[]) {
system("clear");
InitLog();
CheckName(argc, argv);
CheckLocalKey();
ConfigInit();
CustomPort(argc, argv);
CheckForUpdates(argc, argv, std::string(GetVer()) + GetPatch());
}
#endif
size_t DirCount(const std::filesystem::path& path){ size_t DirCount(const std::filesystem::path& path){
return (size_t)std::distance(std::filesystem::directory_iterator{path}, std::filesystem::directory_iterator{}); return (size_t)std::distance(std::filesystem::directory_iterator{path}, std::filesystem::directory_iterator{});
@ -249,8 +305,12 @@ void PreGame(const std::string& GamePath){
}catch(std::exception&e){ }catch(std::exception&e){
fatal(e.what()); fatal(e.what());
} }
#if defined(_WIN32)
std::string ZipPath(GetGamePath() + R"(mods\multiplayer\BeamMP.zip)"); std::string ZipPath(GetGamePath() + R"(mods\multiplayer\BeamMP.zip)");
#elif defined(__linux__)
// Linux version of the game cant handle mods with uppercase names
std::string ZipPath(GetGamePath() + R"(mods/multiplayer/beammp.zip)");
#endif
std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, ZipPath); std::string FileHash = hashpp::get::getFileHash(hashpp::ALGORITHMS::SHA2_256, ZipPath);

View File

@ -5,7 +5,7 @@
/// ///
/// Created by Anonymous275 on 7/16/2020 /// Created by Anonymous275 on 7/16/2020
/// ///
#include "Network/network.h" #include "Network/network.hpp"
#include "Security/Init.h" #include "Security/Init.h"
#include "Startup.h" #include "Startup.h"
#include <iostream> #include <iostream>