This commit is contained in:
Carl Schou 2020-07-07 15:42:10 +02:00
parent be85cc38af
commit 91adcda082
19 changed files with 1300 additions and 0 deletions

63
.gitattributes vendored Normal file
View File

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

340
.gitignore vendored Normal file
View File

@ -0,0 +1,340 @@
## 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
# 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/
# 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
# 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
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# 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
# 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
# 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
*- Backup*.rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb

168
BottlEye/BottlEye.vcxproj Normal file
View File

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{9A6F6F8A-15CB-4276-BD96-1BA5E91DEED6}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>BottlEye</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>ClangCL</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>D:\Sync\Programming\C++\Libraries\Include;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;BOTTLEYE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;BOTTLEYE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;BOTTLEYE_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;BOTTLEYE_EXPORTS;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="D:\Sync\Programming\C++\Libraries\fmt\format.cc" />
<ClCompile Include="D:\Sync\Programming\C++\Libraries\fmt\posix.cc" />
<ClCompile Include="delegate.cpp" />
<ClCompile Include="emulator.cpp" />
<ClCompile Include="entry.cpp" />
<ClCompile Include="singleton.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="be_client.hpp" />
<ClInclude Include="be_packet.hpp" />
<ClInclude Include="delegate.hpp" />
<ClInclude Include="emulator.hpp" />
<ClInclude Include="loggr.hpp" />
<ClInclude Include="singleton.hpp" />
<ClInclude Include="spinner.hpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Source Files\fmt">
<UniqueIdentifier>{0c4a0d52-9a82-4d3f-9a16-c7500b15325c}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\logging">
<UniqueIdentifier>{1c69057d-6d08-43b0-90f1-f14b1a42e09b}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\battleye">
<UniqueIdentifier>{485f60e6-89b2-4606-8d47-d79821e828ba}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\battleye">
<UniqueIdentifier>{16a4f5db-842f-48d4-ba43-77c6665893b9}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="entry.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="delegate.cpp">
<Filter>Source Files\battleye</Filter>
</ClCompile>
<ClCompile Include="emulator.cpp">
<Filter>Source Files\battleye</Filter>
</ClCompile>
<ClCompile Include="singleton.cpp">
<Filter>Source Files\battleye</Filter>
</ClCompile>
<ClCompile Include="D:\Sync\Programming\C++\Libraries\fmt\format.cc">
<Filter>Source Files\fmt</Filter>
</ClCompile>
<ClCompile Include="D:\Sync\Programming\C++\Libraries\fmt\posix.cc">
<Filter>Source Files\fmt</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="spinner.hpp">
<Filter>Header Files\logging</Filter>
</ClInclude>
<ClInclude Include="loggr.hpp">
<Filter>Header Files\logging</Filter>
</ClInclude>
<ClInclude Include="be_client.hpp">
<Filter>Header Files\battleye</Filter>
</ClInclude>
<ClInclude Include="delegate.hpp">
<Filter>Header Files\battleye</Filter>
</ClInclude>
<ClInclude Include="singleton.hpp">
<Filter>Header Files\battleye</Filter>
</ClInclude>
<ClInclude Include="be_packet.hpp">
<Filter>Header Files\battleye</Filter>
</ClInclude>
<ClInclude Include="emulator.hpp">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

58
BottlEye/be_client.hpp Normal file
View File

@ -0,0 +1,58 @@
#pragma once
#include <cstdint>
namespace battleye
{
enum instance_status
{
NONE,
NOT_INITIALIZED,
SUCCESSFULLY_INITIALIZED,
DESTROYING,
DESTROYED
};
struct becl_game_data
{
char* game_version;
std::uint32_t address;
std::uint16_t port;
// FUNCTIONS
using print_message_t = void(*)(char* message);
print_message_t print_message;
using request_restart_t = void(*)(std::uint32_t reason);
request_restart_t request_restart;
using send_packet_t = void(*)(void* packet, std::uint32_t length);
send_packet_t send_packet;
using disconnect_peer_t = void(*)(std::uint8_t* guid, std::uint32_t guid_length, char* reason);
disconnect_peer_t disconnect_peer;
};
struct becl_be_data
{
using exit_t = bool(*)();
exit_t exit;
using run_t = void(*)();
run_t run;
using command_t = void(*)(char* command);
command_t command;
using received_packet_t = void(*)(std::uint8_t* received_packet, std::uint32_t length);
received_packet_t received_packet;
using on_receive_auth_ticket_t = void(*)(std::uint8_t* ticket, std::uint32_t length);
on_receive_auth_ticket_t on_receive_auth_ticket;
using add_peer_t = void(*)(std::uint8_t* guid, std::uint32_t guid_length);
add_peer_t add_peer;
using remove_peer_t = void(*)(std::uint8_t* guid, std::uint32_t guid_length);
remove_peer_t remove_peer;
};
}

49
BottlEye/be_packet.hpp Normal file
View File

@ -0,0 +1,49 @@
#pragma once
#include <cstdint>
namespace battleye
{
enum packet_id : std::uint8_t
{
INIT = 0x00,
START = 0x02,
REQUEST = 0x04,
RESPONSE = 0x05,
HEARTBEAT = 0x09,
};
#pragma pack(push, 1)
struct be_fragment
{
std::uint8_t count;
std::uint8_t index;
};
struct be_packet_header
{
std::uint8_t id;
std::uint8_t sequence;
};
struct be_packet : be_packet_header
{
union
{
be_fragment fragment;
// DATA STARTS AT body[1] IF PACKET IS FRAGMENTED
struct
{
std::uint8_t no_fragmentation_flag;
std::uint8_t body[0];
};
};
inline bool fragmented()
{
return this->fragment.count != 0x00;
}
};
#pragma pack(pop)
}

198
BottlEye/delegate.cpp Normal file
View File

@ -0,0 +1,198 @@
#include "delegate.hpp"
#include "singleton.hpp"
#include "be_packet.hpp"
#include <array>
#include <future>
#include <thread>
battleye::becl_game_data::send_packet_t battleye::delegate::o_send_packet = nullptr;
bool battleye::delegate::exit()
{
singleton::emulator.console().log("BottlEye exiting.");
return true;
}
void battleye::delegate::run()
{
//singleton::emulator.console().log("Executed 'run'");
}
void battleye::delegate::command(char* command)
{
singleton::emulator.console().log("Executed 'command'");
}
void battleye::delegate::received_packet(std::uint8_t* received_packet, std::uint32_t length)
{
auto header = reinterpret_cast<battleye::be_packet*>(received_packet);
switch (header->id)
{
case battleye::packet_id::INIT:
{
singleton::emulator.console().log("INIT");
singleton::emulator.console().log_indented<1, true>("Size (bytes)", length);
auto info_packet = battleye::be_packet{};
info_packet.id = battleye::packet_id::INIT;
info_packet.sequence = 0x05;
battleye::delegate::o_send_packet(&info_packet, sizeof(info_packet));
break;
}
case battleye::packet_id::START:
{
singleton::emulator.console().log("START");
singleton::emulator.console().log_indented<1, true>("Size (bytes)", length);
battleye::delegate::o_send_packet(received_packet, sizeof(battleye::be_packet_header));
break;
}
case battleye::packet_id::REQUEST:
{
singleton::emulator.console().log<true>("REQUEST", header->sequence);
// HANDLE PACKET FRAGMENTATION
if (header->fragmented())
{
singleton::emulator.console().log_indented<1, true>("Fragment count", header->fragment.count);
singleton::emulator.console().log_indented<1, true>("Fragment index", header->fragment.index);
}
// IF NOT FRAGMENTED RESPOND IMMEDIATELY, ELSE ONLY RESPOND TO THE LAST FRAGMENT
const auto respond = !header->fragmented() || (header->fragment.index == header->fragment.count - 1);
if (!respond)
{
singleton::emulator.console().log_indented<1>("Ignoring!");
return;
}
// SEND BACK HEADER
battleye::delegate::o_send_packet(received_packet, sizeof(battleye::be_packet_header));
singleton::emulator.console().log_indented<1>("Sending back header...");
switch (header->sequence)
{
case 0x01:
{
singleton::emulator.console().log_indented<1>("Replaying!");
battleye::delegate::respond(header->sequence,
{
// REDACTED
});
break;
}
case 0x02:
{
singleton::emulator.console().log_indented<1>("Replaying!");
battleye::delegate::respond(header->sequence,
{
// REDACTED
});
break;
}
default:
{
singleton::emulator.console().log_indented<1>("Replying!");
break;
}
}
break;
}
case battleye::packet_id::RESPONSE:
{
singleton::emulator.console().log<true>("Acknowledgement of packet", header->sequence);
break;
}
case battleye::packet_id::HEARTBEAT:
{
singleton::emulator.console().log("Heartbeat");
battleye::delegate::o_send_packet(received_packet, length);
break;
}
default:
{
//battleye::delegate::o_send_packet(received_packet, sizeof(battleye::be_packet));
singleton::emulator.console().log<true>("Unhandled packet", header->id);
break;
}
}
}
void battleye::delegate::on_receive_auth_ticket(std::uint8_t* ticket, std::uint32_t length)
{
singleton::emulator.console().log("Executed 'on_receive_auth_ticket'");
}
void battleye::delegate::add_peer(std::uint8_t* guid, std::uint32_t guid_length)
{
singleton::emulator.console().log("Executed 'add_peer'");
}
void battleye::delegate::remove_peer(std::uint8_t* guid, std::uint32_t guid_length)
{
singleton::emulator.console().log("Executed 'remove_peer'");
}
void battleye::delegate::respond(std::uint8_t response_index, std::initializer_list<std::uint8_t> data)
{
// SETUP RESPONSE PACKET WITH TWO-BYTE HEADER + NO-FRAGMENTATION TOGGLE
const auto size = sizeof(battleye::be_packet_header) + sizeof(battleye::be_fragment::count) + data.size();
auto packet = std::make_unique<std::uint8_t[]>(size);
auto packet_buffer = packet.get();
packet_buffer[0] = (battleye::packet_id::RESPONSE); // PACKET ID
packet_buffer[1] = (response_index - 1); // RESPONSE INDEX
packet_buffer[2] = (0x00); // FRAGMENTATION DISABLED
for (size_t i = 0; i < data.size(); i++)
{
packet_buffer[3 + i] = data.begin()[i];
}
battleye::delegate::o_send_packet(packet_buffer, size);
}
void battleye::delegate::respond_fragmented(std::uint8_t response_index, battleye::be_fragment fragment, std::initializer_list<std::uint8_t> data)
{
// SETUP RESPONSE PACKET WITH TWO-BYTE HEADER + FRAGMENTATION HEADER
const auto size = sizeof(battleye::packet_id) + sizeof(response_index) + sizeof(fragment) + data.size();
if (size != 0x400 && fragment.index != fragment.count - 1) // ALL FRAGMENTS BUT THE LAST IS 0x400 LONG
{
singleton::emulator.console().log_error("Sending too little fragment...");
}
auto packet = std::make_unique<std::uint8_t[]>(size);
auto packet_buffer = packet.get();
packet_buffer[0] = battleye::packet_id::RESPONSE; // PACKET ID
packet_buffer[1] = response_index - 1; // RESPONSE INDEX
packet_buffer[2] = fragment.count; // FRAGMENTATION COUNT
packet_buffer[3] = fragment.index; // FRAGMENTATION INDEX
for (size_t i = 0; i < data.size(); i++)
{
packet_buffer[4 + i] = data.begin()[i];
}
// DEBUG PRINT
battleye::delegate::o_send_packet(packet_buffer, size);
}

20
BottlEye/delegate.hpp Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include "be_client.hpp"
#include "be_packet.hpp"
#include <vector>
namespace battleye::delegate
{
extern battleye::becl_game_data::send_packet_t o_send_packet;
bool exit();
void run();
void command(char* command);
void received_packet(std::uint8_t* received_packet, std::uint32_t length);
void on_receive_auth_ticket(std::uint8_t* ticket, std::uint32_t length);
void add_peer(std::uint8_t* guid, std::uint32_t guid_length);
void remove_peer(std::uint8_t* guid, std::uint32_t guid_length);
void respond(std::uint8_t response_index, std::initializer_list<std::uint8_t> data);
void respond_fragmented(std::uint8_t response_index, battleye::be_fragment fragment, std::initializer_list<std::uint8_t> data);
}

25
BottlEye/emulator.cpp Normal file
View File

@ -0,0 +1,25 @@
#include "emulator.hpp"
#include "delegate.hpp"
void battleye::emulator::setup_battleye(battleye::becl_game_data* game_data,
battleye::becl_be_data* client_data)
{
this->console().log("Setting up game_data...");
this->console().log_indented<1>("Game version", game_data->game_version);
this->console().log_indented<1, true>("Address", game_data->address);
this->console().log_indented<1, true>("Port", game_data->port);
// CACHE RELEVANT FUNCTIONS
battleye::delegate::o_send_packet = game_data->send_packet;
// SETUP CLIENT STRUCTURE
client_data->exit = battleye::delegate::exit;
client_data->run = battleye::delegate::run;
client_data->command = battleye::delegate::command;
client_data->received_packet = battleye::delegate::received_packet;
client_data->on_receive_auth_ticket = battleye::delegate::on_receive_auth_ticket;
client_data->add_peer = battleye::delegate::add_peer;
client_data->remove_peer = battleye::delegate::remove_peer;
this->console().log_indented<1>("Done!");
}

24
BottlEye/emulator.hpp Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include "loggr.hpp"
#include "be_client.hpp"
namespace battleye
{
class emulator
{
public:
emulator() : m_logger() {}
void setup_battleye(battleye::becl_game_data* game_data,
battleye::becl_be_data* client_data);
inline loggr& console()
{
return this->m_logger;
}
private:
loggr m_logger;
};
}

34
BottlEye/entry.cpp Normal file
View File

@ -0,0 +1,34 @@
#include <cstdint>
#include "be_client.hpp"
#include "singleton.hpp"
extern "C"
{
// BEClient_x64!Init
__declspec(dllexport)
battleye::instance_status Init(std::uint64_t integration_version,
battleye::becl_game_data* game_data,
battleye::becl_be_data* client_data)
{
singleton::emulator.console().log("Initialising BottlEye!");
singleton::emulator.console().log_indented<1>("Brought to you by: https://secret.club/");
singleton::emulator.setup_battleye(game_data, client_data);
return battleye::instance_status::SUCCESSFULLY_INITIALIZED;
}
// BEClient_x64!GetVer
__declspec(dllexport)
std::uint32_t GetVer()
{
return 0xFF;
}
}
std::uint32_t __stdcall DllMain(const void* mod_instance [[maybe_unused]],
const std::uint32_t call_reason [[maybe_unused]],
const void* reserved [[maybe_unused]])
{
return 1;
}

130
BottlEye/loggr.hpp Normal file
View File

@ -0,0 +1,130 @@
#pragma once
#include <windows.h>
#include <iostream>
#include <chrono>
#include <fmt\core.h>
class loggr
{
public:
loggr()
{
// SETUP CONSOLE IF NOT PRESENT
auto console_window = GetConsoleWindow();
if (console_window == 0x00)
{
if (!AllocConsole())
{
// ???? SHOULD NEVER HAPPEN
return;
}
std::freopen("CONOUT$", "w", stdout);
m_did_allocate_console = true;
}
}
~loggr()
{
// FREE CONSOLE IF DYNAMICALLY ALLOCATED
if (m_did_allocate_console)
{
const auto freed = FreeConsole();
if (!freed)
{
// ??
}
}
}
// CONSOLE LOGGING FUNCTIONS
template <class...T>
inline void log_raw(T... arguments) const
{
fmt::print(arguments...);
}
inline void log(std::string_view message) const
{
fmt::print("[+] {}\n", message);
}
inline void log_error(std::string_view message) const
{
fmt::print("[!] {}\n", message);
}
template <bool hex = false, class T>
inline void log(std::string_view variable_name, const T& value) const
{
constexpr auto format_string = hex ?
"[=] {:<15} {:X}\n" :
"[=] {:<15} {}\n";
fmt::print(format_string, variable_name, value);
}
template <std::size_t indentation>
inline void log_error_indented(std::string_view message) const
{
fmt::print("[!] {:<{}} {}\n", ' ', indentation, message);
}
template <std::size_t indentation>
inline void log_indented(std::string_view message) const
{
fmt::print("[+] {:<{}} {}\n", ' ', indentation, message);
}
template <std::size_t indentation, bool hex = false, class T>
inline void log_indented(std::string_view variable_name, const T& value) const
{
constexpr auto format_string = hex ?
"[=] {:<{}} {:.<15} {:02X}\n" :
"[=] {:<{}} {:.<15} {}\n";
fmt::print(format_string, ' ', indentation, variable_name, value);
}
// CONSOLE MODIFICATION FUNCTIONS
inline COORD get_position() const
{
CONSOLE_SCREEN_BUFFER_INFO info;
if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info))
{
this->log_error("Failed to get cursor position");
return { 0, 0 };
}
return info.dwCursorPosition;
}
inline void set_position(const COORD cursor) const
{
if (!SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), cursor))
{
this->log_error("Failed to set cursor position");
}
}
inline void clear_line() const
{
// GET CURSOR POSITION
auto position = this->get_position();
position.X = 0;
// CLEAR LINE
DWORD count = 0;
const auto handle = GetStdHandle(STD_OUTPUT_HANDLE);
auto result = FillConsoleOutputCharacter(handle, ' ', 150, position, &count);
// RESET POSITION
set_position(position);
}
private:
bool m_did_allocate_console = false;
};

3
BottlEye/singleton.cpp Normal file
View File

@ -0,0 +1,3 @@
#include "singleton.hpp"
battleye::emulator singleton::emulator = battleye::emulator();

7
BottlEye/singleton.hpp Normal file
View File

@ -0,0 +1,7 @@
#pragma once
#include "emulator.hpp"
namespace singleton
{
extern battleye::emulator emulator;
}

77
BottlEye/spinner.hpp Normal file
View File

@ -0,0 +1,77 @@
#pragma once
#include "loggr.hpp"
#include <chrono>
class spinner
{
public:
spinner(loggr* new_logger) : m_logger(new_logger) { }
static constexpr std::uint8_t CHARACTER_SEQUENCE[] =
{
'|', '/', '-', '\\'
};
inline void start()
{
if (this->m_active)
{
this->m_logger->log_error("Cannot initialise spinner object more than once!");
return;
}
this->m_active = true;
}
inline void update()
{
if (!this->m_active)
{
this->m_logger->log_error("Cannot initialise spinner object without initialization!");
return;
}
// GET TIME SINCE LAST UPDATE
using clock_t = std::chrono::high_resolution_clock;
const auto time = clock_t::now();
const auto time_delta = time - m_last_update_time;
const auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(time_delta);
// ONLY UPDATE SPINNER EVERY x MS
constexpr auto update_time = 150;
if (duration.count() <= update_time)
{
return;
}
// UPDATE THE SPINNER CHARACTER
this->m_logger->clear_line();
this->m_logger->log_raw("[{}]", static_cast<char>(spinner::CHARACTER_SEQUENCE[this->m_seq_index]));
// INCREMENT AND WRAP
this->m_seq_index++;
this->m_seq_index %= sizeof(spinner::CHARACTER_SEQUENCE);
this->m_last_update_time = time;
}
inline void stop()
{
if (!this->m_active)
{
this->m_logger->log_error("Spinner is not active!");
return;
}
this->m_logger->clear_line();
this->m_active = false;
}
private:
const loggr* m_logger;
bool m_active = false;
std::size_t m_seq_index = 0;
std::chrono::steady_clock::time_point m_last_update_time;
};

31
Bottleye.sln Normal file
View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29609.76
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BottlEye", "BottlEye\BottlEye.vcxproj", "{9A6F6F8A-15CB-4276-BD96-1BA5E91DEED6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9A6F6F8A-15CB-4276-BD96-1BA5E91DEED6}.Debug|x64.ActiveCfg = Debug|x64
{9A6F6F8A-15CB-4276-BD96-1BA5E91DEED6}.Debug|x64.Build.0 = Debug|x64
{9A6F6F8A-15CB-4276-BD96-1BA5E91DEED6}.Debug|x86.ActiveCfg = Debug|Win32
{9A6F6F8A-15CB-4276-BD96-1BA5E91DEED6}.Debug|x86.Build.0 = Debug|Win32
{9A6F6F8A-15CB-4276-BD96-1BA5E91DEED6}.Release|x64.ActiveCfg = Release|x64
{9A6F6F8A-15CB-4276-BD96-1BA5E91DEED6}.Release|x64.Build.0 = Release|x64
{9A6F6F8A-15CB-4276-BD96-1BA5E91DEED6}.Release|x86.ActiveCfg = Release|Win32
{9A6F6F8A-15CB-4276-BD96-1BA5E91DEED6}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1C8FC625-02F3-4B76-A958-B1AED03C2B75}
EndGlobalSection
EndGlobal

4
README.md Normal file
View File

@ -0,0 +1,4 @@
<img src="./bottleye_logo.png" width="500">
# Overview
BottlEye is an usermode emulator for the commercial anti-cheat [BattlEye](battleye.com) that works by recreating the anti-cheat

BIN
bottleye_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

1
bottleye_logo.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 276.7 330.5"><path fill="#f3e0cd" d="M148.4 199.2s-3.3-5.4-14.4-10.9-12-4.4-30.2-11.5-41-15.6-41.8-18 3.5-7.7 16.5-15.6 15.9-11.4 34.1-14.8c11.6-2.2 20.7-2.3 29.7-2.4 4.8 0 9.7-.8 15-.7 14.5-3.4 16-7 13.8-10s-20.1.3-22.7-1.5 3.8-4.1 12.2-6.5 13.8-1 21.7-2.4 6.2-4 2.6-6-15.1-2-17-2.4-4.8-1.3-3.7-2.7 3.5-3.5 6-3.6 6.5 2.5 9.1 0-2.6-6.6-6-7.6-13.4 2.2-16 1.2 1.5-3.7 5.3-5 9.8-1.7 10.6-2.4c1.5-1.2 2.7-4.7 1.5-5.3s-10.4-2.7-23.3 3-28.3 19.7-28.3 19.7-3 4.7-29.4 15.2-50.4 14.6-74.1 26.2-23.5 29.5-12 42.3 12.5 14.3 37.4 29 52.2 34.7 78 33z"/><path fill="#feed00" d="M251.2 288.3V199s-31.7 1.6-44 0-64.4-11.4-68.3-7.4-25.7 36.8-38.8 60-16.4 36.7-16.4 36.7z"/><path fill="#f6dcc3" d="M152.9 215.8c-7-1.7-1.8-9.4-1.7-18.7 0 0 1.2-13.3-3.3-25.5-3.5-9.6-12.9-21-13.6-24.5a4.4 4.4 0 01.8-3.8c2.6-3.8 6.2-4 11.2-9.2 2.6-2.7 6.1-11 8.8-12.6 2-1.3 2-2.8 4-5.3 1.2-1.6 8.3-1.8 10.6-3.7 1-1 .6-2.6 1.8-4a59.6 59.6 0 0112.9-10.9c6.4-3.9 12.2-6.7 22-4.4s26.1 13 26.1 13l-17.3 69.1s-12.8 24.5-14.7 25.4c-1.7.8-36.9 15.2-46.3 15.2a5.5 5.5 0 01-1.3-.1z"/><g transform="rotate(12 1656 163.6)"><g fill="#fff"><path d="M208.4 581.5a22.2 22.2 0 01-22.4-22.4 22.2 22.2 0 016.6-15.8 20 20 0 0032.3.8 22.2 22.2 0 01-.7 30.9 22.2 22.2 0 01-15.8 6.5z"/><path fill="#313131" d="M208.4 580.5a21.3 21.3 0 0021.4-21.4c0-5-1.7-9.7-4.9-13.5a21 21 0 01-32.4-.8 21.3 21.3 0 00.8 29.5c4 4 9.4 6.2 15 6.2m0 2a23.2 23.2 0 01-23.3-23.4 23.2 23.2 0 017.8-17.4 19 19 0 0032 .7 23.2 23.2 0 01.1 33.3 23.2 23.2 0 01-16.5 6.8z"/></g><path fill="#313131" d="M208.4 573.1a13.5 13.5 0 01-9.8-4.3 15 15 0 01-4.1-10.4 15.3 15.3 0 014.1-10.4s6.1 4.1 10.2 4.1c3 0 9.8-3.6 10.3-3a14.7 14.7 0 013.2 9.3 15 15 0 01-4 10.4 13.5 13.5 0 01-10 4.3z"/><circle cx="2.5" cy="2.5" r="2.5" fill="#fff" transform="translate(212.8 553.5)"/><g fill="#fff"><path d="M213.1 588a6.2 6.2 0 01-6.2-6c0-.9.6-3.1 4.2-8.9l3.2-5c1.9 4 5 11.2 5 13.8 0 3.4-2.8 6.2-6.2 6.2z"/><path fill="#313131" d="M214.2 570.2l-2.3 3.5c-3.8 6-4 8-4 8.2a5.2 5.2 0 0010.4 0c0-.6-.3-2.7-2.8-8.5l-1.3-3.2m.3-4s5.8 11.8 5.8 15.7a7.2 7.2 0 01-14.4 0c0-4 8.6-15.7 8.6-15.7z"/></g></g><path fill="#f2f2f2" d="M71.6 32.2v-8.9L98 0l13.3 3.2L155 60.8v10.4l20.5 36.6-11.7 9.7-24.1-23-6-4.4h-9.3z"/><path fill="#feed01" d="M71.6 32.2l51.2-13.9 32 42.5v10.4l20.6 36.6-11.7 9.7-24.1-23-6-4.4h-9.3z" opacity=".7"/><path fill="#2e2e41" d="M199 92.3c1.2-1.4 8.9-4 16.6-1.6s12.2 3.5 22.8 12.4 11.4 10.8 17.8 23.9c5.2 10.4 4.4 28.4 4.6 35.4s2.8 8.8 4.9 11.5c2.5 4.2 2.7 11.9 5.9 19.9 5 12.7 2.9 12 4.1 25 .8 8.5-1 12-1.2 16.3-.1 2 2.5 6.2 2 11-.3 3.3.6 8 0 11.4-.6 3.7-.4 2-2 6.4s-3.6 9.5-4.6 11a115 115 0 01-9.8 12.3c-4.3 5-14.5 4.7-18.5 0s1.1-9.8 2.4-18.5 1.5-9.9 1.6-15.5 2-7.1-2.6-13.4-8.7-6.4-14.4-12.6-5.6-7.8-7.5-13-5.4-7.3-10.5-8.7-9-7.6-10.3-11.7 2.2-12.3 6-18.3 1.5-10.9 5.2-21.9 6.3-13.2 9.6-22 3.3-7.2 3.3-13.7.4-6.8-3.3-12.4-7.3-6.3-10.5-9.2-13-2.6-11.7-4z"/><path fill="#212121" d="M72.8 295.8a10.2 10.2 0 014.3.9 7 7 0 013 2.4 6.2 6.2 0 011 3.6 6.4 6.4 0 01-1 3.6 7.6 7.6 0 01-2.8 2.5 9.1 9.1 0 013.7 3 6.8 6.8 0 011.3 4 6.7 6.7 0 01-1.1 3.9 7.6 7.6 0 01-3.2 2.6 11.1 11.1 0 01-4.7 1H58.9v-27.5zm-1.5 11a4 4 0 002.7-.8 2.7 2.7 0 001-2.2 2.7 2.7 0 00-1-2.1 4 4 0 00-2.7-.9h-6.6v6zm1 11.4a4.4 4.4 0 002.8-.9 3 3 0 001.2-2.4 3 3 0 00-1.2-2.4 4.4 4.4 0 00-2.9-1h-7.5v6.7zm23.7 5.6a11.3 11.3 0 01-5.6-1.5 11 11 0 01-4.1-4 10.2 10.2 0 01-1.6-5.4 10.1 10.1 0 011.6-5.4 11.1 11.1 0 014-4 11.3 11.3 0 015.7-1.4 11.3 11.3 0 015.7 1.5 11.1 11.1 0 014 4 10.1 10.1 0 011.6 5.3 10.2 10.2 0 01-1.5 5.4 11 11 0 01-4.1 4 11.3 11.3 0 01-5.7 1.5zm0-5a5.4 5.4 0 002.9-.8 5.8 5.8 0 002-2.1 6 6 0 00.8-3 5.9 5.9 0 00-.8-3 5.8 5.8 0 00-2-2 5.4 5.4 0 00-2.9-.9 5.4 5.4 0 00-2.8.8A5.8 5.8 0 0091 310a5.9 5.9 0 00-.8 3 6 6 0 00.8 2.9 5.8 5.8 0 002 2.1 5.4 5.4 0 003 .8zm26.5 3.2a7.4 7.4 0 01-2.2 1.3 6.9 6.9 0 01-2.5.5 6 6 0 01-4.5-1.8 6.2 6.2 0 01-1.8-4.6v-10h-2.8v-4.8h2.8v-5.7h5.7v5.7h4.5v4.7h-4.5v9.2a2.5 2.5 0 00.5 1.7 1.8 1.8 0 001.4.6 3.4 3.4 0 001.2-.1 2.2 2.2 0 00.8-.5zm15.8 0a7.4 7.4 0 01-2.2 1.3 6.9 6.9 0 01-2.5.5 6 6 0 01-4.5-1.8 6.2 6.2 0 01-1.8-4.6v-10h-2.8v-4.8h2.8v-5.7h5.7v5.7h4.5v4.7H133v9.2a2.5 2.5 0 00.5 1.7 1.8 1.8 0 001.4.6 3.4 3.4 0 001.2-.1 2.2 2.2 0 00.8-.5zm3.5-26.7h5.9v28h-5.9zm32.3 5.8H159v5.5h13.8v5.3h-13.8v6h15.2v5.4H153v-27.5H174zm9.5 29.4a11 11 0 01-2.7-.4 10.8 10.8 0 01-2.4-.9l1.2-4a9.5 9.5 0 001.5.7 4 4 0 001.2.2 3.2 3.2 0 001.5-.3 2.6 2.6 0 001.1-1.1l.6-1.2-8.6-20.9h6l5.5 14.5 5-14.5h6l-8.4 21.7a11 11 0 01-3.1 4.6 6.7 6.7 0 01-4.4 1.6zm26.5-11.3a8.1 8.1 0 002.9-.5 7.6 7.6 0 002.5-1.5l3.2 3.4a9.6 9.6 0 01-3.7 2.3 13.5 13.5 0 01-4.7.9 11.4 11.4 0 01-5.6-1.4 10.5 10.5 0 01-4-4 10.7 10.7 0 01-1.5-5.5 10.8 10.8 0 011.4-5.5 10.3 10.3 0 014-3.9 10.8 10.8 0 015.4-1.4 10.2 10.2 0 015.5 1.5 9.4 9.4 0 013.6 4.3 16.2 16.2 0 011.3 6.6h-15.6a6 6 0 001.8 3.4 5 5 0 003.5 1.3zm0-12.6a5 5 0 00-3.4 1.2 5.8 5.8 0 00-1.9 3.2h10a5.6 5.6 0 00-1.6-3.2 4.4 4.4 0 00-3.2-1.2z"/></svg>

After

Width:  |  Height:  |  Size: 4.8 KiB