76 Commits

Author SHA1 Message Date
Lion
cc4e322065 Merge pull request #88 from saile515/fix-input-linux
Fix input not working on Linux
2024-05-29 11:13:05 +02:00
saile515
915c05c57c fix input not working on linux 2024-05-29 10:56:22 +02:00
gamingdoom
35ad09dd5f Remove extra newline 2023-10-17 21:01:38 -07:00
gamingdoom
8ed2921ec1 remove .vscode 2023-10-17 20:41:15 -07:00
gamingdoom
1bf7faa34d fix guest account issue and uppercase mods 2023-10-17 20:40:11 -07:00
gamingdoom
8ead91c527 Update release-build.yml 2023-10-17 19:31:40 -07:00
gamingdoom
5e602a651c Fix linux build artifact path 2023-10-17 19:18:48 -07:00
gamingdoom
0993b2a463 fix linux build name ... again 2023-10-17 19:16:17 -07:00
gamingdoom
73ada2b541 fix linux build name 2023-10-17 19:15:44 -07:00
gamingdoom
f9bd0967bc Add github actions Linux build 2023-10-17 19:14:54 -07:00
gamingdoom
16b13c074e remove debug symbols 2023-10-17 19:13:16 -07:00
gamingdoom
0a9a883ca4 fix windows build 2023-10-17 18:59:49 -07:00
gamingdoom
a91735531a linux build 2023-10-17 18:53:01 -07:00
gamingdoom
f98ff3f502 Update cmake-windows.yml 2023-10-17 18:38:59 -07:00
gamingdoom
5dfb5f3b88 works but linux build is broken and this is an old version of the source 2023-10-16 22:13:30 -07:00
gamingdoom
54e1beb548 rename network.h to network.hpp 2023-10-16 17:33:52 -07:00
Anonymous275
839bb48cd6 Merge pull request #58 from WhiteHusky/patch-1
Emit a useful message if cleaning the mods folder fails
2023-08-04 20:30:36 +01:00
Carlen White
c4ebdda1a4 Emit a useful message if cleaning the mods folder fails
The launcher complains if it can not delete a file when it's trying to clean the mods folder out. However the message it emits is unhelpful and does not offer a suggestion to what is going on.

This commit addresses this issue by telling the user what the launcher is trying to do and suggests checking if something is currently open in that directory. I figure not having to go into detail in *where* the folder is not necessary and (primarily) only happens if the user is inspecting the folder themselves and already knows where the folder is.
2023-07-02 23:02:14 -04:00
Anonymous275
d6b494c6c4 - release v2.0.82 2022-12-18 14:30:21 +00:00
Anonymous275
a80d4f5147 - quick fix for launcher crash 2022-12-18 14:29:38 +00:00
Anonymous275
811b04485c - try fix for github workflow 2022-12-18 13:20:20 +00:00
Simon Abed El Sater
a64fead653 update 2.0.81 2022-12-18 14:39:54 +02:00
Simon Abed El Sater
399461d1b1 remove version check 2022-12-18 14:39:28 +02:00
Anonymous275
ec5e8ed5b3 v2.0.80 2022-09-25 20:39:27 +03:00
Anonymous275
5655164e60 bump 2.0.80 2022-09-25 20:37:46 +03:00
Simon Abed El Sater
3d9b7c2d67 Merge pull request #49 from snepsnepsnep/master
Fix kick message for server 3.0+
2022-09-25 20:32:50 +03:00
snepsnepsnep
764e3ab5c1 Fix kick message for server 3.0+ 2022-09-25 19:26:46 +02:00
Simon Abed El Sater
3314362faf Merge pull request #48 from Mack29446/master
Decided by vote: Update BeamNG Version and remove Mod Delete warning & Delay
2022-09-25 01:18:58 +03:00
Mackenzie
e483f520db Bump launcher version
2.0.78 -> 2.0.79
2022-09-24 22:49:10 +01:00
Mackenzie
c92e32c0e1 Remove mod wipe warn and delay 2022-09-24 22:48:17 +01:00
Mackenzie
cb872f8a41 Update BeamNG Version 2022-09-24 22:46:38 +01:00
Anonymous275
0aae245054 release 2.0.78 2022-09-24 00:37:29 +03:00
Anonymous275
480a7d038f follow redirects if present 2022-09-24 00:37:04 +03:00
Anonymous275
f62f44d4c0 version 2.0.77 2022-09-20 22:27:26 +03:00
Anonymous275
e316b89fb1 bump 0.26 2022-09-20 22:26:51 +03:00
Anonymous275
3b2dbcac1b release 2.0.76 2022-09-05 03:23:15 +03:00
Anonymous275
d881c9faf6 release 2.0.75 2022-09-05 02:59:05 +03:00
Anonymous275
11d9375f36 fix invalid Key being used 2022-09-05 02:58:22 +03:00
Simon Abed El Sater
4207d7adcf Merge pull request #44 from snepsnepsnep/master
remove key if auth is unsuccessful
2022-09-05 02:40:50 +03:00
snepsnepsnep
832b1d66a0 remove key if auth is unsuccessful 2022-09-04 20:24:27 +02:00
Anonymous275
cd829f9f22 Update Startup.cpp
version 2.0.74
2022-08-12 12:14:31 +03:00
Anonymous275
f7c70eb6df Merge pull request #36 from Mack29446/master
Change serverlist request URL and Protocol
2022-08-12 12:11:22 +03:00
Mackenzie
01960f6470 Change serverlist request URL and Protocol 2022-08-11 20:27:26 +01:00
Anonymous275
f6065a1c00 Merge pull request #21 from Mack29446/master
Update version
2022-06-24 19:46:26 +03:00
Mackenzie
ba3b7f0ed0 Update version 2022-06-23 16:53:06 +01:00
Anonymous275
056eadbef2 Merge pull request #20 from Mack29446/master
Update version
2022-06-21 18:12:49 +03:00
Mackenzie
2bb2dc9040 Update version 2022-06-21 14:28:10 +01:00
Anonymous275
17553fd412 bump launcher version 2022-06-19 02:28:26 +03:00
Anonymous275
08c1c0f682 Merge pull request #19 from Mack29446/master
Update Version Number
2022-06-18 02:02:36 +03:00
Mackenzie
84959ae9c9 Update Version Number 2022-06-17 21:35:00 +01:00
Anonymous275
c90c102097 trying to fix github actions 2022-06-15 21:38:45 +03:00
Anonymous275
5b004426ce vcpkgGitCommitId update 2022-06-15 21:35:12 +03:00
Anonymous275
69c9060dd2 Update release-build.yml 2022-06-15 21:13:02 +03:00
Anonymous275
49870639ff Update cmake-windows.yml 2022-06-15 21:12:41 +03:00
Anonymous275
0843862af9 update for game version 0.25 2022-06-15 21:02:43 +03:00
Anonymous275
71a9a567bc 2.0.63 2021-12-03 18:45:36 +02:00
Anonymous275
a6e3d0fad9 Update cmake-windows.yml 2021-12-03 18:28:03 +02:00
Anonymous275
411d0786a5 0.24.0.1 game version bump 2021-12-03 18:18:57 +02:00
Anonymous-275
acb6b11e24 bump minor version to 62 2021-10-01 00:17:55 +03:00
Anonymous-275
1739393a73 launcher no longer extracts zip file 2021-10-01 00:11:46 +03:00
Anonymous-275
298ef33ab7 V2.0.61 2021-07-03 17:11:56 +03:00
Anonymous-275
d2433cceca V2.0.7 2021-07-03 17:10:55 +03:00
Anonymous-275
705e0ab9c4 Updated version to 0.23.1 2021-07-03 17:09:29 +03:00
Anonymous-275
53c40a2bc3 Removed debug prints 2021-07-01 18:54:36 +03:00
Anonymous-275
96c60ef05a 0.23.0.0 support 2021-07-01 18:54:06 +03:00
Anonymous-275
61759b8531 0.23.0.0 support 2021-07-01 18:53:50 +03:00
Anonymous-275
691be8cd08 Mod validity check 2021-06-02 00:02:50 +03:00
Anonymous-275
082445c295 updated gitignore 2021-05-23 20:04:34 +03:00
Anonymous-275
f4bda81be0 Added 'N' packet flag 2021-05-23 19:22:44 +03:00
Anonymous-275
1ad8e0b8e5 Minor edit 2021-05-11 22:32:46 +03:00
Anonymous-275
6c673e78e5 Fixed invalid string position, Bumped game version 2021-05-11 22:19:42 +03:00
Anonymous-275
09abe75fbb Fixed false detection of proton 2021-04-15 21:05:30 +03:00
Anonymous-275
b45e4b40f2 Auto proton patch, fix for 0.22.2.0 2021-04-15 18:22:54 +03:00
Anonymous-275
15d1539a92 v2.0.2 2021-04-04 23:42:29 +03:00
Anonymous-275
14a5f47549 Merge branch 'master' of ssh://github.com/BeamMP/BeamMP-Launcher 2021-04-04 23:41:23 +03:00
Anonymous-275
584998277d v2.0.2 2021-04-04 23:40:57 +03:00
26 changed files with 7019 additions and 106 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
on: [push, pull_request]
on: [push, pull_request, workflow_dispatch]
env:
BUILD_TYPE: Release
@@ -15,12 +15,12 @@ jobs:
submodules: 'true'
- name: Restore artifacts, or run vcpkg, build and cache artifacts
uses: lukka/run-vcpkg@main
uses: lukka/run-vcpkg@v7
id: runvcpkg
with:
vcpkgArguments: 'discord-rpc zlib rapidjson openssl'
vcpkgDirectory: '${{ runner.workspace }}/b/vcpkg'
vcpkgGitCommitId: '75522bb1f2e7d863078bcd06322348f053a9e33f'
vcpkgGitCommitId: '06b5f4a769d848d1a20fa0acd556019728b56273'
vcpkgTriplet: 'x64-windows-static'
- name: Create Build Environment

View File

@@ -28,6 +28,7 @@ jobs:
body: |
Files included in this release:
- `BeamMP-Launcher.exe` windows build
- `BeamMP-Launcher` linux build
upload-release-files-windows:
name: Upload Windows Release Files
@@ -44,7 +45,7 @@ jobs:
with:
vcpkgArguments: 'discord-rpc zlib rapidjson openssl'
vcpkgDirectory: '${{ runner.workspace }}/b/vcpkg'
vcpkgGitCommitId: '75522bb1f2e7d863078bcd06322348f053a9e33f'
vcpkgGitCommitId: '06b5f4a769d848d1a20fa0acd556019728b56273'
vcpkgTriplet: 'x64-windows-static'
- name: Create Build Environment
@@ -70,3 +71,34 @@ jobs:
asset_path: ${{github.workspace}}/build-windows/Release/BeamMP-Launcher.exe
asset_name: BeamMP-Launcher.exe
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

3
.gitignore vendored
View File

@@ -2,3 +2,6 @@ cmake-build-debug
cmake-build-release
/.idea/
*.log
/*.sh
/*.obj
/*.exe

View File

@@ -11,7 +11,7 @@ set(CMAKE_CXX_STANDARD 17)
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")
add_executable(${PROJECT_NAME} ${source_files})
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "BeamMP-Launcher")
@@ -25,6 +25,11 @@ if (WIN32)
link_directories(${VcpkgRoot}/lib)
target_link_libraries(${PROJECT_NAME} PRIVATE ${VcpkgRoot}/lib/discord-rpc.lib
ZLIB::ZLIB OpenSSL::SSL OpenSSL::Crypto ws2_32)
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
add_definitions("-D_WIN32_WINNT=0x0600")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Os -s --static")

View File

@@ -8,7 +8,7 @@
#pragma once
#include <string>
#include "Logger.h"
class HTTP{
class HTTP {
public:
static bool Download(const std::string &IP, const std::string &Path);
static std::string Post(const std::string& IP, const std::string& Fields);

View File

@@ -9,10 +9,21 @@
#pragma once
#include <string>
#ifdef __linux__
#include <cstdint>
#include "linuxfixes.h"
#include <bits/types/siginfo_t.h>
#include <sys/ucontext.h>
#endif
void NetReset();
extern bool Dev;
extern int ping;
void CoreNetwork();
[[noreturn]] void CoreNetwork();
extern int ClientID;
extern int LastPort;
extern bool ModLoaded;

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__

5710
include/zip_file.h Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -2,7 +2,7 @@
/// Created by Anonymous275 on 2/23/2021
///
#include "Network/network.h"
#include "Network/network.hpp"
#include <filesystem>
#include "Logger.h"
#include <fstream>
@@ -15,7 +15,6 @@ void ParseConfig(const json::Document& d){
if(d["Port"].IsInt()){
DEFAULT_PORT = d["Port"].GetInt();
}
//Default -1
//Release 1
//EA 2

View File

@@ -5,6 +5,9 @@
///
/// Created by Anonymous275 on 7/16/2020
///
#ifndef __linux__
#include "Discord/discord_rpc.h"
#include "Logger.h"
#include <cstring>
@@ -99,8 +102,8 @@ void ErrorAboard(){
exit(6);
}
void Discord_Main(){
std::thread t1(DMain);
t1.detach();
/*std::thread t1(DMain);
t1.detach();*/
/*info("Connecting to discord client...");
int C = 0;
while(DiscordInfo == nullptr && C < 80){
@@ -109,3 +112,5 @@ void Discord_Main(){
}
if(DiscordInfo == nullptr)ErrorAboard();*/
}
#endif

View File

@@ -6,14 +6,26 @@
/// Created by Anonymous275 on 7/19/2020
///
#include <Security/Init.h>
#if defined(_WIN32)
#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 "Logger.h"
#include <iostream>
#include <thread>
unsigned long GamePID = 0;
#if defined(_WIN32)
std::string QueryKey(HKEY hKey,int ID);
std::string GetGamePath(){
static std::string Path;
@@ -36,10 +48,26 @@ std::string GetGamePath(){
Path = QueryKey(hKey,5);
Path += "\\BeamNG.drive\\";
}
Path += CheckVer(GetGameDir()) + "\\";
std::string Ver = CheckVer(GetGameDir());
Ver = Ver.substr(0,Ver.find('.',Ver.find('.')+1));
Path += Ver + "\\";
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){
BOOL bSuccess = FALSE;
PROCESS_INFORMATION pi;
@@ -60,6 +88,27 @@ void StartGame(std::string Dir){
std::this_thread::sleep_for(std::chrono::seconds(5));
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 InitGame(const std::string& Dir){
if(!Dev){
std::thread Game(StartGame, Dir);

View File

@@ -14,16 +14,8 @@
#include <thread>
std::string getDate() {
typedef std::chrono::duration<int, std::ratio_multiply<std::chrono::hours::period, std::ratio<24>>::type> days;
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::chrono::system_clock::duration tp = now.time_since_epoch();
days d = std::chrono::duration_cast<days>(tp);tp -= d;
auto h = std::chrono::duration_cast<std::chrono::hours>(tp);tp -= h;
auto m = std::chrono::duration_cast<std::chrono::minutes>(tp);tp -= m;
auto s = std::chrono::duration_cast<std::chrono::seconds>(tp);tp -= s;
time_t tt = std::chrono::system_clock::to_time_t(now);
tm local_tm{};
localtime_s(&local_tm,&tt);
time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
tm local_tm = *localtime(&tt);
std::stringstream date;
int S = local_tm.tm_sec;
int M = local_tm.tm_min;

View File

@@ -5,12 +5,22 @@
///
/// Created by Anonymous275 on 7/20/2020
///
#include "Network/network.h"
#include "Network/network.hpp"
#include "Security/Init.h"
#include "http.h"
#include "Http.h"
#if defined(_WIN32)
#include <winsock2.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 "Logger.h"
#include <charconv>
@@ -58,7 +68,7 @@ void Parse(std::string Data,SOCKET CSocket){
NetReset();
Terminate = true;
TCPTerminate = true;
Data = Code + HTTP::Post("https://backend.beammp.com/servers","");
Data = Code + HTTP::Get("https://backend.beammp.com/servers-info");
break;
case 'C':
ListOfMods.clear();
@@ -177,13 +187,18 @@ void localRes(){
}
void CoreMain() {
debug("Core Network on start!");
WSADATA wsaData;
SOCKET LSocket,CSocket;
struct addrinfo *res = nullptr;
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));
#endif
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
@@ -231,6 +246,8 @@ void CoreMain() {
KillSocket(LSocket);
WSACleanup();
}
#if defined(_WIN32)
int Handle(EXCEPTION_POINTERS *ep){
char* hex = new char[100];
sprintf_s(hex,100, "%lX", ep->ExceptionRecord->ExceptionCode);
@@ -238,17 +255,24 @@ int Handle(EXCEPTION_POINTERS *ep){
delete [] hex;
return 1;
}
void CoreNetwork(){
while(TraceBack >= 4){
#ifndef __MINGW32__
__try{
#endif
CoreMain();
#ifndef __MINGW32__
}__except(Handle(GetExceptionInformation())){}
#endif
[[noreturn]] void CoreNetwork(){
while(true) {
#if not defined(__MINGW32__)
__try{
#endif
CoreMain();
#if not defined(__MINGW32__) and not defined(__linux__)
}__except(Handle(GetExceptionInformation())){}
#elif not defined(__MINGW32__) and defined(__linux__)
} catch(...){
except("(Core) Code : " + std::string(strerror(errno)));
}
#endif
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}

View File

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

View File

@@ -5,9 +5,20 @@
///
/// Created by Anonymous275 on 7/25/2020
///
#include "Network/network.h"
#include "Network/network.hpp"
#if defined(_WIN32)
#include <winsock2.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 <charconv>
#include <string>
@@ -75,7 +86,7 @@ void ServerSend(std::string Data, bool Rel){
int DLen = int(Data.length());
if(DLen > 3)C = Data.at(0);
if (C == 'O' || C == 'T')Ack = true;
if(C == 'W' || C == 'Y' || C == 'V' || C == 'E' || C == 'C')Rel = true;
if(C == 'N' || C == 'W' || C == 'Y' || C == 'V' || C == 'E' || C == 'C')Rel = true;
if(Ack || Rel){
if(Ack || DLen > 1000)SendLarge(Data);
else TCPSend(Data,TCPSock);
@@ -117,12 +128,16 @@ SOCKET SetupListener(){
if(GSocket != -1)return GSocket;
struct addrinfo *result = nullptr;
struct addrinfo hints{};
int iRes;
#ifdef _WIN32
WSADATA wsaData;
int iRes = WSAStartup(514, &wsaData); //2.2
iRes = WSAStartup(514, &wsaData); //2.2
if (iRes != 0) {
error("(Proxy) WSAStartup failed with error: " + std::to_string(iRes));
return -1;
}
#endif
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;

View File

@@ -10,7 +10,7 @@
#include <iostream>
#include <Logger.h>
#include <fstream>
#include "http.h"
#include "Http.h"
#include <mutex>
#include <cmath>
#include <httplib.h>
@@ -31,6 +31,7 @@ std::string HTTP::Get(const std::string &IP) {
httplib::Client cli(IP.substr(0, pos).c_str());
cli.set_connection_timeout(std::chrono::seconds(10));
cli.set_follow_location(true);
auto res = cli.Get(IP.substr(pos).c_str(), ProgressBar);
std::string Ret;

View File

@@ -6,8 +6,19 @@
/// Created by Anonymous275 on 4/11/2020
///
#include "Network/network.h"
#include "Network/network.hpp"
#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 <filesystem>
#include "Startup.h"
#include "Logger.h"
@@ -38,7 +49,12 @@ std::vector<std::string> Split(const std::string& String,const std::string& deli
void CheckForDir(){
if(!fs::exists("Resources")){
// Could we just use fs::create_directory instead?
#if defined(_WIN32)
_wmkdir(L"Resources");
#elif defined(__linux__)
fs::create_directory(L"Resources");
#endif
}
}
void WaitForConfirm(){
@@ -60,7 +76,7 @@ std::string Auth(SOCKET Sock){
auto Res = TCPRcv(Sock);
if(Res.empty() || Res[0] == 'E'){
if(Res.empty() || Res[0] == 'E' || Res[0] == 'K'){
Abord();
return "";
}
@@ -87,7 +103,7 @@ std::string Auth(SOCKET Sock){
Res = TCPRcv(Sock);
if(Res[0] == 'E'){
if(Res[0] == 'E' || Res[0] == 'K'){
Abord();
return "";
}
@@ -109,11 +125,10 @@ void UpdateUl(bool D,const std::string&msg){
void AsyncUpdate(uint64_t& Rcv,uint64_t Size,const std::string& Name){
do {
double pr = Rcv / double(Size) * 100;
double pr = double(Rcv) / double(Size) * 100;
std::string Per = std::to_string(trunc(pr * 10) / 10);
UpdateUl(true, Name + " (" + Per.substr(0, Per.find('.') + 2) + "%)");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}while(!Terminate && Rcv < Size);
}
@@ -176,8 +191,7 @@ std::string MultiDownload(SOCKET MSock,SOCKET DSock, uint64_t Size, const std::s
uint64_t GRcv = 0, MSize = Size/2, DSize = Size - MSize;
std::thread Au(AsyncUpdate,std::ref(GRcv),Size,Name);
Au.detach();
std::thread Au(AsyncUpdate,std::ref(GRcv), Size, Name);
std::packaged_task<char*()> task([&] { return TCPRcvRaw(MSock,GRcv,MSize); });
std::future<char*> f1 = task.get_future();
@@ -198,20 +212,26 @@ std::string MultiDownload(SOCKET MSock,SOCKET DSock, uint64_t Size, const std::s
MultiKill(MSock,DSock);
return "";
}
if(Au.joinable())Au.join();
///omg yes very ugly my god but i was in a rush will revisit
std::string Ret(Size,0);
memcpy_s(&Ret[0],MSize,MData,MSize);
memcpy(&Ret[0],MData,MSize);
delete[]MData;
memcpy_s(&Ret[MSize],DSize,DData,DSize);
memcpy(&Ret[MSize],DData,DSize);
delete[]DData;
return Ret;
}
void InvalidResource(const std::string& File){
UUl("Invalid mod \"" + File + "\"");
warn("The server tried to sync \"" + File + "\" that is not a .zip file!");
Terminate = true;
}
void SyncResources(SOCKET Sock){
std::string Ret = Auth(Sock);
@@ -238,6 +258,11 @@ void SyncResources(SOCKET Sock){
t.clear();
for(auto FN = FNames.begin(),FS = FSizes.begin(); FN != FNames.end() && !Terminate; ++FN,++FS) {
auto pos = FN->find_last_of('/');
auto ZIP = FN->find(".zip");
if (ZIP == std::string::npos || FN->length() - ZIP != 4) {
InvalidResource(*FN);
return;
}
if (pos == std::string::npos)continue;
Amount++;
}
@@ -258,7 +283,16 @@ void SyncResources(SOCKET Sock){
if(!fs::exists(GetGamePath() + "mods/multiplayer")){
fs::create_directories(GetGamePath() + "mods/multiplayer");
}
fs::copy_file(a, GetGamePath() + "mods/multiplayer" + a.substr(a.find_last_of('/')),
std::string FName = a.substr(a.find_last_of('/'));
// 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);
} catch (std::exception& e) {
error("Failed copy to the mods folder! " + std::string(e.what()));
@@ -299,6 +333,14 @@ void SyncResources(SOCKET Sock){
if(!fs::exists(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);
}
WaitForConfirm();

View File

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

View File

@@ -10,11 +10,20 @@
#include <vector>
#include "Logger.h"
#include <iostream>
#include <ws2tcpip.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;
std::string LastIP;
@@ -109,17 +118,19 @@ std::string TCPRcv(SOCKET Sock){
#ifdef DEBUG
//debug("Parsing from server -> " + std::to_string(Ret.size()));
#endif
if(Ret[0] == 'E')UUl(Ret.substr(1));
if(Ret[0] == 'E' || Ret[0] == 'K')UUl(Ret.substr(1));
return Ret;
}
void TCPClientMain(const std::string& IP,int Port){
LastIP = IP;
LastPort = Port;
WSADATA wsaData;
SOCKADDR_IN ServerAddr;
int RetCode;
#ifdef _WIN32
WSADATA wsaData;
WSAStartup(514, &wsaData); //2.2
#endif
TCPSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(TCPSock == -1){
@@ -127,6 +138,7 @@ void TCPClientMain(const std::string& IP,int Port){
WSACleanup();
return;
}
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(Port);
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)
debug("(TCP) Cannot close socket. Error code: " + std::to_string(WSAGetLastError()));
#ifdef _WIN32
if(WSACleanup() != 0)
debug("(TCP) Client: WSACleanup() failed!...");
#endif
}

View File

@@ -7,7 +7,14 @@
///
#include <filesystem>
#if defined(_WIN32)
#include <windows.h>
#elif defined(__linux__)
#include "vdf_parser.hpp"
#include <vector>
#include <pwd.h>
#include <unistd.h>
#endif
#include "Logger.h"
#include <fstream>
#include <sstream>
@@ -28,7 +35,7 @@ void lowExit(int code){
std::this_thread::sleep_for(std::chrono::seconds(10));
exit(2);
}
void Exit(int code){
/*void Exit(int code){
TraceBack = 0;
std::string msg =
"Sorry. We do not support cracked copies report this if you believe this is a mistake code ";
@@ -43,11 +50,16 @@ void SteamExit(int code){
error(msg+std::to_string(code));
std::this_thread::sleep_for(std::chrono::seconds(10));
exit(4);
}
}*/
std::string GetGameDir(){
if(TraceBack != 4)Exit(0);
//if(TraceBack != 4)Exit(0);
#if defined(_WIN32)
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){
return RegOpenKeyEx(root, reinterpret_cast<LPCSTR>(path), 0, KEY_READ, hKey);
}
@@ -129,6 +141,8 @@ std::string QueryKey(HKEY hKey,int ID){
delete [] buffer;
return "";
}
#endif
namespace fs = std::filesystem;
bool NameValid(const std::string& N){
@@ -244,25 +258,23 @@ std::string GetManifest(const std::string& Man){
bool IDCheck(std::string Man, std::string steam){
bool a = false,b = true;
int pos = int(Man.rfind("steamapps"));
if(pos == -1)Exit(5);
// if(pos == -1)Exit(5);
Man = Man.substr(0,pos+9) + "\\appmanifest_284160.acf";
steam += "\\config\\loginusers.vdf";
if(fs::exists(Man) && fs::exists(steam)){
for(const std::string&ID : GetID(steam)){
if(ID == GetManifest(Man))b = false;
}
if(b)Exit(6);
//if(b)Exit(6);
}else a = true;
return a;
}
void LegitimacyCheck(){
std::string Result,T;
std::string K1 = R"(Software\Valve\Steam)";
std::string K2 = R"(Software\Valve\Steam\Apps\284160)";
std::string K3 = R"(Software\BeamNG\BeamNG.drive)";
HKEY hKey;
LONG dwRegOPenKey = OpenKey(HKEY_CURRENT_USER, K1.c_str(), &hKey);
//std::string K1 = R"(Software\Valve\Steam)";
//std::string K2 = R"(Software\Valve\Steam\Apps\284160)";
/*LONG dwRegOPenKey = OpenKey(HKEY_CURRENT_USER, K1.c_str(), &hKey);
if(dwRegOPenKey == ERROR_SUCCESS) {
Result = QueryKey(hKey, 1);
@@ -287,22 +299,44 @@ void LegitimacyCheck(){
TraceBack++;
}else lowExit(2);
K2.clear();
RegCloseKey(hKey);
dwRegOPenKey = OpenKey(HKEY_CURRENT_USER, K3.c_str(), &hKey);
RegCloseKey(hKey);*/
#if defined(_WIN32)
std::string Result;
std::string K3 = R"(Software\BeamNG\BeamNG.drive)";
HKEY hKey;
LONG dwRegOPenKey = OpenKey(HKEY_CURRENT_USER, K3.c_str(), &hKey);
if(dwRegOPenKey == ERROR_SUCCESS) {
Result = QueryKey(hKey, 3);
if(Result.empty())lowExit(3);
if(IDCheck(Result,T))lowExit(5);
//if(IDCheck(Result,T))lowExit(5);
GameDir = Result;
TraceBack++;
//TraceBack++;
}else lowExit(4);
K3.clear();
Result.clear();
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){
#if defined(_WIN32)
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);
int Size = int(std::filesystem::file_size(Path));
std::string vec(Size,0);

View File

@@ -6,7 +6,7 @@
/// Created by Anonymous275 on 11/26/2020
///
#include "http.h"
#include "Http.h"
#include <filesystem>
#include "Logger.h"
#include <fstream>
@@ -18,7 +18,7 @@ extern bool LoginAuth;
std::string Role;
void UpdateKey(const char* newKey){
if(newKey){
if(newKey && std::isalnum(newKey[0])){
std::ofstream Key("key");
if(Key.is_open()){
Key << newKey;
@@ -58,17 +58,17 @@ std::string Login(const std::string& fields){
error(Buffer);
return GetFail("Invalid answer from authentication servers, please try again later!");
}
if(!d["success"].IsNull() && d["success"].GetBool()){
if(d.HasMember("success") && !d["success"].IsNull() && d["success"].GetBool()){
LoginAuth = true;
if(!d["private_key"].IsNull()){
if(d.HasMember("private_key") && !d["private_key"].IsNull()){
UpdateKey(d["private_key"].GetString());
}
if(!d["public_key"].IsNull()){
if(d.HasMember("public_key") && !d["public_key"].IsNull()){
PublicKey = d["public_key"].GetString();
}
info("Authentication successful!");
}else info("Authentication failed!");
if(!d["message"].IsNull()){
if(d.HasMember("message") && !d["message"].IsNull()){
d.RemoveMember("private_key");
d.RemoveMember("public_key");
rapidjson::StringBuffer buffer;
@@ -88,15 +88,23 @@ void CheckLocalKey(){
Key.read(&Buffer[0], Size);
Key.close();
for (char& c : Buffer) {
if (!std::isalnum(c) && c != '-') {
UpdateKey(nullptr);
return;
}
}
Buffer = HTTP::Post("https://auth.beammp.com/userlogin", R"({"pk":")" + Buffer + "\"}");
json::Document d;
d.Parse(Buffer.c_str());
if (Buffer == "-1" || Buffer.at(0) != '{' || d.HasParseError()) {
error(Buffer);
fatal("Invalid answer from authentication servers, please try again later!");
info("Invalid answer from authentication servers.");
UpdateKey(nullptr);
}
if(d["success"].GetBool()){
if(d.HasMember("success") && d["success"].GetBool()){
LoginAuth = true;
UpdateKey(d["private_key"].GetString());
PublicKey = d["public_key"].GetString();

View File

@@ -5,29 +5,45 @@
///
/// Created by Anonymous275 on 7/16/2020
///
#include "zip_file.h"
#include <string>
#if defined(_WIN32)
#include <windows.h>
#elif defined(__linux__)
#include <unistd.h>
#endif
#include "Discord/discord_info.h"
#include "Network/network.h"
#include "Network/network.hpp"
#include "Security/Init.h"
#include <filesystem>
#include "Startup.h"
#include "Logger.h"
#include <fstream>
#include <thread>
#include "http.h"
#include "Http.h"
#include "Json.h"
extern int TraceBack;
bool Dev = false;
namespace fs = std::filesystem;
#if defined(_WIN32)
std::string GetEN(){
return "BeamMP-Launcher.exe";
}
#elif defined(__linux__)
std::string GetEN(){
return "BeamMP-Launcher";
}
#endif
std::string GetVer(){
return "2.0";
}
std::string GetPatch(){
return ".2";
return ".82";
}
std::string GetEP(char*P){
static std::string Ret = [&](){
std::string path(P);
@@ -35,6 +51,7 @@ std::string GetEP(char*P){
} ();
return Ret;
}
#if defined(_WIN32)
void ReLaunch(int argc,char*args[]){
std::string Arg;
for(int c = 2; c <= argc; c++){
@@ -58,8 +75,36 @@ void URelaunch(int argc,char* args[]){
std::this_thread::sleep_for(std::chrono::seconds(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[]){
#if defined(_WIN32)
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(fs::exists(DN))remove(DN.c_str());
if(fs::exists(DN))ReLaunch(argc,args);
@@ -88,7 +133,11 @@ void CheckForUpdates(int argc,char*args[],const std::string& CV){
if(fs::exists(Back))remove(Back.c_str());
if(HTTP > CV){
#if defined(_WIN32)
system("cls");
#elif defined(__linux__)
system("clear");
#endif
info("Update found!");
info("Updating...");
if(std::rename(EP.c_str(), Back.c_str()))error("failed creating a backup!");
@@ -120,27 +169,92 @@ void CustomPort(int argc, char* argv[]){
if(argc > 2)Dev = true;
}
}
#ifdef _WIN32
void LinuxPatch(){
HKEY hKey = nullptr;
LONG result = RegOpenKeyEx(HKEY_CURRENT_USER, R"(Software\Wine)", 0, KEY_READ, &hKey);
if (result != ERROR_SUCCESS || getenv("USER") == nullptr)return;
RegCloseKey(hKey);
info("Wine/Proton Detected! If you are on windows delete HKEY_CURRENT_USER\\Software\\Wine in regedit");
info("Applying patches...");
result = RegCreateKey(HKEY_CURRENT_USER, R"(Software\Valve\Steam\Apps\284160)", &hKey);
if (result != ERROR_SUCCESS){
fatal(R"(failed to create HKEY_CURRENT_USER\Software\Valve\Steam\Apps\284160)");
return;
}
result = RegSetValueEx(hKey, "Name", 0, REG_SZ, (BYTE*)"BeamNG.drive", 12);
if (result != ERROR_SUCCESS){
fatal(R"(failed to create the value "Name" under HKEY_CURRENT_USER\Software\Valve\Steam\Apps\284160)");
return;
}
RegCloseKey(hKey);
std::string Path = R"(Z:\home\)" + std::string(getenv("USER")) + R"(\.steam\steam\Steam.exe)";
if(!fs::exists(Path)) {
std::ofstream ofs(Path);
if (!ofs.is_open()) {
fatal("Failed to create file \"" + Path + "\"");
return;
} else ofs.close();
}
result = RegOpenKeyEx(HKEY_CURRENT_USER, R"(Software\Valve\Steam)", 0, KEY_ALL_ACCESS, &hKey);
if (result != ERROR_SUCCESS){
fatal(R"(failed to open HKEY_CURRENT_USER\Software\Valve\Steam)");
return;
}
result = RegSetValueEx(hKey, "SteamExe", 0, REG_SZ, (BYTE*)Path.c_str(), Path.size());
if (result != ERROR_SUCCESS){
fatal(R"(failed to create the value "Name" under HKEY_CURRENT_USER\Software\Valve\Steam\Apps\284160)");
return;
}
RegCloseKey(hKey);
info("Patched!");
}
#endif
#if defined(_WIN32)
void InitLauncher(int argc, char* argv[]) {
system("cls");
SetConsoleTitleA(("BeamMP Launcher v" + std::string(GetVer()) + GetPatch()).c_str());
InitLog();
CheckName(argc, argv);
LinuxPatch();
CheckLocalKey();
ConfigInit();
CustomPort(argc, argv);
Discord_Main();
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){
return (size_t)std::distance(std::filesystem::directory_iterator{path}, std::filesystem::directory_iterator{});
}
void CheckMP(const std::string& Path) {
if (!fs::exists(Path))return;
size_t c = DirCount(fs::path(Path));
if (c > 3) {
warn(std::to_string(c - 1) + " multiplayer mods will be wiped from mods/multiplayer! Close this if you don't want that!");
std::this_thread::sleep_for(std::chrono::seconds(15));
}
try {
for (auto& p : fs::directory_iterator(Path)){
if(p.exists() && !p.is_directory()){
@@ -150,19 +264,47 @@ void CheckMP(const std::string& Path) {
}
}
} catch (...) {
fatal("Please close the game, and try again!");
fatal("We were unable to clean the multiplayer mods folder! Is the game still running or do you have something open in that folder?");
}
}
void EnableMP(){
std::string File(GetGamePath() + "mods/db.json");
if(!fs::exists(File))return;
auto Size = fs::file_size(File);
if(Size < 2)return;
std::ifstream db(File);
if(db.is_open()) {
std::string Data(Size, 0);
db.read(&Data[0], Size);
db.close();
json::Document d;
d.Parse(Data.c_str());
if(Data.at(0) != '{' || d.HasParseError()){
//error("Failed to parse " + File); //TODO illegal formatting
return;
}
if(d.HasMember("mods") && !d["mods"].IsNull() && d["mods"].HasMember("multiplayerbeammp") && !d["mods"]["multiplayerbeammp"].IsNull()){
d["mods"]["multiplayerbeammp"]["active"] = true;
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
d.Accept(writer);
std::ofstream ofs(File);
if(ofs.is_open()){
ofs << buffer.GetString();
ofs.close();
}else{
error("Failed to write " + File);
}
}
}
}
void PreGame(const std::string& GamePath){
const std::string CurrVer("0.22.1.0");
std::string GameVer = CheckVer(GamePath);
info("Game Version : " + GameVer);
if(GameVer < CurrVer){
fatal("Game version is old! Please update.");
}else if(GameVer > CurrVer){
warn("Game is newer than recommended, multiplayer may not work as intended!");
}
CheckMP(GetGamePath() + "mods/multiplayer");
if(!Dev) {
@@ -171,15 +313,27 @@ void PreGame(const std::string& GamePath){
if (!fs::exists(GetGamePath() + "mods/multiplayer")) {
fs::create_directories(GetGamePath() + "mods/multiplayer");
}
EnableMP();
}catch(std::exception&e){
fatal(e.what());
}
#if defined(_WIN32)
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
HTTP::Download("https://backend.beammp.com/builds/client?download=true"
"&pk=" + PublicKey +
"&branch=" + Branch, GetGamePath() + R"(mods\multiplayer\BeamMP.zip)");
HTTP::Download("https://backend.beammp.com/builds/client?download=true"
"&pk=" + PublicKey + "&branch=" + Branch, ZipPath);
std::string Target(GetGamePath() + "mods/unpacked/beammp");
if(fs::is_directory(Target)) {
fs::remove_all(Target);
}
//HTTP::Download("beammp.com/builds/client", GetGamePath() + R"(mods\multiplayer\BeamMP.zip)");
}
}
}

View File

@@ -5,13 +5,13 @@
///
/// Created by Anonymous275 on 7/16/2020
///
#include "Network/network.h"
#include "Network/network.hpp"
#include "Security/Init.h"
#include "Startup.h"
#include <iostream>
#include "Logger.h"
#include <thread>
#include "http.h"
#include "Http.h"
[[noreturn]] void flush(){
while(true){
@@ -20,7 +20,6 @@
}
}
int main(int argc, char* argv[]) {
#ifdef DEBUG
std::thread th(flush);