mirror of
https://github.com/SantaSpeen/BeamMP-Server.git
synced 2026-02-16 19:50:40 +00:00
Compare commits
167 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a0939891b | ||
|
|
e0b1a5c91f | ||
|
|
5a275580a4 | ||
|
|
03ee46d293 | ||
|
|
fb7ed95d1d | ||
|
|
21c9ac4f53 | ||
|
|
ab5da1d94b | ||
|
|
6710c18168 | ||
|
|
cdd9ef86ae | ||
|
|
85edadb6e4 | ||
|
|
aa29530d92 | ||
|
|
270cca40ac | ||
|
|
c1633b6401 | ||
|
|
fa9bc16038 | ||
|
|
fedca58e8e | ||
|
|
6ecf6c58ac | ||
|
|
954d55c1a6 | ||
|
|
58e65cf43f | ||
|
|
c9f5ee9729 | ||
|
|
583819070b | ||
|
|
9ddab14f01 | ||
|
|
d44aa86ed1 | ||
|
|
7a5861a917 | ||
|
|
5e603c65b6 | ||
|
|
3137f4e9db | ||
|
|
80c5341650 | ||
|
|
cde41f01b2 | ||
|
|
be7e2f1616 | ||
|
|
cdb2624367 | ||
|
|
308500c01f | ||
|
|
8f05cdcc61 | ||
|
|
94f6a81673 | ||
|
|
60c7997c6b | ||
|
|
2d11841a68 | ||
|
|
01e02edf8c | ||
|
|
52bf3cdd21 | ||
|
|
1bbe88b240 | ||
|
|
5fc6c3ddd7 | ||
|
|
d226b36f44 | ||
|
|
7ab37b7fe9 | ||
|
|
747e948339 | ||
|
|
7fce274915 | ||
|
|
b663563f01 | ||
|
|
8e9bf46778 | ||
|
|
c6fbd3dc49 | ||
|
|
b9758ddaea | ||
|
|
e42256dd5f | ||
|
|
0b71d77a48 | ||
|
|
1e5faea1a4 | ||
|
|
4ecd57fed4 | ||
|
|
b8bd939bd7 | ||
|
|
1ef6cf53a2 | ||
|
|
26383d5346 | ||
|
|
96668add6e | ||
|
|
437a654b90 | ||
|
|
a42ab67d2f | ||
|
|
fe6cfd027e | ||
|
|
a08d29a0ae | ||
|
|
2021f0b461 | ||
|
|
5b92cbc0be | ||
|
|
757c63bddb | ||
|
|
77f811b7a8 | ||
|
|
6bebc4c160 | ||
|
|
e5a0d43024 | ||
|
|
b49abe02eb | ||
|
|
3eb2bd0dfc | ||
|
|
775e46788c | ||
|
|
1de29dc5e4 | ||
|
|
e41b3df095 | ||
|
|
24eaa1e079 | ||
|
|
8ba89e491f | ||
|
|
6a3b933df1 | ||
|
|
f0c87341ab | ||
|
|
fbbdc084a4 | ||
|
|
36db73b562 | ||
|
|
f2d87078ae | ||
|
|
5452aeb558 | ||
|
|
2beff2495f | ||
|
|
9bae155439 | ||
|
|
c5c21c43ad | ||
|
|
f144d451c7 | ||
|
|
ddd9c55822 | ||
|
|
801ea3f777 | ||
|
|
e986df0579 | ||
|
|
e9432ac1ca | ||
|
|
aa73a9d16a | ||
|
|
b2166402a2 | ||
|
|
2ec65d5b84 | ||
|
|
69f20bdf41 | ||
|
|
289bb1c1f3 | ||
|
|
eead954bf9 | ||
|
|
13e79e407c | ||
|
|
4d259c9d25 | ||
|
|
953131289d | ||
|
|
8bc35fb82e | ||
|
|
02fbe72eed | ||
|
|
2604308094 | ||
|
|
6787f43889 | ||
|
|
7e917e99a1 | ||
|
|
9adc633c2f | ||
|
|
030944ebc2 | ||
|
|
90458cbf72 | ||
|
|
3bdc75b0c0 | ||
|
|
71a84b4f1b | ||
|
|
31c96cee94 | ||
|
|
232c4d7b28 | ||
|
|
303647a8c3 | ||
|
|
92cc1cb0fd | ||
|
|
c83bc7864a | ||
|
|
83c095ba17 | ||
|
|
69362b2dfd | ||
|
|
e7c1bdd872 | ||
|
|
6c93ea7fb2 | ||
|
|
1b8c7abea5 | ||
|
|
c5e1175f1a | ||
|
|
ed0e35400d | ||
|
|
3d29067cab | ||
|
|
354ff30b90 | ||
|
|
834db5ecc1 | ||
|
|
62928ece9c | ||
|
|
280e3a8daa | ||
|
|
a05acee04f | ||
|
|
ed6b2d236a | ||
|
|
80c3280e4e | ||
|
|
ff2d5d74ae | ||
|
|
375c4a4952 | ||
|
|
49c38a0f00 | ||
|
|
ba47f21898 | ||
|
|
131e64b706 | ||
|
|
b0c6c2bac4 | ||
|
|
2d360610fc | ||
|
|
25a5cd75c6 | ||
|
|
851343eedb | ||
|
|
a85da1e05e | ||
|
|
ce7abdc960 | ||
|
|
60c38ccd1a | ||
|
|
2a3df072d1 | ||
|
|
1636ae3286 | ||
|
|
123cb4f1a2 | ||
|
|
d368b154c2 | ||
|
|
b5dbb70104 | ||
|
|
5cb43950eb | ||
|
|
8d56873335 | ||
|
|
d50f205787 | ||
|
|
9a47f651fc | ||
|
|
e60790e185 | ||
|
|
7410625fce | ||
|
|
29e77b147c | ||
|
|
9bdec9e5f8 | ||
|
|
388cffbe01 | ||
|
|
640a9c2e54 | ||
|
|
3c244c7e7f | ||
|
|
104856938a | ||
|
|
f427cb8d06 | ||
|
|
fef98347e7 | ||
|
|
e2cae1da59 | ||
|
|
4503338378 | ||
|
|
c47e8783e6 | ||
|
|
4e47f36d84 | ||
|
|
3ba8e55e59 | ||
|
|
56bd547823 | ||
|
|
996d96639c | ||
|
|
54319f7cdd | ||
|
|
60a0d13e63 | ||
|
|
9034319685 | ||
|
|
7d5c5a4526 | ||
|
|
1f620f4093 |
5
.clang-format
Normal file
5
.clang-format
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
BasedOnStyle: WebKit
|
||||
BreakBeforeBraces: Attach
|
||||
|
||||
...
|
||||
508
.gitignore
vendored
508
.gitignore
vendored
@@ -1,104 +1,464 @@
|
||||
# Logs
|
||||
logs
|
||||
boost_*
|
||||
Resources
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
#VS Files
|
||||
out/
|
||||
|
||||
#Clion Files
|
||||
cmake-build-debug/CMakeFiles/
|
||||
cmake-build-release/CMakeFiles/
|
||||
cmake-build-debug/Resources/
|
||||
cmake-build-release/Resources/
|
||||
cmake-build-debug/*.*
|
||||
cmake-build-release/*.*
|
||||
cmake-build-debug/Makefile
|
||||
cmake-build-release/Makefile
|
||||
!cmake-build-debug/*.lib
|
||||
!cmake-build-release/*.lib
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# Dependency directories
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and *not* Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
out/build/x86-Debug/VSInheritEnvironments.txt
|
||||
out/build/x86-Debug/rules.ninja
|
||||
out/build/x86-Debug/CMakeFiles/untitled.dir/manifest.res
|
||||
out/build/x86-Debug/CMakeFiles/untitled.dir/manifest.rc
|
||||
out/build/x86-Debug/CMakeFiles/untitled.dir/intermediate.manifest
|
||||
out/build/x86-Debug/CMakeFiles/untitled.dir/embed.manifest
|
||||
out/build/x86-Debug/CMakeFiles/TargetDirectories.txt
|
||||
out/build/x86-Debug/CMakeFiles/ShowIncludes/main.c
|
||||
out/build/x86-Debug/CMakeFiles/ShowIncludes/foo.h
|
||||
out/build/x86-Debug/CMakeFiles/cmake.check_cache
|
||||
out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CompilerIdCXX/CMakeCXXCompilerId.exe
|
||||
out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CompilerIdCXX/CMakeCXXCompilerId.cpp
|
||||
out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CompilerIdC/CMakeCCompilerId.exe
|
||||
out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CompilerIdC/CMakeCCompilerId.c
|
||||
out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeSystem.cmake
|
||||
out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeRCCompiler.cmake
|
||||
out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeDetermineCompilerABI_CXX.bin
|
||||
out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeDetermineCompilerABI_C.bin
|
||||
out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeCXXCompiler.cmake
|
||||
out/build/x86-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeCCompiler.cmake
|
||||
out/build/x86-Debug/CMakeCache.txt
|
||||
out/build/x86-Debug/cmake_install.cmake
|
||||
out/build/x86-Debug/build.ninja
|
||||
out/build/x86-Debug/.ninja_log
|
||||
out/build/x86-Debug/.ninja_deps
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/target-untitled-Debug-03f16c5921ae0bd48990.json
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/index-2020-01-27T23-42-34-0718.json
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/codemodel-v2-2b93246ca751d7a49cd1.json
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/cmakeFiles-v1-d93b224eb363971ee2c4.json
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/cache-v2-43521627501184045d13.json
|
||||
out/build/x86-Debug/.cmake/api/v1/query/client-MicrosoftVS/query.json
|
||||
out/build/x64-Debug/VSInheritEnvironments.txt
|
||||
out/build/x64-Debug/rules.ninja
|
||||
out/build/x64-Debug/CMakeFiles/untitled.dir/manifest.res
|
||||
out/build/x64-Debug/CMakeFiles/untitled.dir/manifest.rc
|
||||
out/build/x64-Debug/CMakeFiles/untitled.dir/intermediate.manifest
|
||||
out/build/x64-Debug/CMakeFiles/untitled.dir/embed.manifest
|
||||
out/build/x64-Debug/CMakeFiles/TargetDirectories.txt
|
||||
out/build/x64-Debug/CMakeFiles/ShowIncludes/main.c
|
||||
out/build/x64-Debug/CMakeFiles/ShowIncludes/foo.h
|
||||
out/build/x64-Debug/CMakeFiles/cmake.check_cache
|
||||
out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CompilerIdCXX/CMakeCXXCompilerId.exe
|
||||
out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CompilerIdCXX/CMakeCXXCompilerId.cpp
|
||||
out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CompilerIdC/CMakeCCompilerId.exe
|
||||
out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CompilerIdC/CMakeCCompilerId.c
|
||||
out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeSystem.cmake
|
||||
out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeRCCompiler.cmake
|
||||
out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeDetermineCompilerABI_CXX.bin
|
||||
out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeDetermineCompilerABI_C.bin
|
||||
out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeCXXCompiler.cmake
|
||||
out/build/x64-Debug/CMakeFiles/3.15.19101501-MSVC_2/CMakeCCompiler.cmake
|
||||
out/build/x64-Debug/CMakeCache.txt
|
||||
out/build/x64-Debug/cmake_install.cmake
|
||||
out/build/x64-Debug/build.ninja
|
||||
out/build/x64-Debug/.ninja_log
|
||||
out/build/x64-Debug/.ninja_deps
|
||||
out/build/x64-Debug/.cmake/api/v1/reply/target-untitled-Debug-8918286eee207fe0275b.json
|
||||
out/build/x64-Debug/.cmake/api/v1/reply/index-2020-01-27T23-42-03-0431.json
|
||||
out/build/x64-Debug/.cmake/api/v1/reply/codemodel-v2-ee254da00ecbf4b22928.json
|
||||
out/build/x64-Debug/.cmake/api/v1/reply/cmakeFiles-v1-ee926bd040d82c324cbe.json
|
||||
out/build/x64-Debug/.cmake/api/v1/reply/cache-v2-6f7cb0917968b934d35c.json
|
||||
out/build/x64-Debug/.cmake/api/v1/query/client-MicrosoftVS/query.json
|
||||
CMakeSettings.json
|
||||
cmake-build-debug/Resource1.resx
|
||||
out/build/x64-Debug/.cmake/api/v1/reply/index-2020-01-28T10-34-19-0746.json
|
||||
out/build/x64-Debug/untitled.exe
|
||||
out/build/x64-Debug/.cmake/api/v1/reply/index-2020-01-28T11-19-41-0061.json
|
||||
out/build/x64-Debug/.cmake/api/v1/reply/cmakeFiles-v1-52c1d9386071c1490278.json
|
||||
out/build/x86-Debug/CMakeFiles/cmake-main.dir/manifest.res
|
||||
out/build/x86-Debug/CMakeFiles/cmake-main.dir/manifest.rc
|
||||
out/build/x86-Debug/CMakeFiles/cmake-main.dir/intermediate.manifest
|
||||
out/build/x86-Debug/CMakeFiles/cmake-main.dir/embed.manifest
|
||||
out/build/x86-Debug/cmake-main.exe
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/target-enet-Debug-1cc90e5d191bd520f961.json
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/target-cmake-main-Debug-0c9bd3464adc40e447af.json
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/index-2020-01-28T11-21-26-0362.json
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/codemodel-v2-1850e17888d5bab56568.json
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/cmakeFiles-v1-7c376457f6b736ad28ac.json
|
||||
out/build/x64-Debug/CMakeFiles/cmake-main.dir/manifest.res
|
||||
out/build/x64-Debug/CMakeFiles/cmake-main.dir/manifest.rc
|
||||
out/build/x64-Debug/CMakeFiles/cmake-main.dir/intermediate.manifest
|
||||
out/build/x64-Debug/CMakeFiles/cmake-main.dir/embed.manifest
|
||||
out/build/x64-Debug/cmake-main.exe
|
||||
out/build/x64-Debug/.cmake/api/v1/reply/target-enet-Debug-645fd45f5bd4fab53aa9.json
|
||||
out/build/x64-Debug/.cmake/api/v1/reply/target-cmake-main-Debug-b124668c8fb6ca5df286.json
|
||||
out/build/x64-Debug/.cmake/api/v1/reply/index-2020-01-28T11-21-06-0706.json
|
||||
out/build/x64-Debug/.cmake/api/v1/reply/codemodel-v2-63a6ab1789a1732f4563.json
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/target-enet-Debug-d301abed48f6c38bdcfb.json
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/index-2020-01-28T12-30-44-0946.json
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/codemodel-v2-3eaabe43603befc605b1.json
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/target-cmake-main-Debug-70eff68e1e381b42992e.json
|
||||
*.xml
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/target-enet-Debug-48db38ae5d08e27876b8.json
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/target-cmake-main-Debug-540e487569703b71c785.json
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/index-2020-01-28T17-35-38-0764.json
|
||||
out/build/x86-Debug/.cmake/api/v1/reply/codemodel-v2-6a61e390ef8eaf17e9f8.json
|
||||
out/build/x86-Debug/Server.cfg
|
||||
*Server.cfg*
|
||||
|
||||
2
.idea/.gitignore
generated
vendored
Normal file
2
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Default ignored files
|
||||
/workspace.xml
|
||||
1
.idea/.name
generated
Normal file
1
.idea/.name
generated
Normal file
@@ -0,0 +1 @@
|
||||
Server
|
||||
2
.idea/BeamNG-MP-Server.iml
generated
Normal file
2
.idea/BeamNG-MP-Server.iml
generated
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
||||
7
.idea/misc.xml
generated
Normal file
7
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
<component name="JavaScriptSettings">
|
||||
<option name="languageLevel" value="ES6" />
|
||||
</component>
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/BeamNG-MP-Server.iml" filepath="$PROJECT_DIR$/.idea/BeamNG-MP-Server.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
37
CMakeLists.txt
Normal file
37
CMakeLists.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
project(Server)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
|
||||
|
||||
if (UNIX)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic -static-libstdc++")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og -g")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -s")
|
||||
elseif (WIN32)
|
||||
# This might cause issues with old windows headers, but it's worth the trouble to keep the code
|
||||
# completely cross platform. For fixes to common issues arising from /permissive- visit:
|
||||
# https://docs.microsoft.com/en-us/cpp/build/reference/permissive-standards-conformance
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3 /permissive-")
|
||||
message(STATUS "MSVC -> forcing use of statically-linked runtime.")
|
||||
STRING(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})
|
||||
STRING(REPLACE "/MDd" "/MTd" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
|
||||
#-DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static
|
||||
endif ()
|
||||
|
||||
find_package(Boost 1.70.0 REQUIRED COMPONENTS system thread)
|
||||
file(GLOB source_files "src/*.cpp" "src/*/*.cpp" "include/*.h" "include/*/*.h" "include/*.hpp" "include/*/*.hpp")
|
||||
add_executable(BeamMP-Server ${source_files})
|
||||
|
||||
target_include_directories(BeamMP-Server SYSTEM PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
|
||||
find_package(Lua 5.3 REQUIRED)
|
||||
target_include_directories(BeamMP-Server SYSTEM PUBLIC ${LUA_INCLUDE_DIR} ${Boost_INCLUDE_DIRS})
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(BeamMP-Server curl z pthread stdc++fs ${Boost_LINK_DIRS} ${LUA_LIBRARIES})
|
||||
elseif (WIN32)
|
||||
include(FindLua)
|
||||
find_package(CURL CONFIG REQUIRED)
|
||||
find_package(ZLIB REQUIRED)
|
||||
target_link_libraries(BeamMP-Server PRIVATE urlmon ws2_32 CURL::libcurl ZLIB::ZLIB ${Boost_LINK_DIRS} ${LUA_LIBRARIES})
|
||||
endif ()
|
||||
37
README.md
37
README.md
@@ -1 +1,36 @@
|
||||
# BeamNG-MP-Server
|
||||
# BeamNG-MP-Server
|
||||
|
||||
## Unix specific build instructions
|
||||
|
||||
1. You need boost >= 1.70.0
|
||||
|
||||
Check with your ditro's package manager whether it provides this. If it does, you should use that.
|
||||
|
||||
|
||||
If it doesnt provide it or you want to link it statically (like we do with our releases), then you have to do this:
|
||||
|
||||
download the latest boost source code.
|
||||
Then, go to the downloaded directory and run
|
||||
```sh
|
||||
b2 link=static runtime-link=static threading=multi
|
||||
```
|
||||
And then either symlink, edit CMakeLists to find it, or simply run
|
||||
```sh
|
||||
b2 link=static runtime-link=static threading=multi install
|
||||
```
|
||||
(warning: installs boost into your system, you might not want this).
|
||||
|
||||
Then on invocation of cmake, ensure that you define `Boost_USE_STATIC_RUNTIME=ON`.
|
||||
|
||||
|
||||
2. Building
|
||||
|
||||
Run cmake, and then make.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
~/src/Server $ cmake -S . -B bin -DCMAKE_BUILD_TYPE=Release
|
||||
...
|
||||
~/src/Server $ make -C bin -j 5
|
||||
```
|
||||
|
||||
BIN
cmake-build-debug/BeamMP-Server
Normal file
BIN
cmake-build-debug/BeamMP-Server
Normal file
Binary file not shown.
85
include/Client.hpp
Normal file
85
include/Client.hpp
Normal file
@@ -0,0 +1,85 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 5/8/2020
|
||||
///
|
||||
|
||||
#pragma once
|
||||
#ifdef WIN32
|
||||
#include <WS2tcpip.h>
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#define SOCKET int
|
||||
#endif
|
||||
#include "CustomAssert.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
struct VData{
|
||||
int ID = -1;
|
||||
std::string Data;
|
||||
};
|
||||
|
||||
class Client {
|
||||
private:
|
||||
std::set<std::unique_ptr<VData>> VehicleData; //ID and Data;
|
||||
std::string Name = Sec("Unknown Client");
|
||||
sockaddr_in UDPADDR;
|
||||
std::string Role;
|
||||
std::string DID;
|
||||
SOCKET TCPSOCK;
|
||||
int Status = 0;
|
||||
int ID = -1;
|
||||
public:
|
||||
void AddNewCar(int ident,const std::string& Data);
|
||||
void SetCarData(int ident,const std::string&Data);
|
||||
void SetName(const std::string& name);
|
||||
void SetRole(const std::string& role);
|
||||
void SetDID(const std::string& did);
|
||||
std::string GetCarData(int ident);
|
||||
void SetUDPAddr(sockaddr_in Addr);
|
||||
std::set<std::unique_ptr<VData>>& GetAllCars();
|
||||
const std::set<std::unique_ptr<VData>>& GetAllCars() const;
|
||||
void SetTCPSock(SOCKET CSock);
|
||||
void SetStatus(int status);
|
||||
void DeleteCar(int ident);
|
||||
sockaddr_in GetUDPAddr();
|
||||
bool isConnected = false;
|
||||
std::string GetRole();
|
||||
std::string GetName();
|
||||
bool isSynced = false;
|
||||
std::string GetDID();
|
||||
SOCKET GetTCPSock();
|
||||
void SetID(int ID);
|
||||
int GetOpenCarID();
|
||||
int GetCarCount();
|
||||
void ClearCars();
|
||||
int GetStatus();
|
||||
int GetID();
|
||||
};
|
||||
struct ClientInterface{
|
||||
std::set<std::unique_ptr<Client>> Clients;
|
||||
void RemoveClient(Client*& c){
|
||||
Assert(c);
|
||||
c->ClearCars();
|
||||
auto Iter = std::find_if(Clients.begin(), Clients.end(), [&](auto& ptr) {
|
||||
return c == ptr.get();
|
||||
});
|
||||
Assert(Iter != Clients.end());
|
||||
if (Iter == Clients.end()) {
|
||||
return;
|
||||
}
|
||||
Clients.erase(Iter);
|
||||
c = nullptr;
|
||||
}
|
||||
void AddClient(Client*&& c){
|
||||
Assert(c);
|
||||
Clients.insert(std::move(std::unique_ptr<Client>(c)));
|
||||
}
|
||||
int Size(){
|
||||
return int(Clients.size());
|
||||
}
|
||||
};
|
||||
|
||||
extern std::unique_ptr<ClientInterface> CI;
|
||||
7
include/Compressor.h
Normal file
7
include/Compressor.h
Normal file
@@ -0,0 +1,7 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/24/2020
|
||||
///
|
||||
#pragma once
|
||||
#include <string>
|
||||
std::string Comp(std::string Data);
|
||||
std::string DeComp(std::string Compressed);
|
||||
7
include/Curl/Http.h
Normal file
7
include/Curl/Http.h
Normal file
@@ -0,0 +1,7 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/18/2020
|
||||
///
|
||||
#pragma once
|
||||
#include <string>
|
||||
std::string HttpRequest(const std::string& IP, int port);
|
||||
std::string PostHTTP(const std::string& IP, const std::string& Fields);
|
||||
67
include/CustomAssert.h
Normal file
67
include/CustomAssert.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// Author: lionkor
|
||||
|
||||
/*
|
||||
* Asserts are to be used anywhere where assumptions about state are made
|
||||
* implicitly. AssertNotReachable is used where code should never go, like in
|
||||
* default switch cases which shouldn't trigger. They make it explicit
|
||||
* that a place cannot normally be reached and make it an error if they do.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
#include "Logger.h"
|
||||
|
||||
static const char* const ANSI_RESET = "\u001b[0m";
|
||||
|
||||
static const char* const ANSI_BLACK = "\u001b[30m";
|
||||
static const char* const ANSI_RED = "\u001b[31m";
|
||||
static const char* const ANSI_GREEN = "\u001b[32m";
|
||||
static const char* const ANSI_YELLOW = "\u001b[33m";
|
||||
static const char* const ANSI_BLUE = "\u001b[34m";
|
||||
static const char* const ANSI_MAGENTA = "\u001b[35m";
|
||||
static const char* const ANSI_CYAN = "\u001b[36m";
|
||||
static const char* const ANSI_WHITE = "\u001b[37m";
|
||||
|
||||
static const char* const ANSI_BLACK_BOLD = "\u001b[30;1m";
|
||||
static const char* const ANSI_RED_BOLD = "\u001b[31;1m";
|
||||
static const char* const ANSI_GREEN_BOLD = "\u001b[32;1m";
|
||||
static const char* const ANSI_YELLOW_BOLD = "\u001b[33;1m";
|
||||
static const char* const ANSI_BLUE_BOLD = "\u001b[34;1m";
|
||||
static const char* const ANSI_MAGENTA_BOLD = "\u001b[35;1m";
|
||||
static const char* const ANSI_CYAN_BOLD = "\u001b[36;1m";
|
||||
static const char* const ANSI_WHITE_BOLD = "\u001b[37;1m";
|
||||
|
||||
static const char* const ANSI_BOLD = "\u001b[1m";
|
||||
static const char* const ANSI_UNDERLINE = "\u001b[4m";
|
||||
|
||||
#if DEBUG
|
||||
inline void _assert([[maybe_unused]] const char* file, [[maybe_unused]] const char* function, [[maybe_unused]] unsigned line,
|
||||
[[maybe_unused]] const char* condition_string, [[maybe_unused]] bool result) {
|
||||
if (!result) {
|
||||
std::cout << std::flush << "(debug build) TID "
|
||||
<< std::this_thread::get_id() << ": ASSERTION FAILED: at "
|
||||
<< file << ":" << line << " \n\t-> in "
|
||||
<< function << ", Line " << line << ": \n\t\t-> "
|
||||
<< "Failed Condition: " << condition_string << std::endl;
|
||||
std::cout << "... terminating ..." << std::endl;
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
#define Assert(cond) _assert(__FILE__, __func__, __LINE__, #cond, (cond))
|
||||
#define AssertNotReachable() _assert(__FILE__, __func__, __LINE__, "reached unreachable code", false)
|
||||
#else
|
||||
// In release build, these macros turn into NOPs. The compiler will optimize these out.
|
||||
#define Assert(x) \
|
||||
do { \
|
||||
} while (false)
|
||||
#define AssertNotReachable() \
|
||||
do { \
|
||||
} while (false)
|
||||
#endif // DEBUG
|
||||
18
include/Logger.h
Normal file
18
include/Logger.h
Normal file
@@ -0,0 +1,18 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 4/2/2020.
|
||||
///
|
||||
#pragma once
|
||||
#include "Security/Xor.h"
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
void InitLog();
|
||||
#define DebugPrintTID() DebugPrintTIDInternal(__func__, false)
|
||||
void DebugPrintTIDInternal(const std::string& func, bool overwrite = true); // prints the current thread id in debug mode, to make tracing of crashes and asserts easier
|
||||
void ConsoleOut(const std::string& msg);
|
||||
void QueueAbort();
|
||||
void except(const std::string& toPrint);
|
||||
void debug(const std::string& toPrint);
|
||||
void error(const std::string& toPrint);
|
||||
void info(const std::string& toPrint);
|
||||
void warn(const std::string& toPrint);
|
||||
77
include/Lua/LuaSystem.hpp
Normal file
77
include/Lua/LuaSystem.hpp
Normal file
@@ -0,0 +1,77 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 5/20/2020
|
||||
///
|
||||
|
||||
#pragma once
|
||||
#include <any>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <lua.hpp>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
struct LuaArg {
|
||||
std::vector<std::any> args;
|
||||
void PushArgs(lua_State* State) {
|
||||
for (std::any arg : args) {
|
||||
if (!arg.has_value())
|
||||
return;
|
||||
std::string Type = arg.type().name();
|
||||
if (Type.find("bool") != std::string::npos) {
|
||||
lua_pushboolean(State, std::any_cast<bool>(arg));
|
||||
}
|
||||
if (Type.find("basic_string") != std::string::npos || Type.find("char") != std::string::npos) {
|
||||
lua_pushstring(State, std::any_cast<std::string>(arg).c_str());
|
||||
}
|
||||
if (Type.find("int") != std::string::npos) {
|
||||
lua_pushinteger(State, std::any_cast<int>(arg));
|
||||
}
|
||||
if (Type.find("float") != std::string::npos) {
|
||||
lua_pushnumber(State, std::any_cast<float>(arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class Lua {
|
||||
private:
|
||||
std::set<std::pair<std::string, std::string>> _RegisteredEvents;
|
||||
lua_State* luaState { nullptr };
|
||||
fs::file_time_type _LastWrote;
|
||||
std::string _PluginName {};
|
||||
std::string _FileName {};
|
||||
bool _StopThread = false;
|
||||
bool _Console = false;
|
||||
|
||||
public:
|
||||
void Init();
|
||||
void RegisterEvent(const std::string& Event, const std::string& FunctionName);
|
||||
std::string GetRegistered(const std::string& Event) const;
|
||||
void UnRegisterEvent(const std::string& Event);
|
||||
void SetLastWrite(fs::file_time_type time);
|
||||
bool IsRegistered(const std::string& Event);
|
||||
void SetPluginName(const std::string& Name);
|
||||
void Execute(const std::string& Command);
|
||||
void SetFileName(const std::string& Name);
|
||||
fs::file_time_type GetLastWrite();
|
||||
std::string GetPluginName() const;
|
||||
std::string GetFileName() const;
|
||||
lua_State* GetState();
|
||||
const lua_State* GetState() const;
|
||||
std::string GetOrigin();
|
||||
std::mutex Lock;
|
||||
void Reload();
|
||||
Lua(const std::string& PluginName, const std::string& FileName, fs::file_time_type LastWrote, bool Console = false);
|
||||
Lua(bool Console = false);
|
||||
~Lua();
|
||||
void SetStopThread(bool StopThread) { _StopThread = StopThread; }
|
||||
bool GetStopThread() const { return _StopThread; }
|
||||
};
|
||||
int CallFunction(Lua* lua, const std::string& FuncName, std::unique_ptr<LuaArg> args);
|
||||
int TriggerLuaEvent(const std::string& Event, bool local, Lua* Caller, std::unique_ptr<LuaArg> arg, bool Wait);
|
||||
extern std::set<std::unique_ptr<Lua>> PluginEngine;
|
||||
19
include/Network.h
Normal file
19
include/Network.h
Normal file
@@ -0,0 +1,19 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/31/2020
|
||||
///
|
||||
#pragma once
|
||||
#include "Client.hpp"
|
||||
#include <string>
|
||||
void TCPServerMain();
|
||||
void UpdatePlayers();
|
||||
void OnConnect(Client* c);
|
||||
void InitClient(Client* c);
|
||||
void SyncResources(Client* c);
|
||||
[[noreturn]] void UDPServerMain();
|
||||
void OnDisconnect(Client* c, bool kicked);
|
||||
void UDPSend(Client* c, std::string Data);
|
||||
void TCPSend(Client* c, const std::string& Data);
|
||||
void SendLarge(Client* c, std::string Data);
|
||||
void GParser(Client* c, const std::string& Packet);
|
||||
void Respond(Client* c, const std::string& MSG, bool Rel);
|
||||
void SendToAll(Client* c, const std::string& Data, bool Self, bool Rel);
|
||||
19
include/RWMutex.h
Normal file
19
include/RWMutex.h
Normal file
@@ -0,0 +1,19 @@
|
||||
// Author: lionkor
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* An RWMutex allows multiple simultaneous readlocks but only one writelock at a time,
|
||||
* and write locks and read locks are mutually exclusive.
|
||||
*/
|
||||
|
||||
#include <shared_mutex>
|
||||
|
||||
// Use ReadLock(m) and WriteLock(m) to lock it.
|
||||
using RWMutex = std::shared_mutex;
|
||||
// Construct with an RWMutex as a non-const reference.
|
||||
// locks the mutex in lock_shared mode (for reading). Locking in a thread that already owns a lock
|
||||
// i.e. locking multiple times successively is UB. Construction may be blocking. Destruction is guaranteed to release the lock.
|
||||
using ReadLock = std::shared_lock<RWMutex>;
|
||||
// Construct with an RWMutex as a non-const reference.
|
||||
// locks the mutex for writing. Construction may be blocking. Destruction is guaranteed to release the lock.
|
||||
using WriteLock = std::unique_lock<RWMutex>;
|
||||
21
include/Security/Enc.h
Normal file
21
include/Security/Enc.h
Normal file
@@ -0,0 +1,21 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/28/2020
|
||||
///
|
||||
#pragma once
|
||||
#ifdef __linux
|
||||
#define EXCEPTION_POINTERS void
|
||||
#else
|
||||
#include <WS2tcpip.h>
|
||||
#endif
|
||||
#include "Xor.h"
|
||||
#include <string>
|
||||
struct RSA {
|
||||
int n = 0;
|
||||
int e = 0;
|
||||
int d = 0;
|
||||
};
|
||||
std::string RSA_E(const std::string& Data, int e, int n);
|
||||
std::string RSA_E(const std::string& Data, RSA* k);
|
||||
std::string RSA_D(const std::string& Data, RSA* k);
|
||||
int Handle(EXCEPTION_POINTERS* ep, char* Origin);
|
||||
RSA* GenKey();
|
||||
132
include/Security/Xor.h
Normal file
132
include/Security/Xor.h
Normal file
@@ -0,0 +1,132 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 8/11/2020
|
||||
///
|
||||
#pragma once
|
||||
#include <array>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
||||
#define BEGIN_NAMESPACE(x) namespace x {
|
||||
#define END_NAMESPACE }
|
||||
|
||||
BEGIN_NAMESPACE(XorCompileTime)
|
||||
|
||||
constexpr auto time = __TIME__;
|
||||
constexpr auto seed = static_cast<int>(time[7]) + static_cast<int>(time[6]) * 10 + static_cast<int>(time[4]) * 60 + static_cast<int>(time[3]) * 600 + static_cast<int>(time[1]) * 3600 + static_cast<int>(time[0]) * 36000;
|
||||
|
||||
// 1988, Stephen Park and Keith Miller
|
||||
// "Random Number Generators: Good Ones Are Hard To Find", considered as "minimal standard"
|
||||
// Park-Miller 31 bit pseudo-random number generator, implemented with G. Carta's optimisation:
|
||||
// with 32-bit math and without division
|
||||
|
||||
template <int N>
|
||||
struct RandomGenerator {
|
||||
private:
|
||||
static constexpr unsigned a = 16807; // 7^5
|
||||
static constexpr unsigned m = 2147483647; // 2^31 - 1
|
||||
|
||||
static constexpr unsigned s = RandomGenerator<N - 1>::value;
|
||||
static constexpr unsigned lo = a * (s & 0xFFFFu); // Multiply lower 16 bits by 16807
|
||||
static constexpr unsigned hi = a * (s >> 16u); // Multiply higher 16 bits by 16807
|
||||
static constexpr unsigned lo2 = lo + ((hi & 0x7FFFu) << 16u); // Combine lower 15 bits of hi with lo's upper bits
|
||||
static constexpr unsigned hi2 = hi >> 15u; // Discard lower 15 bits of hi
|
||||
static constexpr unsigned lo3 = lo2 + hi;
|
||||
|
||||
public:
|
||||
static constexpr unsigned max = m;
|
||||
static constexpr unsigned value = lo3 > m ? lo3 - m : lo3;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct RandomGenerator<0> {
|
||||
static constexpr unsigned value = seed;
|
||||
};
|
||||
|
||||
template <int N, int M>
|
||||
struct RandomInt {
|
||||
static constexpr auto value = RandomGenerator<N + 1>::value % M;
|
||||
};
|
||||
|
||||
template <int N>
|
||||
struct RandomChar {
|
||||
static const char value = static_cast<char>(1 + RandomInt<N, 0x7F - 1>::value);
|
||||
};
|
||||
|
||||
template <size_t N, int K, typename Char>
|
||||
struct XorString {
|
||||
private:
|
||||
const char _key;
|
||||
std::array<Char, N + 1> _encrypted;
|
||||
|
||||
constexpr Char enc(Char c) const {
|
||||
return c ^ _key;
|
||||
}
|
||||
|
||||
Char dec(Char c) const {
|
||||
return c ^ _key;
|
||||
}
|
||||
|
||||
public:
|
||||
template <size_t... Is>
|
||||
constexpr inline XorString(const Char* str, std::index_sequence<Is...>)
|
||||
: _key(RandomChar<K>::value)
|
||||
, _encrypted { enc(str[Is])... } { }
|
||||
|
||||
inline decltype(auto) decrypt() {
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
_encrypted[i] = dec(_encrypted[i]);
|
||||
}
|
||||
_encrypted[N] = '\0';
|
||||
return _encrypted.data();
|
||||
}
|
||||
};
|
||||
|
||||
static auto w_printf = [](const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
};
|
||||
|
||||
static auto w_printf_s = [](const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vprintf(fmt, args);
|
||||
va_end(args);
|
||||
};
|
||||
|
||||
/*static auto w_sprintf = [](char* buf, const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsprintf(buf, fmt, args);
|
||||
va_end(args);
|
||||
};*/
|
||||
|
||||
/*static auto w_sprintf_ret = [](char* buf, const char* fmt, ...) {
|
||||
int ret;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ret = vsprintf(buf, fmt, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
};*/
|
||||
|
||||
static auto w_sprintf_s = [](char* buf, size_t buf_size, const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf(buf, buf_size, fmt, args);
|
||||
va_end(args);
|
||||
};
|
||||
|
||||
static auto w_sprintf_s_ret = [](char* buf, size_t buf_size, const char* fmt, ...) {
|
||||
int ret;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ret = vsnprintf(buf, buf_size, fmt, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
};
|
||||
#define Sec(s) [] { constexpr XorCompileTime::XorString< sizeof(s)/sizeof(char) - 1, __COUNTER__, char > expr( s, std::make_index_sequence< sizeof(s)/sizeof(char) - 1>() ); return expr; }().decrypt()
|
||||
#define SecW(s) [] { constexpr XorCompileTime::XorString< sizeof(s)/sizeof(wchar_t) - 1, __COUNTER__, wchar_t > expr( s, std::make_index_sequence< sizeof(s)/sizeof(wchar_t) - 1>() ); return expr; }().decrypt()
|
||||
END_NAMESPACE
|
||||
24
include/Settings.h
Normal file
24
include/Settings.h
Normal file
@@ -0,0 +1,24 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/28/2020
|
||||
///
|
||||
#pragma once
|
||||
#include <string>
|
||||
extern std::string ServerName;
|
||||
extern std::string ServerDesc;
|
||||
extern std::string StatReport;
|
||||
extern std::string FileSizes;
|
||||
extern std::string Resource;
|
||||
extern std::string FileList;
|
||||
extern std::string CustomIP;
|
||||
extern std::string MapName;
|
||||
extern uint64_t MaxModSize;
|
||||
extern std::string Key;
|
||||
std::string GetSVer();
|
||||
std::string GetCVer();
|
||||
extern int MaxPlayers;
|
||||
extern int ModsLoaded;
|
||||
extern bool Private;
|
||||
extern int MaxCars;
|
||||
extern bool Debug;
|
||||
extern int Port;
|
||||
extern int PPS;
|
||||
12
include/Startup.h
Normal file
12
include/Startup.h
Normal file
@@ -0,0 +1,12 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/28/2020
|
||||
///
|
||||
#pragma once
|
||||
void InitServer(int argc, char* argv[]);
|
||||
void ConsoleInit();
|
||||
void InitConfig();
|
||||
void InitLua();
|
||||
void InitRes();
|
||||
void HBInit();
|
||||
void StatInit();
|
||||
void NetMain();
|
||||
38
include/UnixCompat.h
Normal file
38
include/UnixCompat.h
Normal file
@@ -0,0 +1,38 @@
|
||||
// Author: lionkor
|
||||
|
||||
#pragma once
|
||||
|
||||
// This header defines unix equivalents of common win32 functions.
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
#include "CustomAssert.h"
|
||||
#include <cstring>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// ZeroMemory is just a {0} or a memset(addr, 0, len), and it's a macro on MSVC
|
||||
inline void ZeroMemory(void* dst, size_t len) {
|
||||
Assert(std::memset(dst, 0, len) != nullptr);
|
||||
}
|
||||
// provides unix equivalent of closesocket call in win32
|
||||
inline void CloseSocketProper(int socket) {
|
||||
shutdown(socket, SHUT_RDWR);
|
||||
close(socket);
|
||||
}
|
||||
|
||||
#ifndef __try
|
||||
#define __try
|
||||
#endif
|
||||
|
||||
#ifndef __except
|
||||
#define __except (x) /**/
|
||||
#endif
|
||||
|
||||
#else // win32
|
||||
|
||||
inline void CloseSocketProper(uint64_t socket) {
|
||||
shutdown(socket, SD_BOTH);
|
||||
closesocket(socket);
|
||||
}
|
||||
#endif // WIN32
|
||||
345
index.js
345
index.js
@@ -1,345 +0,0 @@
|
||||
// Server Settings!
|
||||
var map = "";
|
||||
let _VERSION = "0.0.3"
|
||||
let UDPExpireTime = 30// In Seconds
|
||||
|
||||
const net = require('net');
|
||||
const uuidv4 = require('uuid/v4');
|
||||
const args = require('minimist')(process.argv.slice(2));
|
||||
const chalk = require("chalk")
|
||||
|
||||
//console.log(args.port)
|
||||
if (args.port) {
|
||||
var tcpport = args.port;
|
||||
} else {
|
||||
var tcpport = 30813;
|
||||
}
|
||||
|
||||
var udpport = tcpport + 1;
|
||||
var wsport = tcpport + 2;
|
||||
const host = '0.0.0.0';
|
||||
|
||||
//==========================================================
|
||||
// WebSocket Server
|
||||
//==========================================================
|
||||
|
||||
const WebSocket = require('ws');
|
||||
|
||||
const wss = new WebSocket.Server({ port: wsport });
|
||||
|
||||
wss.on('connection', function connection(ws) {
|
||||
ws.on('message', function incoming(message) {
|
||||
console.log('[WS] received: %s', message);
|
||||
wss.clients.forEach(function each(client) {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
client.send(message);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ws.send('Welcome!');
|
||||
});
|
||||
console.log(chalk.cyan('[WS]')+' Server listening on 0.0.0.0:' + wsport);
|
||||
|
||||
//==========================================================
|
||||
// TCP Server
|
||||
//==========================================================
|
||||
|
||||
const TCPserver = net.createServer();
|
||||
TCPserver.listen(tcpport, () => {
|
||||
console.log(chalk.green('[TCP]')+' Server listening on 0.0.0.0:' + tcpport);
|
||||
});
|
||||
|
||||
let sockets = [];
|
||||
let players = [];
|
||||
let names = [];
|
||||
let vehicles = [];
|
||||
|
||||
TCPserver.on('connection', function(sock) {
|
||||
console.log(chalk.green('[TCP]')+' CONNECTED: ' + sock.remoteAddress + ':' + sock.remotePort);
|
||||
sockets.push(sock);
|
||||
|
||||
var player = {};
|
||||
player.remoteAddress = sock.remoteAddress;
|
||||
player.remotePort = sock.remotePort;
|
||||
player.nickname = "New User, Loading...";
|
||||
player.id = uuidv4();
|
||||
player.currentVehID = 0;
|
||||
players.push(player);
|
||||
|
||||
sock.write('HOLA'+player.id+'\n');
|
||||
if (map == "") {
|
||||
sock.write("MAPS\n");
|
||||
} else {
|
||||
sock.write("MAPC"+map+'\n')
|
||||
}
|
||||
sock.write("VCHK"+_VERSION+'\n')
|
||||
|
||||
sock.on('data', function(data) {
|
||||
// Write the data back to all the connected, the client will receive it as data from the server
|
||||
var str = data.toString();
|
||||
data = str.trim(); //replace(/\r?\n|\r/g, "");
|
||||
var code = data.substring(0, 4);
|
||||
var message = data.substr(4);
|
||||
|
||||
if (code != "PING") {
|
||||
//console.log(code)
|
||||
}
|
||||
//if (data.length > 4) {
|
||||
//console.log(data.length)
|
||||
//}
|
||||
|
||||
switch (code) {
|
||||
case "PING":
|
||||
//console.log("Ping Received")
|
||||
sock.write('PONG\n');
|
||||
break;
|
||||
case "CHAT":
|
||||
sockets.forEach(function(socket, index, array) { // Send update to all clients
|
||||
socket.write(data+'\n');
|
||||
});
|
||||
break;
|
||||
case "MAPS":
|
||||
map = message;
|
||||
console.log("Setting map to: "+map);
|
||||
sock.write("MAPC"+map+'\n');
|
||||
break;
|
||||
case "USER":
|
||||
players.forEach(function(player, index, array) {
|
||||
if (player.remoteAddress == sock.remoteAddress && player.remotePort == sock.remotePort) {
|
||||
console.log("Player Found ("+player.id+"), setting nickname("+data.substr(4)+")");
|
||||
player.nickname = ""+data.substr(4)+"";
|
||||
sockets.forEach(function(socket, index, array) { // Send update to all clients
|
||||
socket.write('PLST'+JSON.stringify(players)+'\n');
|
||||
socket.write('SMSG'+data.substr(4)+' Just Joined the Session.\n');
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
case "QUIT":
|
||||
case "2001":
|
||||
let index = sockets.findIndex(function(o) {
|
||||
return o.remoteAddress === sock.remoteAddress && o.remotePort === sock.remotePort;
|
||||
})
|
||||
if (index !== -1) sockets.splice(index, 1);
|
||||
console.log('CLOSED: ' + sock.remoteAddress + ' ' + sock.remotePort);
|
||||
break;
|
||||
case "U-VI":
|
||||
case "U-VE":
|
||||
case "U-VN":
|
||||
case "U-VP":
|
||||
case "U-VL":
|
||||
case "U-VR":
|
||||
case "U-VV":
|
||||
//console.log(data)
|
||||
//players.forEach(function(player, index, array) {
|
||||
//if (player.remoteAddress != sock.remoteAddress) {
|
||||
//console.log(player.remoteAddress+' != '+sock.remoteAddress+' Is not the same so we should send?')
|
||||
//console.log("Got Update to send!")
|
||||
sockets.forEach(function(socket, index, array) { // Send update to all clients
|
||||
//console.log(socket.remotePort+' != '+sock.remotePort+' Is not the same so we should send?')
|
||||
if ((sock.remoteAddress != socket.remoteAddress && sock.remotePort != socket.remotePort) || (sock.remoteAddress == socket.remoteAddress && sock.remotePort != socket.remotePort)) {
|
||||
socket.write(data+'\n');
|
||||
}
|
||||
});
|
||||
//}
|
||||
//});
|
||||
break;
|
||||
case "U-VC":
|
||||
sockets.forEach(function(socket, index, array) { // Send update to all clients
|
||||
socket.write(data+'\n');
|
||||
});
|
||||
break;
|
||||
case "U-NV":
|
||||
console.log(message)
|
||||
var vid = uuidv4();
|
||||
|
||||
break;
|
||||
case "C-VS": // Client has changed vehicle. lets update our records.
|
||||
console.log(message)
|
||||
players.forEach(function(player, index, array) {
|
||||
if (player.currentVehID != message && player.remoteAddress == sock.remoteAddress && player.remotePort == sock.remotePort) {
|
||||
console.log(chalk.green('[TCP]')+" Player Found ("+player.id+"), updating current vehile("+message+")");
|
||||
player.currentVehID = message;
|
||||
}
|
||||
});
|
||||
break;
|
||||
default:
|
||||
console.log(chalk.green('[TCP]')+' Unknown / unhandled data from:' + sock.remoteAddress);
|
||||
console.log(chalk.green('[TCP]')+' Data -> ' + data);
|
||||
sockets.forEach(function(socket, index, array) { // Send update to all clients
|
||||
//if ((sock.remoteAddress != socket.remoteAddress && sock.remotePort != socket.remotePort) || (sock.remoteAddress == socket.remoteAddress && sock.remotePort != socket.remotePort)) {
|
||||
socket.write(data+'\n');
|
||||
//}
|
||||
});
|
||||
break;
|
||||
}
|
||||
sockets.forEach(function(sock, index, array) {
|
||||
//sock.write(sock.remoteAddress + ':' + sock.remotePort + " said " + data + '\n');
|
||||
});
|
||||
});
|
||||
|
||||
// Add a 'close' event handler to this instance of socket
|
||||
sock.on('close', function(data) {
|
||||
var index = players.findIndex(function(o) {
|
||||
return o.remoteAddress === sock.remoteAddress && o.remotePort === sock.remotePort;
|
||||
})
|
||||
if (index !== -1) sockets.splice(index, 1);
|
||||
index = sockets.findIndex(function(o) {
|
||||
return o.remoteAddress === sock.remoteAddress && o.remotePort === sock.remotePort;
|
||||
})
|
||||
if (index !== -1) sockets.splice(index, 1);
|
||||
console.log('CLOSED: ' + sock.remoteAddress + ' ' + sock.remotePort);
|
||||
players = removePlayer(players, sock.remoteAddress);
|
||||
console.log("Player list now holds: "+JSON.stringify(players));
|
||||
sockets.forEach(function(socket, index, array) { // Send update to all clients
|
||||
socket.write('PLST'+JSON.stringify(players)+'\n');
|
||||
});
|
||||
});
|
||||
|
||||
sock.on('error', (err) => {
|
||||
// handle errors here
|
||||
if (err.code == "ECONNRESET") {
|
||||
console.error(chalk.red("ERROR ")+"Connection Reset for player: ");
|
||||
players.forEach(function(player, index, array) {
|
||||
if (player.remoteAddress == sock.remoteAddress && player.remotePort == sock.remotePort) {
|
||||
console.error(+player.nickname+" ("+player.id+")");
|
||||
console.error(chalk.red("ERROR ")+"End Error.");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.error("Sock Error");
|
||||
console.error(err);
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
TCPserver.on('error', (err) => {
|
||||
// handle errors here
|
||||
console.error("TCPserver Error");
|
||||
console.error(err);
|
||||
throw err;
|
||||
});
|
||||
|
||||
function removePlayer(array, ip) {
|
||||
return array.filter(player => player.remoteAddress != ip);
|
||||
}
|
||||
|
||||
//==========================================================
|
||||
// UDP Server
|
||||
//==========================================================
|
||||
|
||||
var clients = {};
|
||||
var intervalTime = UDPExpireTime*2*1000;
|
||||
|
||||
setInterval(function() {
|
||||
console.log(clients);
|
||||
for (var client in clients) {
|
||||
var lastupdate = clients[client];
|
||||
var millis = Date.now() - lastupdate;
|
||||
var t = Math.floor(millis/1000)
|
||||
if (t > UDPExpireTime) {
|
||||
console.warn("Found Old Client: "+client)
|
||||
delete clients[client];
|
||||
}
|
||||
}
|
||||
}, intervalTime);
|
||||
|
||||
function updateClient (rinfo) {
|
||||
for (var client in clients) {
|
||||
client = JSON.parse(client);
|
||||
var address = client[0];
|
||||
var port = client[1];
|
||||
if (port == rinfo.port && address == rinfo.address) {
|
||||
client
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var dgram = require('dgram');
|
||||
var UDPserver = dgram.createSocket('udp4');
|
||||
|
||||
function UDPsend(message, info) {
|
||||
UDPserver.send(message, 0, message.length, info.port, info.address, function(error){
|
||||
if (error) {
|
||||
console.log("ERROR");
|
||||
console.log(error);
|
||||
client.close();
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
UDPserver.on('listening', function() {
|
||||
var address = UDPserver.address();
|
||||
console.log(chalk.rgb(123, 45, 67)('[UDP]')+' Server listening on ' + address.address + ':' + address.port);
|
||||
});
|
||||
|
||||
UDPserver.on('message',function(msg,rinfo){
|
||||
clients[JSON.stringify([rinfo.address, rinfo.port])] = Date.now();
|
||||
//sending msg
|
||||
var str = msg.toString();
|
||||
data = str.trim(); //replace(/\r?\n|\r/g, "");
|
||||
var code = data.substring(0, 4);
|
||||
//if (code != "PING") {
|
||||
//console.log(msg.toString());
|
||||
//}
|
||||
switch (code) {
|
||||
case "PING":
|
||||
UDPsend("PONG", rinfo)
|
||||
break;
|
||||
case "U-VC":
|
||||
for (var client in clients) {
|
||||
client = JSON.parse(client);
|
||||
var port = client[1];
|
||||
var address = client[0];
|
||||
UDPserver.send(msg, 0, msg.length, port, address, function(error){
|
||||
if (error) {
|
||||
console.log("ERROR");
|
||||
console.log(error);
|
||||
client.close();
|
||||
};
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "U-VR":
|
||||
case "U-VL":
|
||||
case "U-VP":
|
||||
case "U-VN":
|
||||
case "U-VE":
|
||||
case "U-VI":
|
||||
for (var client in clients) {
|
||||
client = JSON.parse(client);
|
||||
var port = client[1];
|
||||
var address = client[0];
|
||||
if (port != rinfo.port && address != rinfo.address) {
|
||||
UDPserver.send(msg, 0, msg.length, port, address, function(error){
|
||||
if (error) {
|
||||
console.log("ERROR");
|
||||
console.log(error);
|
||||
client.close();
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Unhandled data, this at the moment includes the extra packets of vehicles so it needs to be here until it is handled correctly
|
||||
for (var client in clients) {
|
||||
client = JSON.parse(client);
|
||||
var port = client[1];
|
||||
var address = client[0];
|
||||
UDPserver.send(msg, 0, msg.length, port, address, function(error){
|
||||
if (error) {
|
||||
console.log("ERROR");
|
||||
console.log(error);
|
||||
client.close();
|
||||
};
|
||||
});
|
||||
}
|
||||
//console.log(chalk.rgb(123, 45, 67)('[UDP]')+' Data received from client : ' + msg.toString());
|
||||
//console.log(chalk.rgb(123, 45, 67)('[UDP]')+' Received %d bytes from %s:%d\n',msg.length, rinfo.address, rinfo.port);
|
||||
}
|
||||
});
|
||||
|
||||
UDPserver.bind(Number(udpport));
|
||||
1268
package-lock.json
generated
1268
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"name": "beamng.drive-mp-server",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"start": "electron ."
|
||||
},
|
||||
"author": "Mitch Durso",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"electron": "^6.0.7"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": "^3.0.0",
|
||||
"minimist": "^1.2.0",
|
||||
"uuid": "^3.3.3",
|
||||
"ws": "^7.2.1"
|
||||
}
|
||||
}
|
||||
52
src/Compressor.cpp
Normal file
52
src/Compressor.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/15/2020
|
||||
///
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <zlib.h>
|
||||
|
||||
#define Biggest 30000
|
||||
std::string Comp(std::string Data) {
|
||||
std::array<char, Biggest> C {};
|
||||
// obsolete
|
||||
C.fill(0);
|
||||
z_stream defstream;
|
||||
defstream.zalloc = Z_NULL;
|
||||
defstream.zfree = Z_NULL;
|
||||
defstream.opaque = Z_NULL;
|
||||
defstream.avail_in = (uInt)Data.length();
|
||||
defstream.next_in = (Bytef*)&Data[0];
|
||||
defstream.avail_out = Biggest;
|
||||
defstream.next_out = reinterpret_cast<Bytef*>(C.data());
|
||||
deflateInit(&defstream, Z_BEST_COMPRESSION);
|
||||
deflate(&defstream, Z_SYNC_FLUSH);
|
||||
deflate(&defstream, Z_FINISH);
|
||||
deflateEnd(&defstream);
|
||||
size_t TO = defstream.total_out;
|
||||
std::string Ret(TO, 0);
|
||||
std::copy_n(C.begin(), TO, Ret.begin());
|
||||
return Ret;
|
||||
}
|
||||
std::string DeComp(std::string Compressed) {
|
||||
std::array<char, Biggest> C {};
|
||||
// not needed
|
||||
C.fill(0);
|
||||
z_stream infstream;
|
||||
infstream.zalloc = Z_NULL;
|
||||
infstream.zfree = Z_NULL;
|
||||
infstream.opaque = Z_NULL;
|
||||
infstream.avail_in = Biggest;
|
||||
infstream.next_in = (Bytef*)(&Compressed[0]);
|
||||
infstream.avail_out = Biggest;
|
||||
infstream.next_out = (Bytef*)(C.data());
|
||||
inflateInit(&infstream);
|
||||
inflate(&infstream, Z_SYNC_FLUSH);
|
||||
inflate(&infstream, Z_FINISH);
|
||||
inflateEnd(&infstream);
|
||||
size_t TO = infstream.total_out;
|
||||
std::string Ret(TO, 0);
|
||||
std::copy_n(C.begin(), TO, Ret.begin());
|
||||
return Ret;
|
||||
}
|
||||
238
src/Console.cpp
Normal file
238
src/Console.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 10/29/2020
|
||||
///
|
||||
|
||||
#include "Lua/LuaSystem.hpp"
|
||||
#ifdef WIN32
|
||||
#include <conio.h>
|
||||
#include <windows.h>
|
||||
#else // *nix
|
||||
typedef unsigned long DWORD, *PDWORD, *LPDWORD;
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#endif // WIN32
|
||||
#include "Logger.h"
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
std::vector<std::string> QConsoleOut;
|
||||
std::string CInputBuff;
|
||||
std::mutex MLock;
|
||||
std::unique_ptr<Lua> LuaConsole;
|
||||
void HandleInput(const std::string& cmd) {
|
||||
std::cout << std::endl;
|
||||
if (cmd == Sec("exit")) {
|
||||
_Exit(0);
|
||||
} else if (cmd == Sec("clear") || cmd == Sec("cls")) {
|
||||
// 2J is clearscreen, H is reset position to top-left
|
||||
ConsoleOut(Sec("\x1b[2J\x1b[H"));
|
||||
} else {
|
||||
LuaConsole->Execute(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessOut() {
|
||||
static size_t len = 2;
|
||||
if (QConsoleOut.empty() && len == CInputBuff.length())
|
||||
return;
|
||||
printf("%c[2K\r", 27);
|
||||
for (const std::string& msg : QConsoleOut)
|
||||
if (!msg.empty())
|
||||
std::cout << msg;
|
||||
MLock.lock();
|
||||
QConsoleOut.clear();
|
||||
MLock.unlock();
|
||||
std::cout << "> " << CInputBuff << std::flush;
|
||||
len = CInputBuff.length();
|
||||
}
|
||||
|
||||
void ConsoleOut(const std::string& msg) {
|
||||
MLock.lock();
|
||||
QConsoleOut.emplace_back(msg);
|
||||
MLock.unlock();
|
||||
}
|
||||
|
||||
[[noreturn]] void OutputRefresh() {
|
||||
DebugPrintTID();
|
||||
while (true) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
ProcessOut();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
static struct termios old, current;
|
||||
|
||||
void initTermios(int echo) {
|
||||
tcgetattr(0, &old); /* grab old terminal i/o settings */
|
||||
current = old; /* make new settings same as old settings */
|
||||
current.c_lflag &= ~ICANON; /* disable buffered i/o */
|
||||
if (echo) {
|
||||
current.c_lflag |= ECHO; /* set echo mode */
|
||||
} else {
|
||||
current.c_lflag &= ~ECHO; /* set no echo mode */
|
||||
}
|
||||
tcsetattr(0, TCSANOW, ¤t); /* use these new terminal i/o settings now */
|
||||
}
|
||||
|
||||
void resetTermios(void) {
|
||||
tcsetattr(0, TCSANOW, &old);
|
||||
}
|
||||
|
||||
char getch_(int echo) {
|
||||
char ch;
|
||||
initTermios(echo);
|
||||
read(STDIN_FILENO, &ch, 1);
|
||||
resetTermios();
|
||||
return ch;
|
||||
}
|
||||
|
||||
char _getch(void) {
|
||||
return getch_(0);
|
||||
}
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
void SetupConsole() {
|
||||
#if defined(WIN32) && !defined(DEBUG)
|
||||
DWORD outMode = 0;
|
||||
HANDLE stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (stdoutHandle == INVALID_HANDLE_VALUE) {
|
||||
error("Invalid handle");
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
_Exit(GetLastError());
|
||||
}
|
||||
if (!GetConsoleMode(stdoutHandle, &outMode)) {
|
||||
error("Invalid console mode");
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
_Exit(GetLastError());
|
||||
}
|
||||
// Enable ANSI escape codes
|
||||
outMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||
if (!SetConsoleMode(stdoutHandle, outMode)) {
|
||||
error("failed to set console mode");
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
_Exit(GetLastError());
|
||||
}
|
||||
#else
|
||||
#endif // WIN32
|
||||
}
|
||||
|
||||
static std::vector<std::string> ConsoleHistory {};
|
||||
static size_t ConsoleHistoryReadIndex { 0 };
|
||||
|
||||
static inline void ConsoleHistoryAdd(const std::string& cmd) {
|
||||
ConsoleHistory.push_back(cmd);
|
||||
ConsoleHistoryReadIndex = ConsoleHistory.size();
|
||||
}
|
||||
static std::string CompositeInput;
|
||||
static bool CompositeInputExpected { false };
|
||||
|
||||
static void ProcessCompositeInput() {
|
||||
#ifdef WIN32
|
||||
if (CompositeInput.size() == 1 && memcmp(CompositeInput.data(), std::array<char, 1> { 72 }.data(), 1) == 0) {
|
||||
#else // unix
|
||||
if (CompositeInput.size() == 2 && memcmp(CompositeInput.data(), std::array<char, 2> { 91, 65 }.data(), 2) == 0) {
|
||||
#endif // WIN32
|
||||
|
||||
// UP ARROW
|
||||
// info(std::to_string(ConsoleHistoryReadIndex));
|
||||
if (!ConsoleHistory.empty()) {
|
||||
if (ConsoleHistoryReadIndex != 0) {
|
||||
ConsoleHistoryReadIndex -= 1;
|
||||
}
|
||||
CInputBuff = ConsoleHistory.at(ConsoleHistoryReadIndex);
|
||||
}
|
||||
#ifdef WIN32
|
||||
} else if (CompositeInput.size() == 1 && memcmp(CompositeInput.data(), std::array<char, 1> { 80 }.data(), 1) == 0) {
|
||||
#else // unix
|
||||
} else if (CompositeInput.size() == 2 && memcmp(CompositeInput.data(), std::array<char, 2> { 91, 66 }.data(), 2) == 0) {
|
||||
#endif // WIN32
|
||||
|
||||
// DOWN ARROW
|
||||
if (!ConsoleHistory.empty()) {
|
||||
if (ConsoleHistoryReadIndex != ConsoleHistory.size() - 1) {
|
||||
ConsoleHistoryReadIndex += 1;
|
||||
CInputBuff = ConsoleHistory.at(ConsoleHistoryReadIndex);
|
||||
} else {
|
||||
CInputBuff = "";
|
||||
ConsoleHistoryReadIndex = ConsoleHistory.size();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// not composite input, we made a mistake, so lets just add it to the buffer like usual
|
||||
CInputBuff += CompositeInput;
|
||||
}
|
||||
// ensure history doesnt grow too far beyond a max
|
||||
static constexpr size_t MaxHistory = 10;
|
||||
if (ConsoleHistory.size() > 2 * MaxHistory) {
|
||||
std::vector<std::string> NewHistory(ConsoleHistory.begin() + ConsoleHistory.size() - MaxHistory, ConsoleHistory.end());
|
||||
ConsoleHistory = std::move(NewHistory);
|
||||
ConsoleHistoryReadIndex = ConsoleHistory.size();
|
||||
}
|
||||
}
|
||||
|
||||
[[noreturn]] void ReadCin() {
|
||||
DebugPrintTID();
|
||||
while (true) {
|
||||
int In = _getch();
|
||||
// info(std::to_string(In));
|
||||
if (CompositeInputExpected) {
|
||||
CompositeInput += char(In);
|
||||
#ifdef WIN32
|
||||
if (CompositeInput.size() == 1) {
|
||||
#else // unix
|
||||
if (CompositeInput.size() == 2) {
|
||||
#endif // WIN32
|
||||
CompositeInputExpected = false;
|
||||
ProcessCompositeInput();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (In == 13 || In == '\n') {
|
||||
if (!CInputBuff.empty()) {
|
||||
HandleInput(CInputBuff);
|
||||
ConsoleHistoryAdd(CInputBuff);
|
||||
CInputBuff.clear();
|
||||
}
|
||||
} else if (In == 8 || In == 127) {
|
||||
if (!CInputBuff.empty())
|
||||
CInputBuff.pop_back();
|
||||
} else if (In == 4) {
|
||||
CInputBuff = "exit";
|
||||
HandleInput(CInputBuff);
|
||||
CInputBuff.clear();
|
||||
} else if (In == 12) {
|
||||
CInputBuff = "clear";
|
||||
HandleInput(CInputBuff);
|
||||
CInputBuff.clear();
|
||||
#ifdef WIN32
|
||||
} else if (In == 224) {
|
||||
#else // unix
|
||||
} else if (In == 27) {
|
||||
#endif // WIN32
|
||||
|
||||
// escape char, assume stuff follows
|
||||
CompositeInputExpected = true;
|
||||
CompositeInput.clear();
|
||||
} else if (!isprint(In)) {
|
||||
// ignore
|
||||
} else {
|
||||
CInputBuff += char(In);
|
||||
}
|
||||
}
|
||||
}
|
||||
void ConsoleInit() {
|
||||
SetupConsole();
|
||||
LuaConsole = std::make_unique<Lua>(true);
|
||||
printf("> ");
|
||||
std::thread In(ReadCin);
|
||||
In.detach();
|
||||
std::thread Out(OutputRefresh);
|
||||
Out.detach();
|
||||
}
|
||||
132
src/Enc.cpp
Normal file
132
src/Enc.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/28/2020
|
||||
///
|
||||
#include "Security/Enc.h"
|
||||
#include "CustomAssert.h"
|
||||
#include "Settings.h"
|
||||
//#include <windows.h>
|
||||
#include "Logger.h"
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
int Rand() {
|
||||
std::random_device r;
|
||||
std::default_random_engine e1(r());
|
||||
std::uniform_int_distribution<int> uniform_dist(1, 5000);
|
||||
return uniform_dist(e1);
|
||||
}
|
||||
|
||||
int log_power(int n, unsigned int p, int mod) {
|
||||
int result = 1;
|
||||
for (; p; p >>= 1u) {
|
||||
if (p & 1u)
|
||||
result = int((1LL * result * n) % mod);
|
||||
n = int((1LL * n * n) % mod);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
bool rabin_miller(int n) {
|
||||
bool ok = true;
|
||||
for (int i = 1; i <= 5 && ok; i++) {
|
||||
int a = Rand() + 1;
|
||||
int result = log_power(a, n - 1, n);
|
||||
ok &= (result == 1);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
int generate_prime() {
|
||||
int generated = Rand();
|
||||
while (!rabin_miller(generated))
|
||||
generated = Rand();
|
||||
return generated;
|
||||
}
|
||||
int gcd(int a, int b) {
|
||||
while (b) {
|
||||
int r = a % b;
|
||||
a = b;
|
||||
b = r;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
int generate_coprime(int n) {
|
||||
int generated = Rand();
|
||||
while (gcd(n, generated) != 1)
|
||||
generated = Rand();
|
||||
return generated;
|
||||
}
|
||||
|
||||
std::pair<int, int> euclid_extended(int a, int b) {
|
||||
if (!b)
|
||||
return { 1, 0 };
|
||||
auto result = euclid_extended(b, a % b);
|
||||
return { result.second, result.first - (a / b) * result.second };
|
||||
}
|
||||
|
||||
int modular_inverse(int n, int mod) {
|
||||
int inverse = euclid_extended(n, mod).first;
|
||||
while (inverse < 0)
|
||||
inverse += mod;
|
||||
return inverse;
|
||||
}
|
||||
|
||||
RSA* GenKey() {
|
||||
int p, q;
|
||||
p = generate_prime();
|
||||
q = generate_prime();
|
||||
int n = p * q;
|
||||
int phi = (p - 1) * (q - 1);
|
||||
int e = generate_coprime(phi);
|
||||
int d = modular_inverse(e, phi);
|
||||
return new RSA { n, e, d };
|
||||
}
|
||||
|
||||
int Enc(int value, int e, int n) {
|
||||
return log_power(value, e, n);
|
||||
}
|
||||
|
||||
int Dec(int value, int d, int n) {
|
||||
return log_power(value, d, n);
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
int Handle(EXCEPTION_POINTERS* ep, char* Origin) {
|
||||
//Assert(false);
|
||||
std::stringstream R;
|
||||
R << Sec("Code : ") << std::hex
|
||||
<< ep->ExceptionRecord->ExceptionCode
|
||||
<< std::dec << Sec(" Origin : ") << Origin;
|
||||
except(R.str());
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
// stub
|
||||
int Handle(EXCEPTION_POINTERS*, char*) { return 1; }
|
||||
#endif // WIN32
|
||||
|
||||
std::string RSA_E(const std::string& Data, RSA* k) {
|
||||
std::stringstream stream;
|
||||
for (const char& c : Data) {
|
||||
stream << std::hex << Enc(uint8_t(c), k->e, k->n) << "g";
|
||||
}
|
||||
return stream.str();
|
||||
}
|
||||
std::string RSA_E(const std::string& Data, int e, int n) {
|
||||
std::stringstream stream;
|
||||
for (const char& c : Data) {
|
||||
stream << std::hex << Enc(uint8_t(c), e, n) << "g";
|
||||
}
|
||||
return stream.str();
|
||||
}
|
||||
std::string RSA_D(const std::string& Data, RSA* k) {
|
||||
std::stringstream ss(Data);
|
||||
std::string token, ret;
|
||||
while (std::getline(ss, token, 'g')) {
|
||||
if (token.find_first_not_of(Sec("0123456789abcdef")) != std::string::npos)
|
||||
return "";
|
||||
int c = std::stoi(token, nullptr, 16);
|
||||
ret += char(Dec(c, k->d, k->n));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
161
src/Init/Config.cpp
Normal file
161
src/Init/Config.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/28/2020
|
||||
///
|
||||
#include "CustomAssert.h"
|
||||
#include "Logger.h"
|
||||
#include "Security/Enc.h"
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
std::string ServerName;
|
||||
std::string ServerDesc;
|
||||
std::string Resource;
|
||||
std::string MapName;
|
||||
std::string Key;
|
||||
int MaxPlayers;
|
||||
bool Private;
|
||||
int MaxCars;
|
||||
bool Debug;
|
||||
int Port;
|
||||
|
||||
void SetValues(const std::string& Line, int Index) {
|
||||
int state = 0;
|
||||
std::string Data;
|
||||
bool Switch = false;
|
||||
if (Index > 5)
|
||||
Switch = true;
|
||||
for (char c : Line) {
|
||||
if (Switch) {
|
||||
if (c == '\"')
|
||||
state++;
|
||||
if (state > 0 && state < 2)
|
||||
Data += c;
|
||||
} else {
|
||||
if (c == ' ')
|
||||
state++;
|
||||
if (state > 1)
|
||||
Data += c;
|
||||
}
|
||||
}
|
||||
Data = Data.substr(1);
|
||||
std::string::size_type sz;
|
||||
bool FoundTrue = std::string(Data).find("true") != std::string::npos; //searches for "true"
|
||||
switch (Index) {
|
||||
case 1:
|
||||
Debug = FoundTrue; //checks and sets the Debug Value
|
||||
break;
|
||||
case 2:
|
||||
Private = FoundTrue; //checks and sets the Private Value
|
||||
break;
|
||||
case 3:
|
||||
Port = std::stoi(Data, &sz); //sets the Port
|
||||
break;
|
||||
case 4:
|
||||
MaxCars = std::stoi(Data, &sz); //sets the Max Car amount
|
||||
break;
|
||||
case 5:
|
||||
MaxPlayers = std::stoi(Data, &sz); //sets the Max Amount of player
|
||||
break;
|
||||
case 6:
|
||||
MapName = Data; //Map
|
||||
break;
|
||||
case 7:
|
||||
ServerName = Data; //Name
|
||||
break;
|
||||
case 8:
|
||||
ServerDesc = Data; //desc
|
||||
break;
|
||||
case 9:
|
||||
Resource = Data; //File name
|
||||
break;
|
||||
case 10:
|
||||
Key = Data; //File name
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::string RemoveComments(const std::string& Line) {
|
||||
std::string Return;
|
||||
for (char c : Line) {
|
||||
if (c == '#')
|
||||
break;
|
||||
Return += c;
|
||||
}
|
||||
return Return;
|
||||
}
|
||||
void LoadConfig(std::ifstream& IFS) {
|
||||
Assert(IFS.is_open());
|
||||
std::string line;
|
||||
int index = 1;
|
||||
while (getline(IFS, line)) {
|
||||
index++;
|
||||
}
|
||||
if (index - 1 < 11) {
|
||||
error(Sec("Outdated/Incorrect config please remove it server will close in 5 secs"));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
_Exit(0);
|
||||
}
|
||||
IFS.close();
|
||||
IFS.open(Sec("Server.cfg"));
|
||||
info(Sec("Config found updating values"));
|
||||
index = 1;
|
||||
while (getline(IFS, line)) {
|
||||
if (line.rfind('#', 0) != 0 && line.rfind(' ', 0) != 0) { //Checks if it starts as Comment
|
||||
std::string CleanLine = RemoveComments(line); //Cleans it from the Comments
|
||||
SetValues(CleanLine, index); //sets the values
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
void GenerateConfig() {
|
||||
std::ofstream FileStream;
|
||||
FileStream.open(Sec("Server.cfg"));
|
||||
FileStream << Sec("# This is the BeamMP Server Configuration File v0.60\n"
|
||||
"Debug = false # true or false to enable debug console output\n"
|
||||
"Private = true # Private?\n"
|
||||
"Port = 30814 # Port to run the server on UDP and TCP\n"
|
||||
"Cars = 1 # Max cars for every player\n"
|
||||
"MaxPlayers = 10 # Maximum Amount of Clients\n"
|
||||
"Map = \"/levels/gridmap/info.json\" # Default Map\n"
|
||||
"Name = \"BeamMP New Server\" # Server Name\n"
|
||||
"Desc = \"BeamMP Default Description\" # Server Description\n"
|
||||
"use = \"Resources\" # Resource file name\n"
|
||||
"AuthKey = \"\" # Auth Key");
|
||||
FileStream.close();
|
||||
}
|
||||
void Default() {
|
||||
info(Sec("Config not found generating default"));
|
||||
GenerateConfig();
|
||||
error(Sec("You are required to input the AuthKey"));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
_Exit(0);
|
||||
}
|
||||
void DebugData() {
|
||||
debug(std::string(Sec("Debug : ")) + (Debug ? "true" : "false"));
|
||||
debug(std::string(Sec("Private : ")) + (Private ? "true" : "false"));
|
||||
debug(Sec("Port : ") + std::to_string(Port));
|
||||
debug(Sec("Max Cars : ") + std::to_string(MaxCars));
|
||||
debug(Sec("MaxPlayers : ") + std::to_string(MaxPlayers));
|
||||
debug(Sec("MapName : ") + MapName);
|
||||
debug(Sec("ServerName : ") + ServerName);
|
||||
debug(Sec("ServerDesc : ") + ServerDesc);
|
||||
debug(Sec("File : ") + Resource);
|
||||
debug(Sec("Key length: ") + std::to_string(Key.length()));
|
||||
}
|
||||
void InitConfig() {
|
||||
std::ifstream IFS;
|
||||
IFS.open(Sec("Server.cfg"));
|
||||
if (IFS.good())
|
||||
LoadConfig(IFS);
|
||||
else
|
||||
Default();
|
||||
if (IFS.is_open())
|
||||
IFS.close();
|
||||
if (Key.empty()) {
|
||||
error(Sec("No AuthKey was found"));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
_Exit(0);
|
||||
}
|
||||
if (Debug)
|
||||
DebugData();
|
||||
}
|
||||
85
src/Init/Heartbeat.cpp
Normal file
85
src/Init/Heartbeat.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/28/2020
|
||||
///
|
||||
#include "Client.hpp"
|
||||
#include "Curl/Http.h"
|
||||
#include "Logger.h"
|
||||
#include "Security/Enc.h"
|
||||
#include "Settings.h"
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
void WebsocketInit();
|
||||
std::string GetPlayers() {
|
||||
std::string Return;
|
||||
for (auto& c : CI->Clients) {
|
||||
if (c != nullptr) {
|
||||
Return += c->GetName() + ";";
|
||||
}
|
||||
}
|
||||
return Return;
|
||||
}
|
||||
std::string GenerateCall() {
|
||||
std::stringstream Ret;
|
||||
Ret << "uuid=" << Key << "&players=" << CI->Size()
|
||||
<< "&maxplayers=" << MaxPlayers << "&port=" << Port
|
||||
<< "&map=" << MapName << "&private=" << (Private ? "true" : "false")
|
||||
<< "&version=" << GetSVer() << "&clientversion=" << GetCVer()
|
||||
<< "&name=" << ServerName << "&pps=" << StatReport
|
||||
<< "&modlist=" << FileList << "&modstotalsize=" << MaxModSize
|
||||
<< "&modstotal=" << ModsLoaded << "&playerslist=" << GetPlayers()
|
||||
<< "&desc=" << ServerDesc;
|
||||
return Ret.str();
|
||||
}
|
||||
std::string RunPromise(const std::string& IP, const std::string& R) {
|
||||
std::packaged_task<std::string()> task([&]() { return PostHTTP(IP, R); });
|
||||
std::future<std::string> f1 = task.get_future();
|
||||
std::thread t(std::move(task));
|
||||
t.detach();
|
||||
auto status = f1.wait_for(std::chrono::seconds(10));
|
||||
if (status != std::future_status::timeout)
|
||||
return f1.get();
|
||||
error(Sec("Backend system Timeout please try again later"));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
_Exit(0);
|
||||
}
|
||||
|
||||
void Heartbeat() {
|
||||
DebugPrintTID();
|
||||
std::string R, T;
|
||||
bool isAuth = false;
|
||||
while (true) {
|
||||
R = GenerateCall();
|
||||
if (!CustomIP.empty())
|
||||
R += "&ip=" + CustomIP;
|
||||
std::string link = Sec("https://beammp.com/heartbeatv2");
|
||||
T = RunPromise(link, R);
|
||||
if (T.find_first_not_of(Sec("20")) != std::string::npos) {
|
||||
//Backend system refused server startup!
|
||||
std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
std::string Backup = Sec("https://backup1.beammp.com/heartbeatv2");
|
||||
T = RunPromise(Backup, R);
|
||||
if (T.find_first_not_of(Sec("20")) != std::string::npos) {
|
||||
error(Sec("Backend system refused server! Check your AuthKey"));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
_Exit(-1);
|
||||
}
|
||||
}
|
||||
//Server Authenticated
|
||||
if (T.length() == 4)
|
||||
info(Sec("Server authenticated"));
|
||||
R.clear();
|
||||
T.clear();
|
||||
if (!isAuth) {
|
||||
WebsocketInit();
|
||||
isAuth = true;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
}
|
||||
}
|
||||
void HBInit() {
|
||||
std::thread HB(Heartbeat);
|
||||
HB.detach();
|
||||
}
|
||||
36
src/Init/Resources.cpp
Normal file
36
src/Init/Resources.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/28/2020
|
||||
///
|
||||
#include "Logger.h"
|
||||
#include "Security/Enc.h"
|
||||
#include "Settings.h"
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
uint64_t MaxModSize = 0;
|
||||
std::string FileSizes;
|
||||
std::string FileList;
|
||||
int ModsLoaded = 0;
|
||||
|
||||
void InitRes() {
|
||||
std::string Path = Resource + Sec("/Client");
|
||||
if (!fs::exists(Path))
|
||||
fs::create_directory(Path);
|
||||
for (const auto& entry : fs::directory_iterator(Path)) {
|
||||
auto pos = entry.path().string().find(Sec(".zip"));
|
||||
if (pos != std::string::npos) {
|
||||
if (entry.path().string().length() - pos == 4) {
|
||||
FileList += entry.path().string() + ";";
|
||||
FileSizes += std::to_string(fs::file_size(entry.path())) + ";";
|
||||
MaxModSize += fs::file_size(entry.path());
|
||||
ModsLoaded++;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::replace(FileList.begin(), FileList.end(), '\\', '/');
|
||||
if (ModsLoaded) {
|
||||
info(Sec("Loaded ") + std::to_string(ModsLoaded) + Sec(" Mods"));
|
||||
}
|
||||
}
|
||||
36
src/Init/Startup.cpp
Normal file
36
src/Init/Startup.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/28/2020
|
||||
///
|
||||
#include "Client.hpp"
|
||||
#include "Logger.h"
|
||||
#include "Security/Enc.h"
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
std::string CustomIP;
|
||||
std::string GetSVer() {
|
||||
static std::string r = Sec("1.0");
|
||||
return r;
|
||||
}
|
||||
std::string GetCVer() {
|
||||
static std::string r = Sec("1.70");
|
||||
return r;
|
||||
}
|
||||
void Args(int argc, char* argv[]) {
|
||||
info(Sec("BeamMP Server Running version ") + GetSVer());
|
||||
if (argc > 1) {
|
||||
CustomIP = argv[1];
|
||||
size_t n = std::count(CustomIP.begin(), CustomIP.end(), '.');
|
||||
auto p = CustomIP.find_first_not_of(Sec(".0123456789"));
|
||||
if (p != std::string::npos || n != 3 || CustomIP.substr(0, 3) == Sec("127")) {
|
||||
CustomIP.clear();
|
||||
warn(Sec("IP Specified is invalid! Ignoring"));
|
||||
} else
|
||||
info(Sec("Server started with custom IP"));
|
||||
}
|
||||
}
|
||||
void InitServer(int argc, char* argv[]) {
|
||||
InitLog();
|
||||
Args(argc, argv);
|
||||
CI = std::make_unique<ClientInterface>();
|
||||
}
|
||||
88
src/Lua/LuaMain.cpp
Normal file
88
src/Lua/LuaMain.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 5/20/2020
|
||||
///
|
||||
|
||||
#include "Logger.h"
|
||||
#include "Lua/LuaSystem.hpp"
|
||||
#include "Security/Enc.h"
|
||||
#include "Settings.h"
|
||||
#include <thread>
|
||||
|
||||
#ifdef __linux
|
||||
// we need this for `struct stat`
|
||||
#include <sys/stat.h>
|
||||
#endif // __linux
|
||||
|
||||
std::set<std::unique_ptr<Lua>> PluginEngine;
|
||||
bool NewFile(const std::string& Path) {
|
||||
for (auto& Script : PluginEngine) {
|
||||
if (Path == Script->GetFileName())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void RegisterFiles(const std::string& Path, bool HotSwap) {
|
||||
std::string Name = Path.substr(Path.find_last_of('\\') + 1);
|
||||
if (!HotSwap)
|
||||
info(Sec("Loading plugin : ") + Name);
|
||||
for (const auto& entry : fs::directory_iterator(Path)) {
|
||||
auto pos = entry.path().string().find(Sec(".lua"));
|
||||
if (pos != std::string::npos && entry.path().string().length() - pos == 4) {
|
||||
if (!HotSwap || NewFile(entry.path().string())) {
|
||||
auto FileName = entry.path().string();
|
||||
std::unique_ptr<Lua> ScriptToInsert(new Lua(Name, FileName, fs::last_write_time(FileName)));
|
||||
auto& Script = *ScriptToInsert;
|
||||
PluginEngine.insert(std::move(ScriptToInsert));
|
||||
Script.Init();
|
||||
if (HotSwap)
|
||||
info(Sec("[HOTSWAP] Added : ") + Script.GetFileName().substr(Script.GetFileName().find('\\')));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void FolderList(const std::string& Path, bool HotSwap) {
|
||||
for (const auto& entry : fs::directory_iterator(Path)) {
|
||||
auto pos = entry.path().filename().string().find('.');
|
||||
if (pos == std::string::npos) {
|
||||
RegisterFiles(entry.path().string(), HotSwap);
|
||||
}
|
||||
}
|
||||
}
|
||||
[[noreturn]] void HotSwaps(const std::string& path) {
|
||||
DebugPrintTID();
|
||||
while (true) {
|
||||
if (!PluginEngine.empty()) {
|
||||
for (auto& Script : PluginEngine) {
|
||||
struct stat Info { };
|
||||
if (stat(Script->GetFileName().c_str(), &Info) != 0) {
|
||||
Script->SetStopThread(true);
|
||||
PluginEngine.erase(Script);
|
||||
info(Sec("[HOTSWAP] Removed : ") + Script->GetFileName().substr(Script->GetFileName().find('\\')));
|
||||
break;
|
||||
}
|
||||
if (Script->GetLastWrite() != fs::last_write_time(Script->GetFileName())) {
|
||||
Script->SetStopThread(true);
|
||||
info(Sec("[HOTSWAP] Updated : ") + Script->GetFileName().substr(Script->GetFileName().find('\\')));
|
||||
Script->SetLastWrite(fs::last_write_time(Script->GetFileName()));
|
||||
Script->Reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
FolderList(path, true);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
}
|
||||
}
|
||||
|
||||
void InitLua() {
|
||||
if (!fs::exists(Resource)) {
|
||||
fs::create_directory(Resource);
|
||||
}
|
||||
std::string Path = Resource + Sec("/Server");
|
||||
if (!fs::exists(Path)) {
|
||||
fs::create_directory(Path);
|
||||
}
|
||||
FolderList(Path, false);
|
||||
std::thread t1(HotSwaps, Path);
|
||||
t1.detach();
|
||||
info(Sec("Lua system online"));
|
||||
}
|
||||
668
src/Lua/LuaSystem.cpp
Normal file
668
src/Lua/LuaSystem.cpp
Normal file
@@ -0,0 +1,668 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 5/19/2020
|
||||
///
|
||||
|
||||
#include "Lua/LuaSystem.hpp"
|
||||
#include "Client.hpp"
|
||||
#include "Logger.h"
|
||||
#include "Network.h"
|
||||
#include "Security/Enc.h"
|
||||
#include "Settings.h"
|
||||
#include "UnixCompat.h"
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
std::unique_ptr<LuaArg> CreateArg(lua_State* L, int T, int S) {
|
||||
if (S > T)
|
||||
return nullptr;
|
||||
std::unique_ptr<LuaArg> temp(new LuaArg);
|
||||
for (int C = S; C <= T; C++) {
|
||||
if (lua_isstring(L, C)) {
|
||||
temp->args.emplace_back(std::string(lua_tostring(L, C)));
|
||||
} else if (lua_isinteger(L, C)) {
|
||||
temp->args.emplace_back(int(lua_tointeger(L, C)));
|
||||
} else if (lua_isboolean(L, C)) {
|
||||
temp->args.emplace_back(bool(lua_toboolean(L, C)));
|
||||
} else if (lua_isnumber(L, C)) {
|
||||
temp->args.emplace_back(float(lua_tonumber(L, C)));
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
void ClearStack(lua_State* L) {
|
||||
lua_settop(L, 0);
|
||||
}
|
||||
std::optional<std::reference_wrapper<Lua>> GetScript(lua_State* L) {
|
||||
for (auto& Script : PluginEngine) {
|
||||
if (Script->GetState() == L)
|
||||
return *Script;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
void SendError(lua_State* L, const std::string& msg) {
|
||||
Assert(L);
|
||||
auto MaybeS = GetScript(L);
|
||||
std::string a;
|
||||
if (!MaybeS.has_value()) {
|
||||
a = Sec("_Console");
|
||||
} else {
|
||||
Lua& S = MaybeS.value();
|
||||
a = fs::path(S.GetFileName()).filename().string();
|
||||
}
|
||||
warn(a + Sec(" | Incorrect Call of ") + msg);
|
||||
}
|
||||
int Trigger(Lua* lua, const std::string& R, std::unique_ptr<LuaArg> arg) {
|
||||
std::lock_guard<std::mutex> lockGuard(lua->Lock);
|
||||
std::packaged_task<int(std::unique_ptr<LuaArg>)> task([lua, R](std::unique_ptr<LuaArg> arg) { return CallFunction(lua, R, std::move(arg)); });
|
||||
std::future<int> f1 = task.get_future();
|
||||
std::thread t(std::move(task), std::move(arg));
|
||||
t.detach();
|
||||
auto status = f1.wait_for(std::chrono::seconds(5));
|
||||
if (status != std::future_status::timeout)
|
||||
return f1.get();
|
||||
SendError(lua->GetState(), R + " took too long to respond");
|
||||
return 0;
|
||||
}
|
||||
int FutureWait(Lua* lua, const std::string& R, std::unique_ptr<LuaArg> arg, bool Wait) {
|
||||
Assert(lua);
|
||||
std::packaged_task<int(std::unique_ptr<LuaArg>)> task([lua, R](std::unique_ptr<LuaArg> arg) { return Trigger(lua, R, std::move(arg)); });
|
||||
std::future<int> f1 = task.get_future();
|
||||
std::thread t(std::move(task), std::move(arg));
|
||||
t.detach();
|
||||
int T = 0;
|
||||
if (Wait)
|
||||
T = 6;
|
||||
auto status = f1.wait_for(std::chrono::seconds(T));
|
||||
if (status != std::future_status::timeout)
|
||||
return f1.get();
|
||||
return 0;
|
||||
}
|
||||
int TriggerLuaEvent(const std::string& Event, bool local, Lua* Caller, std::unique_ptr<LuaArg> arg, bool Wait) {
|
||||
int R = 0;
|
||||
for (auto& Script : PluginEngine) {
|
||||
if (Script->IsRegistered(Event)) {
|
||||
if (local) {
|
||||
if (Script->GetPluginName() == Caller->GetPluginName()) {
|
||||
R += FutureWait(Script.get(), Script->GetRegistered(Event), std::move(arg), Wait);
|
||||
}
|
||||
} else
|
||||
R += FutureWait(Script.get(), Script->GetRegistered(Event), std::move(arg), Wait);
|
||||
}
|
||||
}
|
||||
return R;
|
||||
}
|
||||
bool ConsoleCheck(lua_State* L, int r) {
|
||||
if (r != LUA_OK) {
|
||||
std::string msg = lua_tostring(L, -1);
|
||||
warn(Sec("_Console | ") + msg);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool CheckLua(lua_State* L, int r) {
|
||||
if (r != LUA_OK) {
|
||||
std::string msg = lua_tostring(L, -1);
|
||||
auto MaybeS = GetScript(L);
|
||||
if (MaybeS.has_value()) {
|
||||
Lua& S = MaybeS.value();
|
||||
std::string a = fs::path(S.GetFileName()).filename().string();
|
||||
warn(a + " | " + msg);
|
||||
return false;
|
||||
}
|
||||
// What the fuck, what do we do?!
|
||||
AssertNotReachable();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int lua_RegisterEvent(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
auto MaybeScript = GetScript(L);
|
||||
Assert(MaybeScript.has_value());
|
||||
Lua& Script = MaybeScript.value();
|
||||
if (Args == 2 && lua_isstring(L, 1) && lua_isstring(L, 2)) {
|
||||
Script.RegisterEvent(lua_tostring(L, 1), lua_tostring(L, 2));
|
||||
} else
|
||||
SendError(L, Sec("RegisterEvent invalid argument count expected 2 got ") + std::to_string(Args));
|
||||
return 0;
|
||||
}
|
||||
int lua_TriggerEventL(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
auto MaybeScript = GetScript(L);
|
||||
Assert(MaybeScript.has_value());
|
||||
Lua& Script = MaybeScript.value();
|
||||
if (Args > 0) {
|
||||
if (lua_isstring(L, 1)) {
|
||||
TriggerLuaEvent(lua_tostring(L, 1), true, &Script, CreateArg(L, Args, 2), false);
|
||||
} else
|
||||
SendError(L, Sec("TriggerLocalEvent wrong argument [1] need string"));
|
||||
} else {
|
||||
SendError(L, Sec("TriggerLocalEvent not enough arguments expected 1 got 0"));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lua_TriggerEventG(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
auto MaybeScript = GetScript(L);
|
||||
Assert(MaybeScript.has_value());
|
||||
Lua& Script = MaybeScript.value();
|
||||
if (Args > 0) {
|
||||
if (lua_isstring(L, 1)) {
|
||||
TriggerLuaEvent(lua_tostring(L, 1), false, &Script, CreateArg(L, Args, 2), false);
|
||||
} else
|
||||
SendError(L, Sec("TriggerGlobalEvent wrong argument [1] need string"));
|
||||
} else
|
||||
SendError(L, Sec("TriggerGlobalEvent not enough arguments"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* ThreadOrigin(Lua* lua) {
|
||||
std::string T = "Thread in " + fs::path(lua->GetFileName()).filename().string();
|
||||
char* Data = new char[T.size() + 1];
|
||||
ZeroMemory(Data, T.size() + 1);
|
||||
memcpy(Data, T.c_str(), T.size());
|
||||
return Data;
|
||||
}
|
||||
void SafeExecution(Lua* lua, const std::string& FuncName) {
|
||||
lua_State* luaState = lua->GetState();
|
||||
lua_getglobal(luaState, FuncName.c_str());
|
||||
if (lua_isfunction(luaState, -1)) {
|
||||
char* Origin = ThreadOrigin(lua);
|
||||
#ifdef WIN32
|
||||
__try {
|
||||
int R = lua_pcall(luaState, 0, 0, 0);
|
||||
CheckLua(luaState, R);
|
||||
} __except (Handle(GetExceptionInformation(), Origin)) {
|
||||
}
|
||||
#else // unix
|
||||
int R = lua_pcall(luaState, 0, 0, 0);
|
||||
CheckLua(luaState, R);
|
||||
#endif // WIN32
|
||||
delete[] Origin;
|
||||
}
|
||||
ClearStack(luaState);
|
||||
}
|
||||
|
||||
void ExecuteAsync(Lua* lua, const std::string& FuncName) {
|
||||
std::lock_guard<std::mutex> lockGuard(lua->Lock);
|
||||
SafeExecution(lua, FuncName);
|
||||
}
|
||||
void CallAsync(Lua* lua, const std::string& Func, int U) {
|
||||
DebugPrintTID();
|
||||
lua->SetStopThread(false);
|
||||
int D = 1000 / U;
|
||||
while (!lua->GetStopThread()) {
|
||||
ExecuteAsync(lua, Func);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(D));
|
||||
}
|
||||
}
|
||||
int lua_StopThread(lua_State* L) {
|
||||
auto MaybeScript = GetScript(L);
|
||||
Assert(MaybeScript.has_value());
|
||||
// ugly, but whatever, this is safe as fuck
|
||||
MaybeScript.value().get().SetStopThread(true);
|
||||
return 0;
|
||||
}
|
||||
int lua_CreateThread(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
if (Args > 1) {
|
||||
if (lua_isstring(L, 1)) {
|
||||
std::string STR = lua_tostring(L, 1);
|
||||
if (lua_isinteger(L, 2) || lua_isnumber(L, 2)) {
|
||||
int U = int(lua_tointeger(L, 2));
|
||||
if (U > 0 && U < 501) {
|
||||
auto MaybeScript = GetScript(L);
|
||||
Assert(MaybeScript.has_value());
|
||||
Lua& Script = MaybeScript.value();
|
||||
std::thread t1(CallAsync, &Script, STR, U);
|
||||
t1.detach();
|
||||
} else
|
||||
SendError(L, Sec("CreateThread wrong argument [2] number must be between 1 and 500"));
|
||||
} else
|
||||
SendError(L, Sec("CreateThread wrong argument [2] need number"));
|
||||
} else
|
||||
SendError(L, Sec("CreateThread wrong argument [1] need string"));
|
||||
} else
|
||||
SendError(L, Sec("CreateThread not enough arguments"));
|
||||
return 0;
|
||||
}
|
||||
int lua_Sleep(lua_State* L) {
|
||||
if (lua_isnumber(L, 1)) {
|
||||
int t = int(lua_tonumber(L, 1));
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(t));
|
||||
} else {
|
||||
SendError(L, Sec("Sleep not enough arguments"));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
Client* GetClient(int ID) {
|
||||
for (auto& c : CI->Clients) {
|
||||
if (c != nullptr && c->GetID() == ID) {
|
||||
return c.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
int lua_isConnected(lua_State* L) {
|
||||
if (lua_isnumber(L, 1)) {
|
||||
int ID = int(lua_tonumber(L, 1));
|
||||
Client* c = GetClient(ID);
|
||||
if (c != nullptr)
|
||||
lua_pushboolean(L, c->isConnected);
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
SendError(L, Sec("isConnected not enough arguments"));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
int lua_GetPlayerName(lua_State* L) {
|
||||
if (lua_isnumber(L, 1)) {
|
||||
int ID = int(lua_tonumber(L, 1));
|
||||
Client* c = GetClient(ID);
|
||||
if (c != nullptr)
|
||||
lua_pushstring(L, c->GetName().c_str());
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
SendError(L, Sec("GetPlayerName not enough arguments"));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
int lua_GetPlayerCount(lua_State* L) {
|
||||
lua_pushinteger(L, CI->Size());
|
||||
return 1;
|
||||
}
|
||||
int lua_GetDID(lua_State* L) {
|
||||
if (lua_isnumber(L, 1)) {
|
||||
int ID = int(lua_tonumber(L, 1));
|
||||
Client* c = GetClient(ID);
|
||||
if (c != nullptr)
|
||||
lua_pushstring(L, c->GetDID().c_str());
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
SendError(L, Sec("GetDID not enough arguments"));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
int lua_GetAllPlayers(lua_State* L) {
|
||||
lua_newtable(L);
|
||||
int i = 1;
|
||||
for (auto& c : CI->Clients) {
|
||||
if (c == nullptr)
|
||||
continue;
|
||||
lua_pushinteger(L, c->GetID());
|
||||
lua_pushstring(L, c->GetName().c_str());
|
||||
lua_settable(L, -3);
|
||||
i++;
|
||||
}
|
||||
if (CI->Clients.empty())
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
int lua_GetCars(lua_State* L) {
|
||||
if (lua_isnumber(L, 1)) {
|
||||
int ID = int(lua_tonumber(L, 1));
|
||||
Client* c = GetClient(ID);
|
||||
if (c != nullptr) {
|
||||
int i = 1;
|
||||
for (auto& v : c->GetAllCars()) {
|
||||
if (v != nullptr) {
|
||||
lua_pushinteger(L, v->ID);
|
||||
lua_pushstring(L, v->Data.substr(3).c_str());
|
||||
lua_settable(L, -3);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (c->GetAllCars().empty())
|
||||
return 0;
|
||||
} else
|
||||
return 0;
|
||||
} else {
|
||||
SendError(L, Sec("GetPlayerVehicles not enough arguments"));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
int lua_dropPlayer(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
if (lua_isnumber(L, 1)) {
|
||||
int ID = int(lua_tonumber(L, 1));
|
||||
Client* c = GetClient(ID);
|
||||
if (c == nullptr)
|
||||
return 0;
|
||||
if (c->GetRole() == Sec("MDEV"))
|
||||
return 0;
|
||||
std::string Reason;
|
||||
if (Args > 1 && lua_isstring(L, 2)) {
|
||||
Reason = std::string(Sec(" Reason : ")) + lua_tostring(L, 2);
|
||||
}
|
||||
Respond(c, "C:Server:You have been Kicked from the server! " + Reason, true);
|
||||
c->SetStatus(-2);
|
||||
info(Sec("Closing socket due to kick"));
|
||||
CloseSocketProper(c->GetTCPSock());
|
||||
|
||||
} else
|
||||
SendError(L, Sec("DropPlayer not enough arguments"));
|
||||
return 0;
|
||||
}
|
||||
int lua_sendChat(lua_State* L) {
|
||||
if (lua_isinteger(L, 1) || lua_isnumber(L, 1)) {
|
||||
if (lua_isstring(L, 2)) {
|
||||
int ID = int(lua_tointeger(L, 1));
|
||||
if (ID == -1) {
|
||||
std::string Packet = "C:Server: " + std::string(lua_tostring(L, 2));
|
||||
SendToAll(nullptr, Packet, true, true);
|
||||
} else {
|
||||
Client* c = GetClient(ID);
|
||||
if (c != nullptr) {
|
||||
if (!c->isSynced)
|
||||
return 0;
|
||||
std::string Packet = "C:Server: " + std::string(lua_tostring(L, 2));
|
||||
Respond(c, Packet, true);
|
||||
} else
|
||||
SendError(L, Sec("SendChatMessage invalid argument [1] invalid ID"));
|
||||
}
|
||||
} else
|
||||
SendError(L, Sec("SendChatMessage invalid argument [2] expected string"));
|
||||
} else
|
||||
SendError(L, Sec("SendChatMessage invalid argument [1] expected number"));
|
||||
return 0;
|
||||
}
|
||||
int lua_RemoveVehicle(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
if (Args != 2) {
|
||||
SendError(L, Sec("RemoveVehicle invalid argument count expected 2 got ") + std::to_string(Args));
|
||||
return 0;
|
||||
}
|
||||
if ((lua_isinteger(L, 1) || lua_isnumber(L, 1)) && (lua_isinteger(L, 2) || lua_isnumber(L, 2))) {
|
||||
int PID = int(lua_tointeger(L, 1));
|
||||
int VID = int(lua_tointeger(L, 2));
|
||||
Client* c = GetClient(PID);
|
||||
if (c == nullptr) {
|
||||
SendError(L, Sec("RemoveVehicle invalid Player ID"));
|
||||
return 0;
|
||||
}
|
||||
if (c->GetRole() == "MDEV")
|
||||
return 0;
|
||||
if (!c->GetCarData(VID).empty()) {
|
||||
std::string Destroy = "Od:" + std::to_string(PID) + "-" + std::to_string(VID);
|
||||
SendToAll(nullptr, Destroy, true, true);
|
||||
c->DeleteCar(VID);
|
||||
}
|
||||
} else
|
||||
SendError(L, Sec("RemoveVehicle invalid argument expected number"));
|
||||
return 0;
|
||||
}
|
||||
int lua_HWID(lua_State* L) {
|
||||
lua_pushinteger(L, -1);
|
||||
return 1;
|
||||
}
|
||||
int lua_RemoteEvent(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
if (Args != 3) {
|
||||
SendError(L, Sec("TriggerClientEvent invalid argument count expected 3 got ") + std::to_string(Args));
|
||||
return 0;
|
||||
}
|
||||
if (!lua_isnumber(L, 1)) {
|
||||
SendError(L, Sec("TriggerClientEvent invalid argument [1] expected number"));
|
||||
return 0;
|
||||
}
|
||||
if (!lua_isstring(L, 2)) {
|
||||
SendError(L, Sec("TriggerClientEvent invalid argument [2] expected string"));
|
||||
return 0;
|
||||
}
|
||||
if (!lua_isstring(L, 3)) {
|
||||
SendError(L, Sec("TriggerClientEvent invalid argument [3] expected string"));
|
||||
return 0;
|
||||
}
|
||||
int ID = int(lua_tointeger(L, 1));
|
||||
std::string Packet = "E:" + std::string(lua_tostring(L, 2)) + ":" + std::string(lua_tostring(L, 3));
|
||||
if (ID == -1)
|
||||
SendToAll(nullptr, Packet, true, true);
|
||||
else {
|
||||
Client* c = GetClient(ID);
|
||||
if (c == nullptr) {
|
||||
SendError(L, Sec("TriggerClientEvent invalid Player ID"));
|
||||
return 0;
|
||||
}
|
||||
Respond(c, Packet, true);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int lua_ServerExit(lua_State*) {
|
||||
_Exit(0);
|
||||
}
|
||||
int lua_Set(lua_State* L) {
|
||||
int Args = lua_gettop(L);
|
||||
if (Args != 2) {
|
||||
SendError(L, Sec("set invalid argument count expected 2 got ") + std::to_string(Args));
|
||||
return 0;
|
||||
}
|
||||
if (!lua_isnumber(L, 1)) {
|
||||
SendError(L, Sec("set invalid argument [1] expected number"));
|
||||
return 0;
|
||||
}
|
||||
auto MaybeSrc = GetScript(L);
|
||||
std::string Name;
|
||||
if (!MaybeSrc.has_value()) {
|
||||
Name = Sec("_Console");
|
||||
} else {
|
||||
Name = MaybeSrc.value().get().GetPluginName();
|
||||
}
|
||||
int C = int(lua_tointeger(L, 1));
|
||||
switch (C) {
|
||||
case 0: //debug
|
||||
if (lua_isboolean(L, 2)) {
|
||||
Debug = lua_toboolean(L, 2);
|
||||
info(Name + Sec(" | Debug -> ") + (Debug ? "true" : "false"));
|
||||
} else
|
||||
SendError(L, Sec("set invalid argument [2] expected boolean for ID : 0"));
|
||||
break;
|
||||
case 1: //private
|
||||
if (lua_isboolean(L, 2)) {
|
||||
Private = lua_toboolean(L, 2);
|
||||
info(Name + Sec(" | Private -> ") + (Private ? "true" : "false"));
|
||||
} else
|
||||
SendError(L, Sec("set invalid argument [2] expected boolean for ID : 1"));
|
||||
break;
|
||||
case 2: //max cars
|
||||
if (lua_isnumber(L, 2)) {
|
||||
MaxCars = int(lua_tointeger(L, 2));
|
||||
info(Name + Sec(" | MaxCars -> ") + std::to_string(MaxCars));
|
||||
} else
|
||||
SendError(L, Sec("set invalid argument [2] expected number for ID : 2"));
|
||||
break;
|
||||
case 3: //max players
|
||||
if (lua_isnumber(L, 2)) {
|
||||
MaxPlayers = int(lua_tointeger(L, 2));
|
||||
info(Name + Sec(" | MaxPlayers -> ") + std::to_string(MaxPlayers));
|
||||
} else
|
||||
SendError(L, Sec("set invalid argument [2] expected number for ID : 3"));
|
||||
break;
|
||||
case 4: //Map
|
||||
if (lua_isstring(L, 2)) {
|
||||
MapName = lua_tostring(L, 2);
|
||||
info(Name + Sec(" | MapName -> ") + MapName);
|
||||
} else
|
||||
SendError(L, Sec("set invalid argument [2] expected string for ID : 4"));
|
||||
break;
|
||||
case 5: //Name
|
||||
if (lua_isstring(L, 2)) {
|
||||
ServerName = lua_tostring(L, 2);
|
||||
info(Name + Sec(" | ServerName -> ") + ServerName);
|
||||
} else
|
||||
SendError(L, Sec("set invalid argument [2] expected string for ID : 5"));
|
||||
break;
|
||||
case 6: //Desc
|
||||
if (lua_isstring(L, 2)) {
|
||||
ServerDesc = lua_tostring(L, 2);
|
||||
info(Name + Sec(" | ServerDesc -> ") + ServerDesc);
|
||||
} else
|
||||
SendError(L, Sec("set invalid argument [2] expected string for ID : 6"));
|
||||
break;
|
||||
default:
|
||||
warn(Sec("Invalid config ID : ") + std::to_string(C));
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
extern "C" {
|
||||
int lua_Print(lua_State* L) {
|
||||
int Arg = lua_gettop(L);
|
||||
for (int i = 1; i <= Arg; i++) {
|
||||
auto str = lua_tostring(L, i);
|
||||
if (str != nullptr) {
|
||||
ConsoleOut(str + std::string(Sec("\n")));
|
||||
} else {
|
||||
ConsoleOut(Sec("nil\n"));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Lua::Lua(const std::string& PluginName, const std::string& FileName, fs::file_time_type LastWrote, bool Console)
|
||||
: luaState(luaL_newstate()) {
|
||||
Assert(luaState);
|
||||
if (!PluginName.empty()) {
|
||||
SetPluginName(PluginName);
|
||||
}
|
||||
if (!FileName.empty()) {
|
||||
SetFileName(FileName);
|
||||
}
|
||||
SetLastWrite(LastWrote);
|
||||
_Console = Console;
|
||||
}
|
||||
|
||||
Lua::Lua(bool Console)
|
||||
: luaState(luaL_newstate()) {
|
||||
_Console = Console;
|
||||
}
|
||||
|
||||
void Lua::Execute(const std::string& Command) {
|
||||
if (ConsoleCheck(luaState, luaL_dostring(luaState, Command.c_str()))) {
|
||||
lua_settop(luaState, 0);
|
||||
}
|
||||
}
|
||||
void Lua::Reload() {
|
||||
if (CheckLua(luaState, luaL_dofile(luaState, _FileName.c_str()))) {
|
||||
CallFunction(this, Sec("onInit"), nullptr);
|
||||
}
|
||||
}
|
||||
std::string Lua::GetOrigin() {
|
||||
return fs::path(GetFileName()).filename().string();
|
||||
}
|
||||
|
||||
int CallFunction(Lua* lua, const std::string& FuncName, std::unique_ptr<LuaArg> Arg) {
|
||||
lua_State* luaState = lua->GetState();
|
||||
lua_getglobal(luaState, FuncName.c_str());
|
||||
if (lua_isfunction(luaState, -1)) {
|
||||
int Size = 0;
|
||||
if (Arg != nullptr) {
|
||||
Size = int(Arg->args.size());
|
||||
Arg->PushArgs(luaState);
|
||||
}
|
||||
std::string Origin = lua->GetOrigin();
|
||||
int R = lua_pcall(luaState, Size, 1, 0);
|
||||
if (CheckLua(luaState, R)) {
|
||||
if (lua_isnumber(luaState, -1)) {
|
||||
return int(lua_tointeger(luaState, -1));
|
||||
}
|
||||
}
|
||||
}
|
||||
ClearStack(luaState);
|
||||
return 0;
|
||||
}
|
||||
void Lua::SetPluginName(const std::string& Name) {
|
||||
_PluginName = Name;
|
||||
}
|
||||
void Lua::SetFileName(const std::string& Name) {
|
||||
_FileName = Name;
|
||||
}
|
||||
void Lua::Init() {
|
||||
Assert(luaState);
|
||||
luaL_openlibs(luaState);
|
||||
lua_register(luaState, "TriggerGlobalEvent", lua_TriggerEventG);
|
||||
lua_register(luaState, "TriggerLocalEvent", lua_TriggerEventL);
|
||||
lua_register(luaState, "TriggerClientEvent", lua_RemoteEvent);
|
||||
lua_register(luaState, "GetPlayerCount", lua_GetPlayerCount);
|
||||
lua_register(luaState, "isPlayerConnected", lua_isConnected);
|
||||
lua_register(luaState, "RegisterEvent", lua_RegisterEvent);
|
||||
lua_register(luaState, "GetPlayerName", lua_GetPlayerName);
|
||||
lua_register(luaState, "RemoveVehicle", lua_RemoveVehicle);
|
||||
lua_register(luaState, "GetPlayerDiscordID", lua_GetDID);
|
||||
lua_register(luaState, "GetPlayerVehicles", lua_GetCars);
|
||||
lua_register(luaState, "CreateThread", lua_CreateThread);
|
||||
lua_register(luaState, "SendChatMessage", lua_sendChat);
|
||||
lua_register(luaState, "GetPlayers", lua_GetAllPlayers);
|
||||
lua_register(luaState, "StopThread", lua_StopThread);
|
||||
lua_register(luaState, "DropPlayer", lua_dropPlayer);
|
||||
lua_register(luaState, "GetPlayerHWID", lua_HWID);
|
||||
lua_register(luaState, "exit", lua_ServerExit);
|
||||
lua_register(luaState, "Sleep", lua_Sleep);
|
||||
lua_register(luaState, "print", lua_Print);
|
||||
lua_register(luaState, "Set", lua_Set);
|
||||
if (!_Console)
|
||||
Reload();
|
||||
}
|
||||
|
||||
void Lua::RegisterEvent(const std::string& Event, const std::string& FunctionName) {
|
||||
_RegisteredEvents.insert(std::make_pair(Event, FunctionName));
|
||||
}
|
||||
void Lua::UnRegisterEvent(const std::string& Event) {
|
||||
for (const std::pair<std::string, std::string>& a : _RegisteredEvents) {
|
||||
if (a.first == Event) {
|
||||
_RegisteredEvents.erase(a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool Lua::IsRegistered(const std::string& Event) {
|
||||
for (const std::pair<std::string, std::string>& a : _RegisteredEvents) {
|
||||
if (a.first == Event)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
std::string Lua::GetRegistered(const std::string& Event) const {
|
||||
for (const std::pair<std::string, std::string>& a : _RegisteredEvents) {
|
||||
if (a.first == Event)
|
||||
return a.second;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
std::string Lua::GetFileName() const {
|
||||
return _FileName;
|
||||
}
|
||||
std::string Lua::GetPluginName() const {
|
||||
return _PluginName;
|
||||
}
|
||||
lua_State* Lua::GetState() {
|
||||
return luaState;
|
||||
}
|
||||
|
||||
const lua_State* Lua::GetState() const {
|
||||
return luaState;
|
||||
}
|
||||
|
||||
void Lua::SetLastWrite(fs::file_time_type time) {
|
||||
_LastWrote = time;
|
||||
}
|
||||
fs::file_time_type Lua::GetLastWrite() {
|
||||
return _LastWrote;
|
||||
}
|
||||
|
||||
Lua::~Lua() {
|
||||
info("closing lua state");
|
||||
lua_close(luaState);
|
||||
}
|
||||
318
src/Network/Auth.cpp
Normal file
318
src/Network/Auth.cpp
Normal file
@@ -0,0 +1,318 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/31/2020
|
||||
///
|
||||
#include "Curl/Http.h"
|
||||
#include "Logger.h"
|
||||
#include "Network.h"
|
||||
#include "Security/Enc.h"
|
||||
#include "Settings.h"
|
||||
#include "UnixCompat.h"
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
bool Send(SOCKET TCPSock, std::string Data) {
|
||||
#ifdef WIN32
|
||||
int BytesSent;
|
||||
int len = static_cast<int>(Data.size());
|
||||
#else
|
||||
int64_t BytesSent;
|
||||
size_t len = Data.size();
|
||||
#endif // WIN32
|
||||
BytesSent = send(TCPSock, Data.c_str(), len, 0);
|
||||
Data.clear();
|
||||
if (BytesSent <= 0) {
|
||||
#ifndef WIN32
|
||||
error(__func__ + std::string(" ") + strerror(errno));
|
||||
#else
|
||||
error(__func__ + std::string(" ") + std::to_string(WSAGetLastError()));
|
||||
#endif // WIN32
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
std::string Rcv(SOCKET TCPSock) {
|
||||
uint32_t RealSize;
|
||||
#ifdef WIN32
|
||||
int64_t BytesRcv = recv(TCPSock, reinterpret_cast<char*>(&RealSize), sizeof(RealSize), 0);
|
||||
#else
|
||||
int64_t BytesRcv = recv(TCPSock, reinterpret_cast<void*>(&RealSize), sizeof(RealSize), 0);
|
||||
#endif
|
||||
if (BytesRcv != sizeof(RealSize)) {
|
||||
error(std::string(Sec("invalid packet: expected 4, got ")) + std::to_string(BytesRcv));
|
||||
return "";
|
||||
}
|
||||
// RealSize is big-endian, so we convert it to host endianness
|
||||
RealSize = ntohl(RealSize);
|
||||
debug(std::string("got ") + std::to_string(RealSize) + " as size");
|
||||
if (RealSize > 7000) {
|
||||
error(Sec("Larger than allowed TCP packet received"));
|
||||
return "";
|
||||
}
|
||||
char buf[7000];
|
||||
std::fill_n(buf, 7000, 0);
|
||||
BytesRcv = recv(TCPSock, buf, RealSize, 0);
|
||||
if (BytesRcv != RealSize) {
|
||||
debug("expected " + std::to_string(RealSize) + " bytes, got " + std::to_string(BytesRcv) + " instead");
|
||||
}
|
||||
if (BytesRcv <= 0)
|
||||
return "";
|
||||
return std::string(buf);
|
||||
}
|
||||
std::string GetRole(const std::string& DID) {
|
||||
if (!DID.empty()) {
|
||||
std::string a = HttpRequest(Sec("https://beammp.com/entitlement?did=") + DID, 443);
|
||||
std::string b = HttpRequest(Sec("https://backup1.beammp.com/entitlement?did=") + DID, 443);
|
||||
if (!a.empty() || !b.empty()) {
|
||||
if (a != b)
|
||||
a = b;
|
||||
auto pos = a.find('"');
|
||||
if (pos != std::string::npos) {
|
||||
return a.substr(pos + 1, a.find('"', pos + 1) - 2);
|
||||
} else if (a == "[]")
|
||||
return Sec("Member");
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
void Check(SOCKET TCPSock, std::shared_ptr<std::atomic_bool> ok) {
|
||||
DebugPrintTID();
|
||||
size_t accum = 0;
|
||||
while (!*ok) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
accum += 100;
|
||||
if (accum >= 5000) {
|
||||
error(Sec("Identification timed out (Check accum)"));
|
||||
CloseSocketProper(TCPSock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
int Max() {
|
||||
int M = MaxPlayers;
|
||||
for (auto& c : CI->Clients) {
|
||||
if (c != nullptr) {
|
||||
if (c->GetRole() == Sec("MDEV"))
|
||||
M++;
|
||||
}
|
||||
}
|
||||
return M;
|
||||
}
|
||||
void CreateClient(SOCKET TCPSock, const std::string& Name, const std::string& DID, const std::string& Role) {
|
||||
auto* c = new Client;
|
||||
c->SetTCPSock(TCPSock);
|
||||
c->SetName(Name);
|
||||
c->SetRole(Role);
|
||||
c->SetDID(DID);
|
||||
Client& Client = *c;
|
||||
CI->AddClient(std::move(c));
|
||||
InitClient(&Client);
|
||||
}
|
||||
std::pair<int, int> Parse(const std::string& msg) {
|
||||
std::stringstream ss(msg);
|
||||
std::string t;
|
||||
std::pair<int, int> a = { 0, 0 }; //N then E
|
||||
while (std::getline(ss, t, 'g')) {
|
||||
if (t.find_first_not_of(Sec("0123456789abcdef")) != std::string::npos)
|
||||
return a;
|
||||
if (a.first == 0) {
|
||||
a.first = std::stoi(t, nullptr, 16);
|
||||
} else if (a.second == 0) {
|
||||
a.second = std::stoi(t, nullptr, 16);
|
||||
} else
|
||||
return a;
|
||||
}
|
||||
return { 0, 0 };
|
||||
}
|
||||
std::string GenerateM(RSA* key) {
|
||||
std::stringstream stream;
|
||||
stream << std::hex << key->n << "g" << key->e << "g" << RSA_E(Sec("IDC"), key);
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
void Identification(SOCKET TCPSock, RSA* Skey) {
|
||||
DebugPrintTID();
|
||||
Assert(Skey);
|
||||
std::shared_ptr<std::atomic_bool> ok = std::make_shared<std::atomic_bool>(false);
|
||||
std::thread Timeout(Check, TCPSock, ok);
|
||||
Timeout.detach();
|
||||
std::string Name, DID, Role;
|
||||
if (!Send(TCPSock, GenerateM(Skey))) {
|
||||
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
|
||||
CloseSocketProper(TCPSock);
|
||||
return;
|
||||
}
|
||||
std::string msg = Rcv(TCPSock);
|
||||
auto Keys = Parse(msg);
|
||||
if (!Send(TCPSock, RSA_E("HC", Keys.second, Keys.first))) {
|
||||
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
|
||||
CloseSocketProper(TCPSock);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string Res = Rcv(TCPSock);
|
||||
std::string Ver = Rcv(TCPSock);
|
||||
*ok = true;
|
||||
Ver = RSA_D(Ver, Skey);
|
||||
if (Ver.size() > 3 && Ver.substr(0, 2) == Sec("VC")) {
|
||||
Ver = Ver.substr(2);
|
||||
if (Ver.length() > 4 || Ver != GetCVer()) {
|
||||
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
|
||||
CloseSocketProper(TCPSock);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
|
||||
CloseSocketProper(TCPSock);
|
||||
return;
|
||||
}
|
||||
Res = RSA_D(Res, Skey);
|
||||
if (Res.size() < 3 || Res.substr(0, 2) != Sec("NR")) {
|
||||
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
|
||||
CloseSocketProper(TCPSock);
|
||||
return;
|
||||
}
|
||||
if (Res.find(':') == std::string::npos) {
|
||||
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
|
||||
CloseSocketProper(TCPSock);
|
||||
return;
|
||||
}
|
||||
Name = Res.substr(2, Res.find(':') - 2);
|
||||
DID = Res.substr(Res.find(':') + 1);
|
||||
Role = GetRole(DID);
|
||||
if (Role.empty() || Role.find(Sec("Error")) != std::string::npos) {
|
||||
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
|
||||
CloseSocketProper(TCPSock);
|
||||
return;
|
||||
}
|
||||
// DebugPrintTIDInternal(std::string("Client(") + Name + ")");
|
||||
debug(Sec("Name -> ") + Name + Sec(", Role -> ") + Role + Sec(", ID -> ") + DID);
|
||||
for (auto& c : CI->Clients) {
|
||||
if (c != nullptr) {
|
||||
if (c->GetDID() == DID) {
|
||||
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
|
||||
CloseSocketProper(c->GetTCPSock());
|
||||
c->SetStatus(-2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Role == Sec("MDEV") || CI->Size() < Max()) {
|
||||
debug("Identification success");
|
||||
CreateClient(TCPSock, Name, DID, Role);
|
||||
} else {
|
||||
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
|
||||
CloseSocketProper(TCPSock);
|
||||
}
|
||||
}
|
||||
void Identify(SOCKET TCPSock) {
|
||||
RSA* Skey = GenKey();
|
||||
// this disgusting ifdef stuff is needed because for some
|
||||
// reason MSVC defines __try and __except and libg++ defines
|
||||
// __try and __catch so its all a big mess if we leave this in or undefine
|
||||
// the macros
|
||||
/*#ifdef WIN32
|
||||
__try{
|
||||
#endif // WIN32*/
|
||||
Identification(TCPSock, Skey);
|
||||
/*#ifdef WIN32
|
||||
}__except(1){
|
||||
if(TCPSock != -1){
|
||||
error("died on " + std::string(__func__) + ":" + std::to_string(__LINE__));
|
||||
CloseSocketProper(TCPSock);
|
||||
}
|
||||
}
|
||||
#endif // WIN32*/
|
||||
|
||||
delete Skey;
|
||||
}
|
||||
|
||||
void TCPServerMain() {
|
||||
DebugPrintTID();
|
||||
#ifdef WIN32
|
||||
WSADATA wsaData;
|
||||
if (WSAStartup(514, &wsaData)) {
|
||||
error(Sec("Can't start Winsock!"));
|
||||
return;
|
||||
}
|
||||
SOCKET client, Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
sockaddr_in addr {};
|
||||
addr.sin_addr.S_un.S_addr = ADDR_ANY;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(Port);
|
||||
if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
|
||||
error(Sec("Can't bind socket! ") + std::to_string(WSAGetLastError()));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
_Exit(-1);
|
||||
}
|
||||
if (Listener == -1) {
|
||||
error(Sec("Invalid listening socket"));
|
||||
return;
|
||||
}
|
||||
if (listen(Listener, SOMAXCONN)) {
|
||||
error(Sec("listener failed ") + std::to_string(GetLastError()));
|
||||
return;
|
||||
}
|
||||
info(Sec("Vehicle event network online"));
|
||||
do {
|
||||
try {
|
||||
client = accept(Listener, nullptr, nullptr);
|
||||
if (client == -1) {
|
||||
warn(Sec("Got an invalid client socket on connect! Skipping..."));
|
||||
continue;
|
||||
}
|
||||
std::thread ID(Identify, client);
|
||||
ID.detach();
|
||||
} catch (const std::exception& e) {
|
||||
error(Sec("fatal: ") + std::string(e.what()));
|
||||
}
|
||||
} while (client);
|
||||
|
||||
CloseSocketProper(client);
|
||||
WSACleanup();
|
||||
#else // unix
|
||||
// wondering why we need slightly different implementations of this?
|
||||
// ask ms.
|
||||
SOCKET client = -1, Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
int optval = 1;
|
||||
setsockopt(Listener, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
|
||||
// TODO: check optval or return value idk
|
||||
sockaddr_in addr {};
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(uint16_t(Port));
|
||||
if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) != 0) {
|
||||
error(Sec("Can't bind socket! ") + std::string(strerror(errno)));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
_Exit(-1);
|
||||
}
|
||||
if (Listener == -1) {
|
||||
error(Sec("Invalid listening socket"));
|
||||
return;
|
||||
}
|
||||
if (listen(Listener, SOMAXCONN)) {
|
||||
error(Sec("listener failed ") + std::string(strerror(errno)));
|
||||
return;
|
||||
}
|
||||
info(Sec("Vehicle event network online"));
|
||||
do {
|
||||
try {
|
||||
client = accept(Listener, nullptr, nullptr);
|
||||
if (client == -1) {
|
||||
warn(Sec("Got an invalid client socket on connect! Skipping..."));
|
||||
continue;
|
||||
}
|
||||
std::thread ID(Identify, client);
|
||||
ID.detach();
|
||||
} catch (const std::exception& e) {
|
||||
error(Sec("fatal: ") + std::string(e.what()));
|
||||
}
|
||||
} while (client);
|
||||
|
||||
debug("all ok, arrived at " + std::string(__func__) + ":" + std::to_string(__LINE__));
|
||||
CloseSocketProper(client);
|
||||
#endif // WIN32
|
||||
}
|
||||
105
src/Network/Client.cpp
Normal file
105
src/Network/Client.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 5/8/2020
|
||||
///
|
||||
#include "Client.hpp"
|
||||
|
||||
std::string Client::GetName() {
|
||||
return Name;
|
||||
}
|
||||
void Client::SetName(const std::string& name) {
|
||||
Name = name;
|
||||
}
|
||||
void Client::SetDID(const std::string& did) {
|
||||
DID = did;
|
||||
}
|
||||
std::string Client::GetDID() {
|
||||
return DID;
|
||||
}
|
||||
void Client::SetRole(const std::string& role) {
|
||||
Role = role;
|
||||
}
|
||||
std::string Client::GetRole() {
|
||||
return Role;
|
||||
}
|
||||
int Client::GetID() {
|
||||
return ID;
|
||||
}
|
||||
void Client::SetID(int id) {
|
||||
ID = id;
|
||||
}
|
||||
void Client::SetStatus(int state) {
|
||||
Status = state;
|
||||
}
|
||||
int Client::GetStatus() {
|
||||
return Status;
|
||||
}
|
||||
void Client::SetUDPAddr(sockaddr_in Addr) {
|
||||
UDPADDR = Addr;
|
||||
}
|
||||
sockaddr_in Client::GetUDPAddr() {
|
||||
return UDPADDR;
|
||||
}
|
||||
void Client::SetTCPSock(SOCKET CSock) {
|
||||
TCPSOCK = CSock;
|
||||
}
|
||||
SOCKET Client::GetTCPSock() {
|
||||
return TCPSOCK;
|
||||
}
|
||||
void Client::DeleteCar(int ident) {
|
||||
for (auto& v : VehicleData) {
|
||||
if (v != nullptr && v->ID == ident) {
|
||||
VehicleData.erase(v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void Client::ClearCars() {
|
||||
VehicleData.clear();
|
||||
}
|
||||
int Client::GetOpenCarID() {
|
||||
int OpenID = 0;
|
||||
bool found;
|
||||
do {
|
||||
found = true;
|
||||
for (auto& v : VehicleData) {
|
||||
if (v != nullptr && v->ID == OpenID) {
|
||||
OpenID++;
|
||||
found = false;
|
||||
}
|
||||
}
|
||||
} while (!found);
|
||||
return OpenID;
|
||||
}
|
||||
void Client::AddNewCar(int ident, const std::string& Data) {
|
||||
VehicleData.insert(std::unique_ptr<VData>(new VData { ident, Data }));
|
||||
}
|
||||
|
||||
std::set<std::unique_ptr<VData>>& Client::GetAllCars() {
|
||||
return VehicleData;
|
||||
}
|
||||
|
||||
const std::set<std::unique_ptr<VData>>& Client::GetAllCars() const {
|
||||
return VehicleData;
|
||||
}
|
||||
|
||||
std::string Client::GetCarData(int ident) {
|
||||
for (auto& v : VehicleData) {
|
||||
if (v != nullptr && v->ID == ident) {
|
||||
return v->Data;
|
||||
}
|
||||
}
|
||||
DeleteCar(ident);
|
||||
return "";
|
||||
}
|
||||
void Client::SetCarData(int ident, const std::string& Data) {
|
||||
for (auto& v : VehicleData) {
|
||||
if (v != nullptr && v->ID == ident) {
|
||||
v->Data = Data;
|
||||
return;
|
||||
}
|
||||
}
|
||||
DeleteCar(ident);
|
||||
}
|
||||
int Client::GetCarCount() {
|
||||
return int(VehicleData.size());
|
||||
}
|
||||
248
src/Network/GParser.cpp
Normal file
248
src/Network/GParser.cpp
Normal file
@@ -0,0 +1,248 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 8/1/2020
|
||||
///
|
||||
#include "Client.hpp"
|
||||
#include "Logger.h"
|
||||
#include "Lua/LuaSystem.hpp"
|
||||
#include "Network.h"
|
||||
#include "Security/Enc.h"
|
||||
#include "Settings.h"
|
||||
#include "UnixCompat.h"
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
int FC(const std::string& s, const std::string& p, int n) {
|
||||
auto i = s.find(p);
|
||||
int j;
|
||||
for (j = 1; j < n && i != std::string::npos; ++j) {
|
||||
i = s.find(p, i + 1);
|
||||
}
|
||||
if (j == n)
|
||||
return int(i);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
void Apply(Client* c, int VID, const std::string& pckt) {
|
||||
Assert(c);
|
||||
std::string Packet = pckt;
|
||||
std::string VD = c->GetCarData(VID);
|
||||
Packet = Packet.substr(FC(Packet, ",", 2) + 1);
|
||||
Packet = VD.substr(0, FC(VD, ",", 2) + 1) + Packet.substr(0, Packet.find_last_of('"') + 1) + VD.substr(FC(VD, ",\"", 7));
|
||||
c->SetCarData(VID, Packet);
|
||||
}
|
||||
|
||||
void VehicleParser(Client* c, const std::string& Pckt) {
|
||||
Assert(c);
|
||||
if (c == nullptr || Pckt.length() < 4)
|
||||
return;
|
||||
std::string Packet = Pckt;
|
||||
char Code = Packet.at(1);
|
||||
int PID = -1;
|
||||
int VID = -1;
|
||||
std::string Data = Packet.substr(3), pid, vid;
|
||||
switch (Code) { //Spawned Destroyed Switched/Moved NotFound Reset
|
||||
case 's':
|
||||
#ifdef DEBUG
|
||||
debug(std::string(Sec("got 'Os' packet: '")) + Packet + Sec("' (") + std::to_string(Packet.size()) + Sec(")"));
|
||||
#endif
|
||||
if (Data.at(0) == '0') {
|
||||
int CarID = c->GetOpenCarID();
|
||||
debug(c->GetName() + Sec(" created a car with ID ") + std::to_string(CarID));
|
||||
Packet = "Os:" + c->GetRole() + ":" + c->GetName() + ":" + std::to_string(c->GetID()) + "-" + std::to_string(CarID) + Packet.substr(4);
|
||||
if (c->GetCarCount() >= MaxCars || TriggerLuaEvent(Sec("onVehicleSpawn"), false, nullptr, std::make_unique<LuaArg>(LuaArg { { c->GetID(), CarID, Packet.substr(3) } }), true)) {
|
||||
Respond(c, Packet, true);
|
||||
std::string Destroy = "Od:" + std::to_string(c->GetID()) + "-" + std::to_string(CarID);
|
||||
Respond(c, Destroy, true);
|
||||
debug(c->GetName() + Sec(" (force : car limit/lua) removed ID ") + std::to_string(CarID));
|
||||
} else {
|
||||
c->AddNewCar(CarID, Packet);
|
||||
SendToAll(nullptr, Packet, true, true);
|
||||
}
|
||||
}
|
||||
return;
|
||||
case 'c':
|
||||
#ifdef DEBUG
|
||||
debug(std::string(Sec("got 'Oc' packet: '")) + Packet + Sec("' (") + std::to_string(Packet.size()) + Sec(")"));
|
||||
#endif
|
||||
pid = Data.substr(0, Data.find('-'));
|
||||
vid = Data.substr(Data.find('-') + 1, Data.find(':', 1) - Data.find('-') - 1);
|
||||
if (pid.find_first_not_of("0123456789") == std::string::npos && vid.find_first_not_of("0123456789") == std::string::npos) {
|
||||
PID = stoi(pid);
|
||||
VID = stoi(vid);
|
||||
}
|
||||
if (PID != -1 && VID != -1 && PID == c->GetID()) {
|
||||
if (!TriggerLuaEvent(Sec("onVehicleEdited"), false, nullptr,
|
||||
std::unique_ptr<LuaArg>(new LuaArg { { c->GetID(), VID, Packet.substr(3) } }),
|
||||
true)) {
|
||||
SendToAll(c, Packet, false, true);
|
||||
Apply(c, VID, Packet);
|
||||
} else {
|
||||
std::string Destroy = "Od:" + std::to_string(c->GetID()) + "-" + std::to_string(VID);
|
||||
Respond(c, Destroy, true);
|
||||
c->DeleteCar(VID);
|
||||
}
|
||||
}
|
||||
return;
|
||||
case 'd':
|
||||
#ifdef DEBUG
|
||||
debug(std::string(Sec("got 'Od' packet: '")) + Packet + Sec("' (") + std::to_string(Packet.size()) + Sec(")"));
|
||||
#endif
|
||||
pid = Data.substr(0, Data.find('-'));
|
||||
vid = Data.substr(Data.find('-') + 1);
|
||||
if (pid.find_first_not_of("0123456789") == std::string::npos && vid.find_first_not_of("0123456789") == std::string::npos) {
|
||||
PID = stoi(pid);
|
||||
VID = stoi(vid);
|
||||
}
|
||||
if (PID != -1 && VID != -1 && PID == c->GetID()) {
|
||||
SendToAll(nullptr, Packet, true, true);
|
||||
TriggerLuaEvent(Sec("onVehicleDeleted"), false, nullptr,
|
||||
std::unique_ptr<LuaArg>(new LuaArg { { c->GetID(), VID } }), false);
|
||||
c->DeleteCar(VID);
|
||||
debug(c->GetName() + Sec(" deleted car with ID ") + std::to_string(VID));
|
||||
}
|
||||
return;
|
||||
case 'r':
|
||||
#ifdef DEBUG
|
||||
debug(std::string(Sec("got 'Or' packet: '")) + Packet + Sec("' (") + std::to_string(Packet.size()) + Sec(")"));
|
||||
#endif
|
||||
SendToAll(c, Packet, false, true);
|
||||
return;
|
||||
default:
|
||||
#ifdef DEBUG
|
||||
warn(std::string(Sec("possibly not implemented: '") + Packet + Sec("' (") + std::to_string(Packet.size()) + Sec(")")));
|
||||
#endif // DEBUG
|
||||
return;
|
||||
}
|
||||
}
|
||||
void SyncClient(Client* c) {
|
||||
Assert(c);
|
||||
if (c->isSynced)
|
||||
return;
|
||||
c->isSynced = true;
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
Respond(c, Sec("Sn") + c->GetName(), true);
|
||||
SendToAll(c, Sec("JWelcome ") + c->GetName() + "!", false, true);
|
||||
TriggerLuaEvent(Sec("onPlayerJoin"), false, nullptr, std::unique_ptr<LuaArg>(new LuaArg { { c->GetID() } }), false);
|
||||
for (auto& client : CI->Clients) {
|
||||
if (client != nullptr) {
|
||||
if (client.get() != c) {
|
||||
for (auto& v : client->GetAllCars()) {
|
||||
if (v != nullptr) {
|
||||
if(c->GetStatus() < 0)return;
|
||||
Respond(c, v->Data, true);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
info(c->GetName() + Sec(" is now synced!"));
|
||||
}
|
||||
void ParseVeh(Client* c, const std::string& Packet) {
|
||||
Assert(c);
|
||||
#ifdef WIN32
|
||||
__try {
|
||||
VehicleParser(c, Packet);
|
||||
} __except (Handle(GetExceptionInformation(), Sec("Vehicle Handler"))) { }
|
||||
#else // unix
|
||||
VehicleParser(c, Packet);
|
||||
#endif // WIN32
|
||||
}
|
||||
|
||||
void HandleEvent(Client* c, const std::string& Data) {
|
||||
Assert(c);
|
||||
std::stringstream ss(Data);
|
||||
std::string t, Name;
|
||||
int a = 0;
|
||||
while (std::getline(ss, t, ':')) {
|
||||
switch (a) {
|
||||
case 1:
|
||||
Name = t;
|
||||
break;
|
||||
case 2:
|
||||
TriggerLuaEvent(Name, false, nullptr, std::unique_ptr<LuaArg>(new LuaArg { { c->GetID(), t } }), false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (a == 2)
|
||||
break;
|
||||
a++;
|
||||
}
|
||||
}
|
||||
|
||||
void GlobalParser(Client* c, const std::string& Pack) {
|
||||
Assert(c);
|
||||
if (Pack.empty() || c == nullptr)
|
||||
return;
|
||||
std::string Packet = Pack.substr(0, strlen(Pack.c_str()));
|
||||
std::string pct;
|
||||
char Code = Packet.at(0);
|
||||
|
||||
//V to Z
|
||||
if (Code <= 90 && Code >= 86) {
|
||||
PPS++;
|
||||
SendToAll(c, Packet, false, false);
|
||||
return;
|
||||
}
|
||||
switch (Code) {
|
||||
case 'P': // initial connection
|
||||
#ifdef DEBUG
|
||||
debug(std::string(Sec("got 'P' packet: '")) + Pack + Sec("' (") + std::to_string(Packet.size()) + Sec(")"));
|
||||
#endif
|
||||
Respond(c, Sec("P") + std::to_string(c->GetID()), true);
|
||||
SyncClient(c);
|
||||
return;
|
||||
case 'p':
|
||||
Respond(c, Sec("p"), false);
|
||||
UpdatePlayers();
|
||||
return;
|
||||
case 'O':
|
||||
if (Packet.length() > 1000) {
|
||||
debug(Sec("Received data from: ") + c->GetName() + Sec(" Size: ") + std::to_string(Packet.length()));
|
||||
}
|
||||
ParseVeh(c, Packet);
|
||||
return;
|
||||
case 'J':
|
||||
#ifdef DEBUG
|
||||
debug(std::string(Sec("got 'J' packet: '")) + Pack + Sec("' (") + std::to_string(Packet.size()) + Sec(")"));
|
||||
#endif
|
||||
SendToAll(c, Packet, false, true);
|
||||
return;
|
||||
case 'C':
|
||||
#ifdef DEBUG
|
||||
debug(std::string(Sec("got 'C' packet: '")) + Pack + Sec("' (") + std::to_string(Packet.size()) + Sec(")"));
|
||||
#endif
|
||||
if (Packet.length() < 4 || Packet.find(':', 3) == std::string::npos)
|
||||
break;
|
||||
if (TriggerLuaEvent(Sec("onChatMessage"), false, nullptr,
|
||||
std::unique_ptr<LuaArg>(new LuaArg {
|
||||
{ c->GetID(), c->GetName(), Packet.substr(Packet.find(':', 3) + 1) } }),
|
||||
true))
|
||||
break;
|
||||
SendToAll(nullptr, Packet, true, true);
|
||||
return;
|
||||
case 'E':
|
||||
#ifdef DEBUG
|
||||
debug(std::string(Sec("got 'E' packet: '")) + Pack + Sec("' (") + std::to_string(Packet.size()) + Sec(")"));
|
||||
#endif
|
||||
HandleEvent(c, Packet);
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void GParser(Client* c, const std::string& Packet) {
|
||||
Assert(c);
|
||||
if (Packet.find("Zp") != std::string::npos && Packet.size() > 500) {
|
||||
abort();
|
||||
}
|
||||
#ifdef WIN32
|
||||
__try {
|
||||
GlobalParser(c, Packet);
|
||||
} __except (Handle(GetExceptionInformation(), Sec("Global Handler"))) { }
|
||||
#else
|
||||
GlobalParser(c, Packet);
|
||||
#endif // WIN32
|
||||
}
|
||||
52
src/Network/Http.cpp
Normal file
52
src/Network/Http.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 4/9/2020
|
||||
///
|
||||
|
||||
#include "CustomAssert.h"
|
||||
#include <curl/curl.h>
|
||||
#include <iostream>
|
||||
static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
|
||||
((std::string*)userp)->append((char*)contents, size * nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
std::string HttpRequest(const std::string& IP, int port) {
|
||||
CURL* curl;
|
||||
CURLcode res;
|
||||
std::string readBuffer;
|
||||
curl = curl_easy_init();
|
||||
Assert(curl);
|
||||
if (curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, IP.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_PORT, port);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
|
||||
res = curl_easy_perform(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
if (res != CURLE_OK)
|
||||
return "-1";
|
||||
}
|
||||
return readBuffer;
|
||||
}
|
||||
|
||||
std::string PostHTTP(const std::string& IP, const std::string& Fields) {
|
||||
CURL* curl;
|
||||
CURLcode res;
|
||||
std::string readBuffer;
|
||||
curl = curl_easy_init();
|
||||
Assert(curl);
|
||||
if (curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, IP.c_str());
|
||||
/*curl_easy_setopt(curl, CURLOPT_URL, "https://95.216.35.232/heartbeatv2");
|
||||
curl_easy_setopt(curl, CURLOPT_PORT, 3600);*/
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, Fields.size());
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, Fields.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
|
||||
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
|
||||
res = curl_easy_perform(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
if (res != CURLE_OK)
|
||||
return "-1";
|
||||
}
|
||||
return readBuffer;
|
||||
}
|
||||
101
src/Network/InitClient.cpp
Normal file
101
src/Network/InitClient.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 8/1/2020
|
||||
///
|
||||
#include "Client.hpp"
|
||||
#include "Logger.h"
|
||||
#include "Lua/LuaSystem.hpp"
|
||||
#include "Network.h"
|
||||
#include "Security/Enc.h"
|
||||
#include "Settings.h"
|
||||
int OpenID() {
|
||||
int ID = 0;
|
||||
bool found;
|
||||
do {
|
||||
found = true;
|
||||
for (auto& c : CI->Clients) {
|
||||
if (c != nullptr) {
|
||||
if (c->GetID() == ID) {
|
||||
found = false;
|
||||
ID++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (!found);
|
||||
return ID;
|
||||
}
|
||||
void Respond(Client* c, const std::string& MSG, bool Rel) {
|
||||
Assert(c);
|
||||
char C = MSG.at(0);
|
||||
if (Rel || C == 'W' || C == 'Y' || C == 'V' || C == 'E') {
|
||||
if (C == 'O' || C == 'T' || MSG.length() > 1000) {
|
||||
SendLarge(c, MSG);
|
||||
} else {
|
||||
TCPSend(c, MSG);
|
||||
}
|
||||
} else {
|
||||
UDPSend(c, MSG);
|
||||
}
|
||||
}
|
||||
void SendToAll(Client* c, const std::string& Data, bool Self, bool Rel) {
|
||||
if (!Self)
|
||||
Assert(c);
|
||||
char C = Data.at(0);
|
||||
for (auto& client : CI->Clients) {
|
||||
if (client != nullptr) {
|
||||
if (Self || client.get() != c) {
|
||||
if (client->isSynced) {
|
||||
if (Rel || C == 'W' || C == 'Y' || C == 'V' || C == 'E') {
|
||||
if (C == 'O' || C == 'T' || Data.length() > 1000)
|
||||
SendLarge(client.get(), Data);
|
||||
else
|
||||
TCPSend(client.get(), Data);
|
||||
} else
|
||||
UDPSend(client.get(), Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void UpdatePlayers() {
|
||||
std::string Packet = Sec("Ss") + std::to_string(CI->Size()) + "/" + std::to_string(MaxPlayers) + ":";
|
||||
for (auto& c : CI->Clients) {
|
||||
if (c != nullptr)
|
||||
Packet += c->GetName() + ",";
|
||||
}
|
||||
Packet = Packet.substr(0, Packet.length() - 1);
|
||||
SendToAll(nullptr, Packet, true, true);
|
||||
}
|
||||
void OnDisconnect(Client* c, bool kicked) {
|
||||
|
||||
Assert(c);
|
||||
info(c->GetName() + Sec(" Connection Terminated"));
|
||||
if (c == nullptr)
|
||||
return;
|
||||
std::string Packet;
|
||||
for (auto& v : c->GetAllCars()) {
|
||||
if (v != nullptr) {
|
||||
Packet = "Od:" + std::to_string(c->GetID()) + "-" + std::to_string(v->ID);
|
||||
SendToAll(c, Packet, false, true);
|
||||
}
|
||||
}
|
||||
if (kicked)
|
||||
Packet = Sec("L") + c->GetName() + Sec(" was kicked!");
|
||||
Packet = Sec("L") + c->GetName() + Sec(" Left the server!");
|
||||
SendToAll(c, Packet, false, true);
|
||||
Packet.clear();
|
||||
TriggerLuaEvent(Sec("onPlayerDisconnect"), false, nullptr, std::unique_ptr<LuaArg>(new LuaArg { { c->GetID() } }), false);
|
||||
CI->RemoveClient(c); ///Removes the Client from existence
|
||||
}
|
||||
void OnConnect(Client* c) {
|
||||
Assert(c);
|
||||
info(Sec("Client connected"));
|
||||
c->SetID(OpenID());
|
||||
info(Sec("Assigned ID ") + std::to_string(c->GetID()) + Sec(" to ") + c->GetName());
|
||||
TriggerLuaEvent(Sec("onPlayerConnecting"), false, nullptr, std::unique_ptr<LuaArg>(new LuaArg { { c->GetID() } }), false);
|
||||
SyncResources(c);
|
||||
if (c->GetStatus() < 0)
|
||||
return;
|
||||
Respond(c, "M" + MapName, true); //Send the Map on connect
|
||||
info(c->GetName() + Sec(" : Connected"));
|
||||
TriggerLuaEvent(Sec("onPlayerJoining"), false, nullptr, std::unique_ptr<LuaArg>(new LuaArg { { c->GetID() } }), false);
|
||||
}
|
||||
9
src/Network/NetMain.cpp
Normal file
9
src/Network/NetMain.cpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#include "Network.h"
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
std::unique_ptr<ClientInterface> CI;
|
||||
void NetMain() {
|
||||
std::thread TCP(TCPServerMain);
|
||||
TCP.detach();
|
||||
UDPServerMain();
|
||||
}
|
||||
44
src/Network/StatMonitor.cpp
Normal file
44
src/Network/StatMonitor.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 6/18/2020
|
||||
///
|
||||
#include "Client.hpp"
|
||||
#include "Security/Enc.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
std::string StatReport;
|
||||
int PPS = 0;
|
||||
void Monitor() {
|
||||
int R, C = 0, V = 0;
|
||||
if (CI->Clients.empty()) {
|
||||
StatReport = "-";
|
||||
return;
|
||||
}
|
||||
for (auto& c : CI->Clients) {
|
||||
if (c != nullptr && c->GetCarCount() > 0) {
|
||||
C++;
|
||||
V += c->GetCarCount();
|
||||
}
|
||||
}
|
||||
if (C == 0 || PPS == 0) {
|
||||
StatReport = "-";
|
||||
} else {
|
||||
R = (PPS / C) / V;
|
||||
StatReport = std::to_string(R);
|
||||
}
|
||||
PPS = 0;
|
||||
}
|
||||
|
||||
[[noreturn]] void Stat() {
|
||||
DebugPrintTID();
|
||||
while (true) {
|
||||
Monitor();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
void StatInit() {
|
||||
StatReport = "-";
|
||||
std::thread Init(Stat);
|
||||
Init.detach();
|
||||
}
|
||||
139
src/Network/Sync.cpp
Normal file
139
src/Network/Sync.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 8/1/2020
|
||||
///
|
||||
#include "Client.hpp"
|
||||
#include "Logger.h"
|
||||
#include "Security/Enc.h"
|
||||
#include "Settings.h"
|
||||
#include "UnixCompat.h"
|
||||
#include <fstream>
|
||||
|
||||
#ifdef __linux
|
||||
// we need this for `struct stat`
|
||||
#include <sys/stat.h>
|
||||
#endif // __linux
|
||||
|
||||
void STCPSend(Client* c, std::string Data) {
|
||||
Assert(c);
|
||||
if (c == nullptr)
|
||||
return;
|
||||
#ifdef WIN32
|
||||
int BytesSent;
|
||||
int len = static_cast<int>(Data.size());
|
||||
#else
|
||||
int64_t BytesSent;
|
||||
size_t len = Data.size();
|
||||
#endif // WIN32
|
||||
BytesSent = send(c->GetTCPSock(), Data.c_str(), len, 0);
|
||||
Data.clear();
|
||||
if (BytesSent == 0) {
|
||||
if (c->GetStatus() > -1)
|
||||
c->SetStatus(-1);
|
||||
} else if (BytesSent < 0) {
|
||||
if (c->GetStatus() > -1)
|
||||
c->SetStatus(-1);
|
||||
info(Sec("Closing socket, BytesSent < 0"));
|
||||
CloseSocketProper(c->GetTCPSock());
|
||||
}
|
||||
}
|
||||
void SendFile(Client* c, const std::string& Name) {
|
||||
Assert(c);
|
||||
info(c->GetName() + Sec(" requesting : ") + Name.substr(Name.find_last_of('/')));
|
||||
struct stat Info { };
|
||||
if (stat(Name.c_str(), &Info) != 0) {
|
||||
STCPSend(c, Sec("Cannot Open"));
|
||||
return;
|
||||
}
|
||||
std::ifstream f(Name.c_str(), std::ios::binary);
|
||||
f.seekg(0, std::ios_base::end);
|
||||
std::streampos fileSize = f.tellg();
|
||||
size_t Size = size_t(fileSize);
|
||||
size_t Sent = 0;
|
||||
size_t Diff;
|
||||
int64_t Split = 64000;
|
||||
while (c->GetStatus() > -1 && Sent < Size) {
|
||||
Diff = Size - Sent;
|
||||
if (Diff > size_t(Split)) {
|
||||
std::string Data(size_t(Split), 0);
|
||||
f.seekg(int64_t(Sent), std::ios_base::beg);
|
||||
f.read(&Data[0], Split);
|
||||
STCPSend(c, Data);
|
||||
Sent += size_t(Split);
|
||||
} else {
|
||||
std::string Data(Diff, 0);
|
||||
f.seekg(int64_t(Sent), std::ios_base::beg);
|
||||
f.read(&Data[0], int64_t(Diff));
|
||||
STCPSend(c, Data);
|
||||
Sent += Diff;
|
||||
}
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
|
||||
void Parse(Client* c, const std::string& Packet) {
|
||||
Assert(c);
|
||||
if (c == nullptr || Packet.empty())
|
||||
return;
|
||||
char Code = Packet.at(0), SubCode = 0;
|
||||
if (Packet.length() > 1)
|
||||
SubCode = Packet.at(1);
|
||||
switch (Code) {
|
||||
case 'f':
|
||||
SendFile(c, Packet.substr(1));
|
||||
return;
|
||||
case 'S':
|
||||
if (SubCode == 'R') {
|
||||
debug(Sec("Sending Mod Info"));
|
||||
std::string ToSend = FileList + FileSizes;
|
||||
if (ToSend.empty())
|
||||
ToSend = "-";
|
||||
STCPSend(c, ToSend);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool STCPRecv(Client* c) {
|
||||
Assert(c);
|
||||
if (c == nullptr)
|
||||
return false;
|
||||
#define len 200
|
||||
char buf[len];
|
||||
ZeroMemory(buf, len);
|
||||
int64_t BytesRcv = recv(c->GetTCPSock(), buf, len, 0);
|
||||
#undef len
|
||||
if (BytesRcv == 0) {
|
||||
if (c->GetStatus() > -1)
|
||||
c->SetStatus(-1);
|
||||
info(Sec("Closing socket in STCP receive, BytesRcv == 0"));
|
||||
CloseSocketProper(c->GetTCPSock());
|
||||
return false;
|
||||
} else if (BytesRcv < 0) {
|
||||
if (c->GetStatus() > -1)
|
||||
c->SetStatus(-1);
|
||||
info(Sec("Closing socket in STCP receive, BytesRcv < 0"));
|
||||
CloseSocketProper(c->GetTCPSock());
|
||||
return false;
|
||||
}
|
||||
if (strcmp(buf, "Done") == 0)
|
||||
return false;
|
||||
std::string Ret(buf, size_t(BytesRcv));
|
||||
Parse(c, Ret);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SyncResources(Client* c) {
|
||||
Assert(c);
|
||||
if (c == nullptr)
|
||||
return;
|
||||
try {
|
||||
STCPSend(c, Sec("WS"));
|
||||
while (c->GetStatus() > -1 && STCPRecv(c))
|
||||
;
|
||||
} catch (std::exception& e) {
|
||||
except(Sec("Exception! : ") + std::string(e.what()));
|
||||
c->SetStatus(-1);
|
||||
}
|
||||
}
|
||||
137
src/Network/TCPHandler.cpp
Normal file
137
src/Network/TCPHandler.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 8/1/2020
|
||||
///
|
||||
#include "Compressor.h"
|
||||
#include "Logger.h"
|
||||
#include "Network.h"
|
||||
#include "Security/Enc.h"
|
||||
#include "UnixCompat.h"
|
||||
#include <thread>
|
||||
|
||||
void TCPSend(Client* c, const std::string& Data) {
|
||||
Assert(c);
|
||||
if (c == nullptr)
|
||||
return;
|
||||
// Size is BIG ENDIAN now, use only for header!
|
||||
//auto Size = htonl(int32_t(Data.size()));
|
||||
///TODO : BIG ENDIAN for other OS
|
||||
int32_t Size, Sent, Temp;
|
||||
std::string Send(4, 0);
|
||||
Size = int32_t(Data.size());
|
||||
memcpy(&Send[0], &Size, sizeof(Size));
|
||||
Send += Data;
|
||||
Sent = 0;
|
||||
Size += 4;
|
||||
do {
|
||||
Temp = send(c->GetTCPSock(), &Send[Sent], Size - Sent, 0);
|
||||
if (Temp == 0) {
|
||||
if (c->GetStatus() > -1)
|
||||
c->SetStatus(-1);
|
||||
return;
|
||||
} else if (Temp < 0) {
|
||||
if (c->GetStatus() > -1)
|
||||
c->SetStatus(-1);
|
||||
// info(Sec("Closing socket, Temp < 0"));
|
||||
CloseSocketProper(c->GetTCPSock());
|
||||
return;
|
||||
}
|
||||
Sent += Temp;
|
||||
} while (Sent < Size);
|
||||
}
|
||||
|
||||
bool CheckBytes(Client* c, int32_t BytesRcv) {
|
||||
Assert(c);
|
||||
if (BytesRcv == 0) {
|
||||
debug(Sec("(TCP) Connection closing..."));
|
||||
if (c->GetStatus() > -1)
|
||||
c->SetStatus(-1);
|
||||
return false;
|
||||
} else if (BytesRcv < 0) {
|
||||
#ifdef WIN32
|
||||
debug(Sec("(TCP) recv failed with error: ") + std::to_string(WSAGetLastError()));
|
||||
#else // unix
|
||||
debug(Sec("(TCP) recv failed with error: ") + std::string(strerror(errno)));
|
||||
#endif // WIN32
|
||||
if (c->GetStatus() > -1)
|
||||
c->SetStatus(-1);
|
||||
info(Sec("Closing socket in CheckBytes, BytesRcv < 0"));
|
||||
CloseSocketProper(c->GetTCPSock());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TCPRcv(Client* c) {
|
||||
Assert(c);
|
||||
int32_t Header, BytesRcv = 0, Temp;
|
||||
if (c == nullptr || c->GetStatus() < 0)
|
||||
return;
|
||||
|
||||
std::vector<char> Data(sizeof(Header));
|
||||
do {
|
||||
Temp = recv(c->GetTCPSock(), &Data[BytesRcv], 4 - BytesRcv, 0);
|
||||
if (!CheckBytes(c, Temp)) {
|
||||
#ifdef DEBUG
|
||||
error(std::string(__func__) + Sec(": failed on CheckBytes in while(BytesRcv < 4)"));
|
||||
#endif // DEBUG
|
||||
return;
|
||||
}
|
||||
BytesRcv += Temp;
|
||||
} while (size_t(BytesRcv) < sizeof(Header));
|
||||
memcpy(&Header, &Data[0], sizeof(Header));
|
||||
|
||||
#ifdef DEBUG
|
||||
//debug(std::string(__func__) + Sec(": expecting ") + std::to_string(Header) + Sec(" bytes."));
|
||||
#endif // DEBUG
|
||||
if (!CheckBytes(c, BytesRcv)) {
|
||||
#ifdef DEBUG
|
||||
error(std::string(__func__) + Sec(": failed on CheckBytes"));
|
||||
#endif // DEBUG
|
||||
return;
|
||||
}
|
||||
Data.resize(Header);
|
||||
BytesRcv = 0;
|
||||
do {
|
||||
Temp = recv(c->GetTCPSock(), &Data[BytesRcv], Header - BytesRcv, 0);
|
||||
if (!CheckBytes(c, Temp)) {
|
||||
#ifdef DEBUG
|
||||
error(std::string(__func__) + Sec(": failed on CheckBytes in while(BytesRcv < Header)"));
|
||||
#endif // DEBUG
|
||||
|
||||
return;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
//debug(std::string(__func__) + Sec(": Temp: ") + std::to_string(Temp) + Sec(", BytesRcv: ") + std::to_string(BytesRcv));
|
||||
#endif // DEBUG
|
||||
BytesRcv += Temp;
|
||||
} while (BytesRcv < Header);
|
||||
#ifdef DEBUG
|
||||
//debug(std::string(__func__) + Sec(": finished recv with Temp: ") + std::to_string(Temp) + Sec(", BytesRcv: ") + std::to_string(BytesRcv));
|
||||
#endif // DEBUG
|
||||
std::string Ret(Data.data(), Header);
|
||||
|
||||
if (Ret.substr(0, 4) == "ABG:") {
|
||||
Ret = DeComp(Ret.substr(4));
|
||||
}
|
||||
#ifdef DEBUG
|
||||
//debug("Parsing from " + c->GetName() + " -> " +std::to_string(Ret.size()));
|
||||
#endif
|
||||
GParser(c, Ret);
|
||||
}
|
||||
|
||||
void TCPClient(Client* c) {
|
||||
DebugPrintTIDInternal(Sec("Client(") + c->GetName() + Sec(")"), true);
|
||||
Assert(c);
|
||||
if (c->GetTCPSock() == -1) {
|
||||
CI->RemoveClient(c);
|
||||
return;
|
||||
}
|
||||
OnConnect(c);
|
||||
while (c->GetStatus() > -1)
|
||||
TCPRcv(c);
|
||||
OnDisconnect(c, c->GetStatus() == -2);
|
||||
}
|
||||
void InitClient(Client* c) {
|
||||
std::thread NewClient(TCPClient, c);
|
||||
NewClient.detach();
|
||||
}
|
||||
376
src/Network/VehicleData.cpp
Normal file
376
src/Network/VehicleData.cpp
Normal file
@@ -0,0 +1,376 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 5/8/2020
|
||||
///
|
||||
///UDP
|
||||
#include "Client.hpp"
|
||||
#include "Compressor.h"
|
||||
#include "Logger.h"
|
||||
#include "Network.h"
|
||||
#include "Security/Enc.h"
|
||||
#include "Settings.h"
|
||||
#include "UnixCompat.h"
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
int FC(const std::string& s, const std::string& p, int n);
|
||||
struct PacketData {
|
||||
int ID;
|
||||
::Client* Client;
|
||||
std::string Data;
|
||||
int Tries;
|
||||
};
|
||||
struct SplitData {
|
||||
int Total {};
|
||||
int ID {};
|
||||
std::set<std::pair<int, std::string>> Fragments;
|
||||
};
|
||||
|
||||
SOCKET UDPSock;
|
||||
std::set<PacketData*> DataAcks;
|
||||
std::set<SplitData*> SplitPackets;
|
||||
void UDPSend(Client* c, std::string Data) {
|
||||
Assert(c);
|
||||
if (c == nullptr || !c->isConnected || c->GetStatus() < 0)
|
||||
return;
|
||||
sockaddr_in Addr = c->GetUDPAddr();
|
||||
socklen_t AddrSize = sizeof(c->GetUDPAddr());
|
||||
if (Data.length() > 400) {
|
||||
std::string CMP(Comp(Data));
|
||||
Data = "ABG:" + CMP;
|
||||
}
|
||||
#ifdef WIN32
|
||||
int sendOk;
|
||||
int len = static_cast<int>(Data.size());
|
||||
#else
|
||||
int64_t sendOk;
|
||||
size_t len = Data.size();
|
||||
#endif // WIN32
|
||||
|
||||
sendOk = sendto(UDPSock, Data.c_str(), len, 0, (sockaddr*)&Addr, AddrSize);
|
||||
#ifdef WIN32
|
||||
if (sendOk == -1) {
|
||||
debug(Sec("(UDP) Send Failed Code : ") + std::to_string(WSAGetLastError()));
|
||||
if (c->GetStatus() > -1)
|
||||
c->SetStatus(-1);
|
||||
} else if (sendOk == 0) {
|
||||
debug(Sec("(UDP) sendto returned 0"));
|
||||
if (c->GetStatus() > -1)
|
||||
c->SetStatus(-1);
|
||||
}
|
||||
#else // unix
|
||||
if (sendOk == -1) {
|
||||
debug(Sec("(UDP) Send Failed Code : ") + std::string(strerror(errno)));
|
||||
if (c->GetStatus() > -1)
|
||||
c->SetStatus(-1);
|
||||
} else if (sendOk == 0) {
|
||||
debug(Sec("(UDP) sendto returned 0"));
|
||||
if (c->GetStatus() > -1)
|
||||
c->SetStatus(-1);
|
||||
}
|
||||
#endif // WIN32
|
||||
}
|
||||
|
||||
void AckID(int ID) {
|
||||
for (PacketData* p : DataAcks) {
|
||||
if (p != nullptr && p->ID == ID) {
|
||||
DataAcks.erase(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
int PacktID() {
|
||||
static int ID = -1;
|
||||
if (ID > 999999)
|
||||
ID = 0;
|
||||
else
|
||||
ID++;
|
||||
return ID;
|
||||
}
|
||||
int SplitID() {
|
||||
static int SID = -1;
|
||||
if (SID > 999999)
|
||||
SID = 0;
|
||||
else
|
||||
SID++;
|
||||
return SID;
|
||||
}
|
||||
void SendLarge(Client* c, std::string Data) {
|
||||
Assert(c);
|
||||
if (Data.length() > 400) {
|
||||
std::string CMP(Comp(Data));
|
||||
Data = "ABG:" + CMP;
|
||||
}
|
||||
TCPSend(c, Data);
|
||||
}
|
||||
struct HandledC {
|
||||
size_t Pos = 0;
|
||||
Client* c = nullptr;
|
||||
std::array<int, 100> HandledIDs = { -1 };
|
||||
};
|
||||
std::set<HandledC*> HandledIDs;
|
||||
void ResetIDs(HandledC* H) {
|
||||
for (size_t C = 0; C < 100; C++) {
|
||||
H->HandledIDs.at(C) = -1;
|
||||
}
|
||||
}
|
||||
HandledC* GetHandled(Client* c) {
|
||||
Assert(c);
|
||||
for (HandledC* h : HandledIDs) {
|
||||
if (h->c == c) {
|
||||
return h;
|
||||
}
|
||||
}
|
||||
return new HandledC();
|
||||
}
|
||||
bool Handled(Client* c, int ID) {
|
||||
Assert(c);
|
||||
bool handle = false;
|
||||
for (HandledC* h : HandledIDs) {
|
||||
if (h->c == c) {
|
||||
for (int id : h->HandledIDs) {
|
||||
if (id == ID)
|
||||
return true;
|
||||
}
|
||||
if (h->Pos > 99)
|
||||
h->Pos = 0;
|
||||
h->HandledIDs.at(h->Pos) = ID;
|
||||
h->Pos++;
|
||||
handle = true;
|
||||
}
|
||||
}
|
||||
for (HandledC* h : HandledIDs) {
|
||||
if (h->c == nullptr || !h->c->isConnected) {
|
||||
HandledIDs.erase(h);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!handle) {
|
||||
HandledC* h = GetHandled(c);
|
||||
ResetIDs(h);
|
||||
if (h->Pos > 99)
|
||||
h->Pos = 0;
|
||||
h->HandledIDs.at(h->Pos) = ID;
|
||||
h->Pos++;
|
||||
h->c = c;
|
||||
HandledIDs.insert(h);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
std::string UDPRcvFromClient(sockaddr_in& client) {
|
||||
size_t clientLength = sizeof(client);
|
||||
ZeroMemory(&client, clientLength);
|
||||
std::string Ret(10240, 0);
|
||||
int64_t Rcv = recvfrom(UDPSock, &Ret[0], 10240, 0, (sockaddr*)&client, (socklen_t*)&clientLength);
|
||||
if (Rcv == -1) {
|
||||
#ifdef WIN32
|
||||
error(Sec("(UDP) Error receiving from Client! Code : ") + std::to_string(WSAGetLastError()));
|
||||
#else // unix
|
||||
error(Sec("(UDP) Error receiving from Client! Code : ") + std::string(strerror(errno)));
|
||||
#endif // WIN32
|
||||
return "";
|
||||
}
|
||||
return Ret.substr(0, Rcv);
|
||||
}
|
||||
|
||||
SplitData* GetSplit(int SplitID) {
|
||||
for (SplitData* a : SplitPackets) {
|
||||
if (a->ID == SplitID)
|
||||
return a;
|
||||
}
|
||||
auto* SP = new SplitData();
|
||||
SplitPackets.insert(SP);
|
||||
return SP;
|
||||
}
|
||||
void HandleChunk(Client* c, const std::string& Data) {
|
||||
Assert(c);
|
||||
int pos = FC(Data, "|", 5);
|
||||
if (pos == -1)
|
||||
return;
|
||||
std::stringstream ss(Data.substr(0, size_t(pos++)));
|
||||
std::string t;
|
||||
int I = -1;
|
||||
//Current Max ID SID
|
||||
std::vector<int> Num(4, 0);
|
||||
while (std::getline(ss, t, '|')) {
|
||||
if (I >= 0)
|
||||
Num.at(size_t(I)) = std::stoi(t);
|
||||
I++;
|
||||
}
|
||||
std::string ack = "TRG:" + std::to_string(Num.at(2));
|
||||
UDPSend(c, ack);
|
||||
if (Handled(c, Num.at(2))) {
|
||||
return;
|
||||
}
|
||||
std::string Packet = Data.substr(size_t(pos));
|
||||
SplitData* SData = GetSplit(Num.at(3));
|
||||
SData->Total = Num.at(1);
|
||||
SData->ID = Num.at(3);
|
||||
SData->Fragments.insert(std::make_pair(Num.at(0), Packet));
|
||||
if (SData->Fragments.size() == size_t(SData->Total)) {
|
||||
std::string ToHandle;
|
||||
for (const std::pair<int, std::string>& a : SData->Fragments) {
|
||||
ToHandle += a.second;
|
||||
}
|
||||
GParser(c, ToHandle);
|
||||
SplitPackets.erase(SData);
|
||||
delete SData;
|
||||
SData = nullptr;
|
||||
}
|
||||
}
|
||||
void UDPParser(Client* c, std::string Packet) {
|
||||
if (Packet.find("Zp") != std::string::npos && Packet.size() > 500) {
|
||||
abort();
|
||||
}
|
||||
Assert(c);
|
||||
if (Packet.substr(0, 4) == "ABG:") {
|
||||
Packet = DeComp(Packet.substr(4));
|
||||
}
|
||||
if (Packet.substr(0, 4) == "TRG:") {
|
||||
std::string pkt = Packet.substr(4);
|
||||
if (Packet.find_first_not_of("0123456789") == std::string::npos) {
|
||||
AckID(stoi(Packet));
|
||||
}
|
||||
return;
|
||||
} else if (Packet.substr(0, 3) == "BD:") {
|
||||
auto pos = Packet.find(':', 4);
|
||||
int ID = stoi(Packet.substr(3, pos - 3));
|
||||
std::string pkt = "TRG:" + std::to_string(ID);
|
||||
UDPSend(c, pkt);
|
||||
if (!Handled(c, ID)) {
|
||||
pkt = Packet.substr(pos + 1);
|
||||
GParser(c, pkt);
|
||||
}
|
||||
return;
|
||||
} else if (Packet.substr(0, 2) == "SC") {
|
||||
HandleChunk(c, Packet);
|
||||
return;
|
||||
}
|
||||
GParser(c, Packet);
|
||||
}
|
||||
void LOOP() {
|
||||
DebugPrintTID();
|
||||
while (UDPSock != -1) {
|
||||
if (!DataAcks.empty()) {
|
||||
for (PacketData* p : DataAcks) {
|
||||
if (p != nullptr) {
|
||||
if (p->Client == nullptr || p->Client->GetTCPSock() == -1) {
|
||||
DataAcks.erase(p);
|
||||
break;
|
||||
}
|
||||
if (p->Tries < 15) {
|
||||
UDPSend(p->Client, p->Data);
|
||||
p->Tries++;
|
||||
} else {
|
||||
DataAcks.erase(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(300));
|
||||
}
|
||||
}
|
||||
[[noreturn]] void UDPServerMain() {
|
||||
#ifdef WIN32
|
||||
WSADATA data;
|
||||
if (WSAStartup(514, &data)) {
|
||||
error(Sec("Can't start Winsock!"));
|
||||
//return;
|
||||
}
|
||||
|
||||
UDPSock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
// Create a server hint structure for the server
|
||||
sockaddr_in serverAddr {};
|
||||
serverAddr.sin_addr.S_un.S_addr = ADDR_ANY; //Any Local
|
||||
serverAddr.sin_family = AF_INET; // Address format is IPv4
|
||||
serverAddr.sin_port = htons(Port); // Convert from little to big endian
|
||||
|
||||
// Try and bind the socket to the IP and port
|
||||
if (bind(UDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
|
||||
error(Sec("Can't bind socket!") + std::to_string(WSAGetLastError()));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
_Exit(-1);
|
||||
//return;
|
||||
}
|
||||
|
||||
DataAcks.clear();
|
||||
std::thread Ack(LOOP);
|
||||
Ack.detach();
|
||||
|
||||
info(Sec("Vehicle data network online on port ") + std::to_string(Port) + Sec(" with a Max of ") + std::to_string(MaxPlayers) + Sec(" Clients"));
|
||||
while (true) {
|
||||
try {
|
||||
sockaddr_in client {};
|
||||
std::string Data = UDPRcvFromClient(client); //Receives any data from Socket
|
||||
auto Pos = Data.find(':');
|
||||
if (Data.empty() || Pos < 0 || Pos > 2)
|
||||
continue;
|
||||
/*char clientIp[256];
|
||||
ZeroMemory(clientIp, 256); ///Code to get IP we don't need that yet
|
||||
inet_ntop(AF_INET, &client.sin_addr, clientIp, 256);*/
|
||||
uint8_t ID = Data.at(0) - 1;
|
||||
for (auto& c : CI->Clients) {
|
||||
if (c != nullptr && c->GetID() == ID) {
|
||||
c->SetUDPAddr(client);
|
||||
c->isConnected = true;
|
||||
UDPParser(c.get(), Data.substr(2));
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
error(Sec("fatal: ") + std::string(e.what()));
|
||||
}
|
||||
}
|
||||
/*CloseSocketProper(UDPSock);
|
||||
WSACleanup();
|
||||
return;*/
|
||||
#else // unix
|
||||
UDPSock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
// Create a server hint structure for the server
|
||||
sockaddr_in serverAddr {};
|
||||
serverAddr.sin_addr.s_addr = INADDR_ANY; //Any Local
|
||||
serverAddr.sin_family = AF_INET; // Address format is IPv4
|
||||
serverAddr.sin_port = htons(uint16_t(Port)); // Convert from little to big endian
|
||||
|
||||
// Try and bind the socket to the IP and port
|
||||
if (bind(UDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) != 0) {
|
||||
error(Sec("Can't bind socket!") + std::string(strerror(errno)));
|
||||
std::this_thread::sleep_for(std::chrono::seconds(5));
|
||||
_Exit(-1);
|
||||
//return;
|
||||
}
|
||||
|
||||
DataAcks.clear();
|
||||
std::thread Ack(LOOP);
|
||||
Ack.detach();
|
||||
|
||||
info(Sec("Vehicle data network online on port ") + std::to_string(Port) + Sec(" with a Max of ") + std::to_string(MaxPlayers) + Sec(" Clients"));
|
||||
while (true) {
|
||||
try {
|
||||
sockaddr_in client {};
|
||||
std::string Data = UDPRcvFromClient(client); //Receives any data from Socket
|
||||
size_t Pos = Data.find(':');
|
||||
if (Data.empty() || Pos > 2)
|
||||
continue;
|
||||
/*char clientIp[256];
|
||||
ZeroMemory(clientIp, 256); ///Code to get IP we don't need that yet
|
||||
inet_ntop(AF_INET, &client.sin_addr, clientIp, 256);*/
|
||||
uint8_t ID = uint8_t(Data.at(0)) - 1;
|
||||
for (auto& c : CI->Clients) {
|
||||
if (c != nullptr && c->GetID() == ID) {
|
||||
c->SetUDPAddr(client);
|
||||
c->isConnected = true;
|
||||
UDPParser(c.get(), Data.substr(2));
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
error(Sec("fatal: ") + std::string(e.what()));
|
||||
}
|
||||
}
|
||||
/*CloseSocketProper(UDPSock); // TODO: Why not this? We did this in TCPServerMain?
|
||||
return;
|
||||
*/
|
||||
#endif // WIN32
|
||||
}
|
||||
56
src/Network/Websocket.cpp
Normal file
56
src/Network/Websocket.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 11/6/2020
|
||||
///
|
||||
/*#include <boost/beast/core.hpp>
|
||||
#include "Logger.h"
|
||||
#include "Security/Enc.h"
|
||||
#include <boost/asio/connect.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>*/
|
||||
#include <boost/beast/websocket.hpp>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
/*namespace beast = boost::beast;
|
||||
namespace http = beast::http;
|
||||
namespace websocket = beast::websocket;
|
||||
namespace net = boost::asio;
|
||||
using tcp = boost::asio::ip::tcp;
|
||||
|
||||
std::string GetRes(const beast::flat_buffer& buff) {
|
||||
return (char*)buff.data().data();
|
||||
}*/
|
||||
|
||||
void SyncData() {
|
||||
/*DebugPrintTID();
|
||||
try {
|
||||
std::string const host = Sec("95.216.35.232");
|
||||
|
||||
net::io_context ioc;
|
||||
tcp::resolver r(ioc);
|
||||
|
||||
websocket::stream<tcp::socket> ws(ioc);
|
||||
auto const results = r.resolve(host, Sec("3600"));
|
||||
net::connect(ws.next_layer(), results.begin(), results.end());
|
||||
|
||||
|
||||
ws.handshake(host, "/");
|
||||
beast::flat_buffer buffer;
|
||||
ws.write(boost::asio::buffer("Hello, world!"));
|
||||
ws.read(buffer);
|
||||
|
||||
std::cout << GetRes(buffer) << std::endl;
|
||||
|
||||
ws.close(websocket::close_code::normal);
|
||||
|
||||
}catch(std::exception const& e){
|
||||
error(e.what());
|
||||
std::this_thread::sleep_for(std::chrono::seconds(3));
|
||||
_Exit(0);
|
||||
}*/
|
||||
}
|
||||
|
||||
void WebsocketInit() {
|
||||
/*std::thread t1(SyncData);
|
||||
t1.detach();*/
|
||||
}
|
||||
139
src/logger.cpp
Normal file
139
src/logger.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
///
|
||||
/// Created by Anonymous275 on 7/17/2020
|
||||
///
|
||||
#include "Logger.h"
|
||||
#include "RWMutex.h"
|
||||
#include "Security/Enc.h"
|
||||
#include "Settings.h"
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
static RWMutex ThreadNameMapMutex;
|
||||
static std::unordered_map<std::thread::id, std::string> ThreadNameMap;
|
||||
|
||||
std::string ThreadName() {
|
||||
ReadLock lock(ThreadNameMapMutex);
|
||||
std::string Name;
|
||||
if (ThreadNameMap.find(std::this_thread::get_id()) != ThreadNameMap.end()) {
|
||||
Name = ThreadNameMap.at(std::this_thread::get_id());
|
||||
} else {
|
||||
std::stringstream ss;
|
||||
ss << std::this_thread::get_id();
|
||||
Name = ss.str();
|
||||
}
|
||||
return Name;
|
||||
}
|
||||
|
||||
void SetThreadName(const std::string& Name, bool overwrite) {
|
||||
WriteLock lock(ThreadNameMapMutex);
|
||||
if (overwrite || ThreadNameMap.find(std::this_thread::get_id()) == ThreadNameMap.end()) {
|
||||
ThreadNameMap[std::this_thread::get_id()] = Name;
|
||||
}
|
||||
}
|
||||
|
||||
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 {};
|
||||
#ifdef WIN32
|
||||
localtime_s(&local_tm, &tt);
|
||||
#else // unix
|
||||
localtime_r(&tt, &local_tm);
|
||||
#endif // WIN32
|
||||
std::stringstream date;
|
||||
int S = local_tm.tm_sec;
|
||||
int M = local_tm.tm_min;
|
||||
int H = local_tm.tm_hour;
|
||||
std::string Secs = (S > 9 ? std::to_string(S) : "0" + std::to_string(S));
|
||||
std::string Min = (M > 9 ? std::to_string(M) : "0" + std::to_string(M));
|
||||
std::string Hour = (H > 9 ? std::to_string(H) : "0" + std::to_string(H));
|
||||
date
|
||||
<< "["
|
||||
<< local_tm.tm_mday << "/"
|
||||
<< local_tm.tm_mon + 1 << "/"
|
||||
<< local_tm.tm_year + 1900 << " "
|
||||
<< Hour << ":"
|
||||
<< Min << ":"
|
||||
<< Secs
|
||||
<< "] ";
|
||||
if (Debug) {
|
||||
date << ThreadName()
|
||||
<< " ";
|
||||
}
|
||||
return date.str();
|
||||
}
|
||||
|
||||
void InitLog() {
|
||||
std::ofstream LFS;
|
||||
LFS.open(Sec("Server.log"));
|
||||
if (!LFS.is_open()) {
|
||||
error(Sec("logger file init failed!"));
|
||||
} else
|
||||
LFS.close();
|
||||
}
|
||||
std::mutex LogLock;
|
||||
|
||||
void DebugPrintTIDInternal(const std::string& func, bool overwrite) {
|
||||
// we need to print to cout here as we might crash before all console output is handled,
|
||||
// due to segfaults or asserts.
|
||||
SetThreadName(func, overwrite);
|
||||
#ifdef DEBUG
|
||||
std::scoped_lock Guard(LogLock);
|
||||
std::stringstream Print;
|
||||
Print << "(debug build) Thread '" << std::this_thread::get_id() << "' is " << func << "\n";
|
||||
ConsoleOut(Print.str());
|
||||
#endif // DEBUG
|
||||
}
|
||||
|
||||
void addToLog(const std::string& Line) {
|
||||
std::ofstream LFS;
|
||||
LFS.open(Sec("Server.log"), std::ios_base::app);
|
||||
LFS << Line.c_str();
|
||||
LFS.close();
|
||||
}
|
||||
void info(const std::string& toPrint) {
|
||||
std::scoped_lock Guard(LogLock);
|
||||
std::string Print = getDate() + Sec("[INFO] ") + toPrint + "\n";
|
||||
ConsoleOut(Print);
|
||||
addToLog(Print);
|
||||
}
|
||||
void debug(const std::string& toPrint) {
|
||||
if (!Debug)
|
||||
return;
|
||||
std::scoped_lock Guard(LogLock);
|
||||
std::string Print = getDate() + Sec("[DEBUG] ") + toPrint + "\n";
|
||||
ConsoleOut(Print);
|
||||
addToLog(Print);
|
||||
}
|
||||
void warn(const std::string& toPrint) {
|
||||
std::scoped_lock Guard(LogLock);
|
||||
std::string Print = getDate() + Sec("[WARN] ") + toPrint + "\n";
|
||||
ConsoleOut(Print);
|
||||
addToLog(Print);
|
||||
}
|
||||
void error(const std::string& toPrint) {
|
||||
std::scoped_lock Guard(LogLock);
|
||||
std::string Print = getDate() + Sec("[ERROR] ") + toPrint + "\n";
|
||||
ConsoleOut(Print);
|
||||
addToLog(Print);
|
||||
}
|
||||
void except(const std::string& toPrint) {
|
||||
std::scoped_lock Guard(LogLock);
|
||||
std::string Print = getDate() + Sec("[EXCEP] ") + toPrint + "\n";
|
||||
ConsoleOut(Print);
|
||||
addToLog(Print);
|
||||
}
|
||||
53
src/main.cpp
Normal file
53
src/main.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "CustomAssert.h"
|
||||
#include "Security/Xor.h"
|
||||
#include "Startup.h"
|
||||
#include <curl/curl.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#ifndef WIN32
|
||||
#include <signal.h>
|
||||
void UnixSignalHandler(int sig) {
|
||||
switch (sig) {
|
||||
case SIGPIPE:
|
||||
warn(Sec("ignored signal SIGPIPE: Pipe broken"));
|
||||
break;
|
||||
default:
|
||||
error(Sec("Signal arrived in handler but was not handled: ") + std::to_string(sig));
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // WIN32
|
||||
|
||||
[[noreturn]] void loop() {
|
||||
DebugPrintTID();
|
||||
while (true) {
|
||||
std::cout.flush();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(600));
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifndef WIN32
|
||||
// ignore SIGPIPE, the signal that is sent for example when a client
|
||||
// disconnects while data is being sent to him ("broken pipe").
|
||||
signal(SIGPIPE, UnixSignalHandler);
|
||||
#endif // WIN32
|
||||
DebugPrintTID();
|
||||
// curl needs to be initialized to properly deallocate its resources later
|
||||
Assert(curl_global_init(CURL_GLOBAL_DEFAULT) == CURLE_OK);
|
||||
#ifdef DEBUG
|
||||
std::thread t1(loop);
|
||||
t1.detach();
|
||||
#endif
|
||||
ConsoleInit();
|
||||
InitServer(argc, argv);
|
||||
InitConfig();
|
||||
InitLua();
|
||||
InitRes();
|
||||
HBInit();
|
||||
StatInit();
|
||||
NetMain();
|
||||
// clean up curl at the end to be sure
|
||||
curl_global_cleanup();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user