crlib: remove local headers

This commit is contained in:
dmitry 2021-09-08 20:05:14 +03:00
commit f41b63dc97
No known key found for this signature in database
GPG key ID: 8297CE728B7A7E37
24 changed files with 0 additions and 5502 deletions

View file

@ -1,408 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-basic.h>
#include <crlib/cr-memory.h>
#include <crlib/cr-movable.h>
#include <crlib/cr-random.h>
#include <initializer_list>
// policy to reserve memory
CR_DECLARE_SCOPED_ENUM (ReservePolicy,
Multiple,
Single,
)
CR_NAMESPACE_BEGIN
// simple array class like std::vector
template <typename T, ReservePolicy R = ReservePolicy::Multiple, size_t S = 0> class Array : public DenyCopying {
private:
T *contents_ {};
size_t capacity_ {};
size_t length_ {};
public:
explicit Array () {
if (fix (S > 0)) {
reserve (S);
}
}
Array (const size_t amount) {
reserve (amount);
}
Array (Array &&rhs) noexcept {
contents_ = rhs.contents_;
length_ = rhs.length_;
capacity_ = rhs.capacity_;
rhs.reset ();
}
Array (const std::initializer_list <T> &list) {
for (const auto &elem : list) {
push (elem);
}
}
~Array () {
destroy ();
}
private:
void destructElements () noexcept {
for (size_t i = 0; i < length_; ++i) {
Memory::destruct (&contents_[i]);
}
}
void transferElements (T *dest, T *src, size_t length) noexcept {
for (size_t i = 0; i < length; ++i) {
Memory::construct (&dest[i], cr::move (src[i]));
Memory::destruct (&src[i]);
}
}
void destroy () {
destructElements ();
Memory::release (contents_);
}
void reset () {
contents_ = nullptr;
capacity_ = 0;
length_ = 0;
}
public:
bool reserve (const size_t amount) {
if (length_ + amount < capacity_) {
return true;
}
auto capacity = capacity_ ? capacity_ : 12;
if (cr::fix (R == ReservePolicy::Multiple)) {
while (length_ + amount > capacity) {
capacity *= 2;
}
}
else {
capacity = amount + capacity_ + 1;
}
auto data = Memory::get <T> (capacity);
if (contents_) {
transferElements (data, contents_, length_);
Memory::release (contents_);
}
contents_ = data;
capacity_ = capacity;
return true;
}
bool resize (const size_t amount) {
if (amount < length_) {
while (amount < length_) {
discard ();
}
}
else if (amount > length_) {
if (!ensure (amount)) {
return false;
}
size_t resizeLength = amount - length_;
while (resizeLength--) {
emplace ();
}
}
return true;
}
bool ensure (const size_t amount) {
if (amount <= length_) {
return true;
}
return reserve (amount - length_);
}
template <typename U = size_t> U length () const {
return static_cast <U> (length_);
}
size_t capacity () const {
return capacity_;
}
template <typename U> bool set (size_t index, U &&object) {
if (index >= capacity_) {
if (!reserve (index + 1)) {
return false;
}
}
Memory::construct (&contents_[index], cr::forward <U> (object));
if (index >= length_) {
length_ = index + 1;
}
return true;
}
template <typename U> bool insert (size_t index, U &&object) {
return insert (index, &object, 1);
}
template <typename U> bool insert (size_t index, U *objects, size_t count = 1) {
if (!objects || !count) {
return false;
}
const size_t capacity = (length_ > index ? length_ : index) + count;
if (capacity >= capacity_ && !reserve (capacity)) {
return false;
}
if (index >= length_) {
for (size_t i = 0; i < count; ++i) {
Memory::construct (&contents_[i + index], cr::forward <U> (objects[i]));
}
length_ = capacity;
}
else {
size_t i = 0;
for (i = length_; i > index; --i) {
contents_[i + count - 1] = cr::move (contents_[i - 1]);
}
for (i = 0; i < count; ++i) {
Memory::construct (&contents_[i + index], cr::forward <U> (objects[i]));
}
length_ += count;
}
return true;
}
bool insert (size_t at, const Array &rhs) {
if (&rhs == this) {
return false;
}
return insert (at, &rhs.contents_[0], rhs.length_);
}
bool erase (const size_t index, const size_t count) {
if (index + count > capacity_) {
return false;
}
for (size_t i = index; i < index + count; ++i) {
Memory::destruct (&contents_[i]);
}
length_ -= count;
for (size_t i = index; i < length_; ++i) {
contents_[i] = cr::move (contents_[i + count]);
}
return true;
}
bool shift () {
return erase (0, 1);
}
template <typename U> bool unshift (U &&object) {
return insert (0, &object);
}
bool remove (const T &object) {
return erase (index (object), 1);
}
template <typename U> bool push (U &&object) {
if (!reserve (1)) {
return false;
}
Memory::construct (&contents_[length_], cr::forward <U> (object));
++length_;
return true;
}
template <typename ...Args> bool emplace (Args &&...args) {
if (!reserve (1)) {
return false;
}
Memory::construct (&contents_[length_], cr::forward <Args> (args)...);
++length_;
return true;
}
T pop () {
auto object = cr::move (contents_[length_ - 1]);
discard ();
return object;
}
void discard () {
erase (length_ - 1, 1);
}
size_t index (const T &object) const {
return &object - &contents_[0];
}
void shuffle () {
int32 shuffleLength = length <int32> ();
for (int32 i = shuffleLength; i >= 1; --i) {
cr::swap (contents_[i - 1], contents_[rg.get (i, shuffleLength - 2)]);
}
}
void reverse () {
for (size_t i = 0; i < length_ / 2; ++i) {
cr::swap (contents_[i], contents_[length_ - 1 - i]);
}
}
template <typename U> bool extend (U &&rhs) {
if (length_ == 0) {
*this = cr::move (rhs);
}
else {
for (size_t i = 0; i < rhs.length (); ++i) {
if (!push (cr::move (rhs[i]))) {
return false;
}
}
}
return true;
}
template <typename U> bool assign (U &&rhs) {
clear ();
return extend (cr::move (rhs));
}
void clear () {
destructElements ();
length_ = 0;
}
bool empty () const {
return length_ == 0;
}
bool shrink () {
if (length_ == capacity_ || !length_) {
return false;
}
auto data = Memory::get <T> (length_);
transferElements (data, contents_, length_);
Memory::release (contents_);
contents_ = data;
capacity_ = length_;
return true;
}
const T &at (size_t index) const {
return contents_[index];
}
T &at (size_t index) {
return contents_[index];
}
const T &first () const {
return contents_[0];
}
T &first () {
return contents_[0];
}
T &last () {
return contents_[length_ - 1];
}
const T &last () const {
return contents_[length_ - 1];
}
const T &random () const {
return contents_[rg.get (0, length <int32> () - 1)];
}
T &random () {
return contents_[rg.get (0, length <int32> () - 1)];
}
T *data () {
return contents_;
}
T *data () const {
return contents_;
}
public:
Array &operator = (Array &&rhs) noexcept {
if (this != &rhs) {
destroy ();
contents_ = rhs.contents_;
length_ = rhs.length_;
capacity_ = rhs.capacity_;
rhs.reset ();
}
return *this;
}
public:
const T &operator [] (size_t index) const {
return at (index);
}
T &operator [] (size_t index) {
return at (index);
}
// for range-based loops
public:
T *begin () {
return contents_;
}
T *begin () const {
return contents_;
}
T *end () {
return contents_ + length_;
}
T *end () const {
return contents_ + length_;
}
};
// small array (with minimal reserve policy, something like fixed array, but still able to grow, by default allocates 64 elements)
template <typename T> using SmallArray = Array <T, ReservePolicy::Single, 64>;
CR_NAMESPACE_END

View file

@ -1,130 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
// our global namaespace
#define CR_NAMESPACE_BEGIN namespace cr {
#define CR_NAMESPACE_END }
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <limits.h>
CR_NAMESPACE_BEGIN
//
// some useful type definitions
//
namespace types {
using int8 = signed char;
using int16 = signed short;
using int32 = signed int;
using uint8 = unsigned char;
using uint16 = unsigned short;
using uint32 = unsigned int;
using uint64 = unsigned long long;
}
// make types available for our own use
using namespace cr::types;
//
// global helper stuff
//
template <typename T, size_t N> constexpr size_t bufsize (const T (&)[N]) {
return N - 1;
}
template <typename T> constexpr T abs (const T &a) {
return a > 0 ? a : -a;
}
template <typename T> constexpr T bit (const T &a) {
return static_cast <T> (1ULL << a);
}
template <typename T> constexpr T min (const T &a, const T &b) {
return a < b ? a : b;
}
template <typename T> constexpr T max (const T &a, const T &b) {
return a > b ? a : b;
}
template <typename T> constexpr T square (const T &value) {
return value * value;
}
template <typename T> constexpr T clamp (const T &x, const T &a, const T &b) {
return min (max (x, a), b);
}
template <typename T> const T &fix (const T &type) {
return type;
}
//
// base classes
//
// simple non-copying base class
class DenyCopying {
protected:
explicit DenyCopying () = default;
~DenyCopying () = default;
public:
DenyCopying (const DenyCopying &) = delete;
DenyCopying &operator = (const DenyCopying &) = delete;
};
// singleton for objects
template<typename T> class Singleton : public DenyCopying {
protected:
Singleton ()
{ }
public:
static T &instance () {
static T __instance {};
return __instance;
}
public:
T *operator -> () {
return &instance ();
}
};
// simple scoped enum, instaed of enum class
#define CR_DECLARE_SCOPED_ENUM_TYPE(enumName, enumType, ...) \
CR_NAMESPACE_BEGIN \
namespace enums { \
struct _##enumName : protected DenyCopying { \
enum Type : enumType { \
__VA_ARGS__ \
}; \
}; \
} \
CR_NAMESPACE_END \
using enumName = ::cr::enums::_##enumName::Type; \
// same as above, but with int32 type
#define CR_DECLARE_SCOPED_ENUM(enumName, ...) \
CR_DECLARE_SCOPED_ENUM_TYPE(enumName, int32, __VA_ARGS__) \
// exposes global variable from class singleton
#define CR_EXPOSE_GLOBAL_SINGLETON(className, variable) \
static auto &variable { className::instance () } \
CR_NAMESPACE_END
// platform-dependant-stuff
#include <crlib/cr-platform.h>

View file

@ -1,151 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-array.h>
CR_NAMESPACE_BEGIN
// simple priority queue
template <typename T> class BinaryHeap final : public DenyCopying {
private:
Array <T> contents_;
public:
explicit BinaryHeap () = default;
BinaryHeap (BinaryHeap &&rhs) noexcept : contents_ (cr::move (rhs.contents_))
{ }
~BinaryHeap () = default;
public:
template <typename U> bool push (U &&item) {
if (!contents_.push (cr::move (item))) {
return false;
}
const size_t length = contents_.length ();
if (length > 1) {
percolateUp (length - 1);
}
return true;
}
template <typename ...Args> bool emplace (Args &&...args) {
if (!contents_.emplace (cr::forward <Args> (args)...)) {
return false;
}
const size_t length = contents_.length ();
if (length > 1) {
percolateUp (length - 1);
}
return true;
}
const T &top () const {
return contents_[0];
}
T pop () {
if (contents_.length () == 1) {
return contents_.pop ();
}
auto key (cr::move (contents_[0]));
contents_[0] = cr::move (contents_.last ());
contents_.discard ();
percolateDown (0);
return key;
}
public:
size_t length () const {
return contents_.length ();
}
bool empty () const {
return !contents_.length ();
}
void clear () {
contents_.clear ();
}
private:
void percolateUp (size_t index) {
while (index != 0) {
const size_t parentIndex = parent (index);
if (contents_[parentIndex] > contents_[index]) {
cr::swap (contents_[index], contents_[parentIndex]);
index = parentIndex;
}
else {
break;
}
}
}
void percolateDown (size_t index) {
while (hasLeft (index)) {
size_t bestIndex = left (index);
if (hasRight (index)) {
const size_t rightIndex = right (index);
if (contents_[rightIndex] < contents_[bestIndex]) {
bestIndex = rightIndex;
}
}
if (contents_[index] > contents_[bestIndex]) {
cr::swap (contents_[index], contents_[bestIndex]);
index = bestIndex;
bestIndex = left (index);
}
else {
break;
}
}
}
private:
BinaryHeap &operator = (BinaryHeap &&rhs) noexcept {
if (this != &rhs) {
contents_ = cr::move (rhs.contents_);
}
return *this;
}
private:
static constexpr size_t parent (size_t index) {
return (index - 1) / 2;
}
static constexpr size_t left (size_t index) {
return (index * 2) + 1;
}
static constexpr size_t right (size_t index) {
return (index * 2) + 2;
}
bool hasLeft (size_t index) const {
return left (index) < contents_.length ();
}
bool hasRight (size_t index) const {
return right (index) < contents_.length ();
}
};
CR_NAMESPACE_END

View file

@ -1,39 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-basic.h>
CR_NAMESPACE_BEGIN
// simple color holder
class Color final {
public:
int32 red = 0, green = 0, blue = 0;
public:
Color (int32 r, int32 g, int32 b) : red (r), green (g), blue (b) { }
explicit Color () = default;
~Color () = default;
public:
void reset () {
red = green = blue = 0;
}
int32 avg () const {
return sum () / (sizeof (Color) / sizeof (int32));
}
int32 sum () const {
return red + green + blue;
}
};
CR_NAMESPACE_END

View file

@ -1,39 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <stdio.h>
#include <crlib/cr-basic.h>
#include <crlib/cr-memory.h>
#include <crlib/cr-array.h>
#include <crlib/cr-deque.h>
#include <crlib/cr-binheap.h>
#include <crlib/cr-files.h>
#include <crlib/cr-lambda.h>
#include <crlib/cr-http.h>
#include <crlib/cr-library.h>
#include <crlib/cr-hashmap.h>
#include <crlib/cr-logger.h>
#include <crlib/cr-math.h>
#include <crlib/cr-vector.h>
#include <crlib/cr-random.h>
#include <crlib/cr-ulz.h>
#include <crlib/cr-color.h>
#include <crlib/cr-detour.h>
CR_NAMESPACE_BEGIN
namespace types {
using StringArray = Array <String>;
using IntArray = Array <int>;
}
using namespace cr::types;
CR_NAMESPACE_END

View file

@ -1,230 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-memory.h>
#include <crlib/cr-twin.h>
CR_NAMESPACE_BEGIN
template <typename T> class Deque : private DenyCopying {
private:
size_t capacity_ {};
T *contents_ {};
Twin <size_t, size_t> index_ {};
private:
size_t pickFrontIndex () {
if (index_.first == 0) {
if (capacity_ && index_.second != capacity_ - 1) {
return capacity_ - 1;
}
}
else if (index_.first - 1 != index_.second) {
return index_.first - 1;
}
extendCapacity ();
return capacity_ - 1;
}
size_t pickRearIndex () {
if (index_.second < index_.first) {
if (index_.second + 1 != index_.first) {
return index_.second + 1;
}
}
else {
if (index_.second + 1 < capacity_) {
return index_.second + 1;
}
if (index_.first != 0) {
return 0;
}
}
extendCapacity ();
return index_.second + 1;
}
void extendCapacity () {
auto capacity = capacity_ ? capacity_ * 2 : 8;
auto contents = Memory::get <T> (sizeof (T) * capacity);
auto transfer = [] (T &dst, T &src) {
Memory::construct (&dst, cr::move (src));
Memory::destruct (&src);
};
if (index_.first < index_.second) {
for (size_t i = 0; i < index_.second - index_.first; ++i) {
transfer (contents[i], contents_[index_.first + i]);
}
index_.second = index_.second - index_.first;
index_.first = 0;
}
else {
for (size_t i = 0; i < capacity_ - index_.first; ++i) {
transfer (contents[i], contents_[index_.first + i]);
}
for (size_t i = 0; i < index_.second; ++i) {
transfer (contents[capacity_ - index_.first + i], contents_[i]);
}
index_.second = index_.second + (capacity_ - index_.first);
index_.first = 0;
}
Memory::release (contents_);
contents_ = contents;
capacity_ = capacity;
}
void destroy () {
auto destruct = [&] (size_t start, size_t end) {
for (size_t i = start; i < end; ++i) {
Memory::destruct (&contents_[i]);
}
};
if (index_.first <= index_.second) {
destruct (index_.first, index_.second);
}
else {
destruct (index_.first, capacity_);
destruct (0, index_.second);
}
Memory::release (contents_);
}
void reset () {
contents_ = nullptr;
capacity_ = 0;
clear ();
}
public:
explicit Deque () : capacity_ (0), contents_ (nullptr)
{ }
Deque (Deque &&rhs) : contents_ (rhs.contents_), capacity_ (rhs.capacity_) {
index_.first (rhs.index_.first);
index_.second (rhs.index_.second);
rhs.reset ();
}
~Deque () {
destroy ();
}
public:
bool empty () const {
return index_.first == index_.second;
}
template <typename ...Args> void emplaceLast (Args &&...args) {
auto rear = pickRearIndex ();
Memory::construct (&contents_[index_.second], cr::forward <Args> (args)...);
index_.second = rear;
}
template <typename ...Args> void emplaceFront (Args &&...args) {
index_.first = pickFrontIndex ();
Memory::construct (&contents_[index_.first], cr::forward <Args> (args)...);
}
void discardFront () {
Memory::destruct (&contents_[index_.first]);
if (index_.first == capacity_ - 1) {
index_.first = 0;
}
else {
index_.first++;
}
}
void discardLast () {
if (index_.second == 0) {
index_.second = capacity_ - 1;
}
else {
index_.second--;
}
Memory::destruct (&contents_[index_.second]);
}
T popFront () {
auto object (front ());
discardFront ();
return object;
}
T popLast () {
auto object (last ());
discardLast ();
return object;
}
public:
const T &front () const {
return contents_[index_.first];
}
const T &last () const {
if (index_.second == 0) {
return contents_[capacity_ - 1];
}
return contents_[index_.second - 1];
}
T &front () {
return contents_[index_.first];
}
T &last () {
if (index_.second == 0) {
return contents_[capacity_ - 1];
}
return contents_[index_.second - 1];
}
size_t length () const {
if (index_.first == index_.second) {
return 0;
}
return index_.first < index_.second ? index_.second - index_.first : index_.second + (capacity_ - index_.first);
}
void clear () {
index_.first = 0;
index_.second = 0;
}
public:
Deque &operator = (Deque &&rhs) {
destroy ();
contents_ = rhs.contents_;
capacity_ = rhs.capacity_;
index_.first = rhs.index_.first;
index_.second = rhs.index_.second;
rhs.reset ();
return *this;
}
};
CR_NAMESPACE_END

View file

@ -1,249 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-basic.h>
#if !defined (CR_WINDOWS)
# include <sys/mman.h>
# include <pthread.h>
#endif
CR_NAMESPACE_BEGIN
// simple wrapper for critical sections
class CriticalSection final : public DenyCopying {
private:
#if defined (CR_WINDOWS)
CRITICAL_SECTION cs_;
#else
pthread_mutex_t mutex_;
#endif
public:
CriticalSection () {
#if defined (CR_WINDOWS)
InitializeCriticalSection (&cs_);
#else
pthread_mutex_init (&mutex_, nullptr);
#endif
}
~CriticalSection () {
#if defined (CR_WINDOWS)
DeleteCriticalSection (&cs_);
#else
pthread_mutex_destroy (&mutex_);
#endif
}
void lock () {
#if defined (CR_WINDOWS)
EnterCriticalSection (&cs_);
#else
pthread_mutex_lock (&mutex_);
#endif
}
void unlock () {
#if defined (CR_WINDOWS)
LeaveCriticalSection (&cs_);
#else
pthread_mutex_unlock (&mutex_);
#endif
}
};
// simple autolock wrapper
class AutoLock final : public DenyCopying {
private:
CriticalSection *cs_;
public:
AutoLock (CriticalSection *cs) : cs_ (cs) {
cs_->lock ();
}
~AutoLock () {
cs_->unlock ();
}
};
// simple detour class for x86/x64
template <typename T> class Detour final : public DenyCopying {
private:
enum : uint32 {
PtrSize = sizeof (void *),
#if defined (CR_ARCH_X64)
Offset = 2
#else
Offset = 1
#endif
};
#if defined (CR_ARCH_X64)
using uintptr = uint64;
#else
using uintptr = uint32;
#endif
private:
CriticalSection cs_;
void *original_ = nullptr;
void *detour_ = nullptr;
Array <uint8> savedBytes_ { };
Array <uint8> jmpBuffer_
#ifdef CR_ARCH_X64
{ 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0 };
#else
{ 0xb8, 0x00, 0x00, 0x00, 0x00, 0xff, 0xe0 };
#endif
#if !defined (CR_WINDOWS)
unsigned long pageSize_ { 0 };
uintptr pageStart_ { 0 };
#endif
bool overwritten_ { false };
private:
bool overwriteMemory (const Array <uint8> &to, const bool overwritten) noexcept {
overwritten_ = overwritten;
AutoLock lock (&cs_);
#if defined (CR_WINDOWS)
unsigned long oldProtect {};
if (VirtualProtect (original_, to.length (), PAGE_EXECUTE_READWRITE, &oldProtect)) {
memcpy (original_, to.data (), to.length ());
// restore protection
return VirtualProtect (original_, to.length (), oldProtect, &oldProtect);
}
#else
if (mprotect (reinterpret_cast <void *> (pageStart_), pageSize_, PROT_READ | PROT_WRITE | PROT_EXEC) != -1) {
memcpy (original_, to.data (), to.length ());
// restore protection
return mprotect (reinterpret_cast <void *> (pageStart_), pageSize_, PROT_READ | PROT_EXEC) != -1;
}
#endif
return false;
}
public:
Detour () = default;
Detour (StringRef module, StringRef name, T *address) {
initialize (module, name, address);
}
~Detour () {
restore ();
original_ = nullptr;
detour_ = nullptr;
}
private:
class DetourSwitch final {
private:
Detour <T> *detour_;
public:
DetourSwitch (Detour *detour) : detour_ (detour) {
detour_->restore ();
}
~DetourSwitch () {
detour_->detour ();
}
};
public:
void initialize (StringRef module, StringRef name, T *address) {
savedBytes_.resize (jmpBuffer_.length ());
#if !defined (CR_WINDOWS)
(void) module;
(void) name;
auto ptr = reinterpret_cast <uint8 *> (address);
while (*reinterpret_cast <uint16 *> (ptr) == 0x25ff) {
ptr = **reinterpret_cast <uint8 ***> (ptr + 2);
}
original_ = ptr;
pageSize_ = static_cast <unsigned long> (sysconf (_SC_PAGE_SIZE));
#else
auto handle = GetModuleHandleA (module.chars ());
if (!handle) {
original_ = reinterpret_cast <void *> (address);
return;
}
original_ = reinterpret_cast <void *> (GetProcAddress (handle, name.chars ()));
if (!original_) {
original_ = reinterpret_cast <void *> (address);
return;
}
#endif
}
void install (void *detour, const bool enable = false) {
if (!original_) {
return;
}
detour_ = detour;
#if !defined (CR_WINDOWS)
pageStart_ = reinterpret_cast <uintptr> (original_) & -pageSize_;
#endif
memcpy (savedBytes_.data (), original_, savedBytes_.length ());
memcpy (reinterpret_cast <void *> (reinterpret_cast <uintptr> (jmpBuffer_.data ()) + Offset), &detour_, PtrSize);
if (enable) {
this->detour ();
}
}
bool valid () const {
return original_ && detour_;
}
bool detoured () const {
return overwritten_;
}
bool detour () {
if (!valid ()) {
return false;
}
return overwriteMemory (jmpBuffer_, true);
}
bool restore () {
if (!valid ()) {
return false;
}
return overwriteMemory (savedBytes_, false);
}
template <typename... Args > decltype (auto) operator () (Args &&...args) {
DetourSwitch sw (this);
return reinterpret_cast <T *> (original_) (args...);
}
};
CR_NAMESPACE_END

View file

@ -1,389 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <stdio.h>
#include <crlib/cr-string.h>
#include <crlib/cr-lambda.h>
CR_NAMESPACE_BEGIN
// simple stdio file wrapper
class File final : private DenyCopying {
private:
FILE *handle_ = nullptr;
size_t length_ {};
public:
explicit File () = default;
File (StringRef file, StringRef mode = "rt") {
open (file, mode);
}
~File () {
close ();
}
public:
bool open (StringRef file, StringRef mode) {
if (!openFile (file, mode)) {
return false;
}
fseek (handle_, 0L, SEEK_END);
length_ = ftell (handle_);
fseek (handle_, 0L, SEEK_SET);
return true;
}
void close () {
if (handle_ != nullptr) {
fclose (handle_);
handle_ = nullptr;
}
length_ = 0;
}
bool eof () const {
return !!feof (handle_);
}
bool flush () const {
return !!fflush (handle_);
}
int get () const {
return fgetc (handle_);
}
char *getString (char *buffer, int count) const {
return fgets (buffer, count, handle_);
}
bool getLine (String &line) {
int ch = 0;
SmallArray <char> data (255);
line.clear ();
while ((ch = get ()) != EOF && !eof ()) {
data.push (static_cast <char> (ch));
if (ch == '\n') {
break;
}
}
if (!data.empty ()) {
line.assign (data.data (), data.length ());
}
return !line.empty ();
}
template <typename ...Args> size_t puts (const char *fmt, Args &&...args) {
if (!*this) {
return 0;
}
return fputs (strings.format (fmt, cr::forward <Args> (args)...), handle_);
}
bool puts (const char *buffer) {
if (!*this) {
return 0;
}
if (fputs (buffer, handle_) < 0) {
return false;
}
return true;
}
int putChar (int ch) {
return fputc (ch, handle_);
}
size_t read (void *buffer, size_t size, size_t count = 1) {
return fread (buffer, size, count, handle_);
}
size_t write (void *buffer, size_t size, size_t count = 1) {
return fwrite (buffer, size, count, handle_);
}
bool seek (long offset, int origin) {
if (fseek (handle_, offset, origin) != 0) {
return false;
}
return true;
}
void rewind () {
::rewind (handle_);
}
size_t length () const {
return length_;
}
public:
explicit operator bool () const {
return handle_ != nullptr;
}
public:
static inline bool exists (StringRef file) {
File fp;
if (fp.open (file, "rb")) {
fp.close ();
return true;
}
return false;
}
static inline void createPath (const char *path) {
for (auto str = const_cast <char *> (path) + 1; *str; ++str) {
if (*str == '/') {
*str = 0;
plat.createDirectory (path);
*str = '/';
}
}
plat.createDirectory (path);
}
private:
bool openFile (StringRef filename, StringRef mode) {
if (*this) {
close ();
}
#if defined (CR_WINDOWS)
fopen_s (&handle_, filename.chars (), mode.chars ());
#else
handle_ = fopen (filename.chars (), mode.chars ());
#endif
return handle_ != nullptr;
}
};
// wrapper for memory file for loading data into the memory
class MemFileStorage : public Singleton <MemFileStorage> {
private:
using LoadFunction = Lambda <uint8 * (const char *, int *)>;
using FreeFunction = Lambda <void (void *)>;
private:
LoadFunction loadFun_ = nullptr;
FreeFunction freeFun_ = nullptr;
public:
explicit MemFileStorage () = default;
~MemFileStorage () = default;
public:
void initizalize (LoadFunction loader, FreeFunction unloader) {
loadFun_ = cr::move (loader);
freeFun_ = cr::move (unloader);
}
public:
uint8 *load (StringRef file, int *size) {
if (loadFun_) {
return loadFun_ (file.chars (), size);
}
return nullptr;
}
void unload (void *buffer) {
if (freeFun_) {
freeFun_ (buffer);
}
}
public:
static uint8 *defaultLoad (const char *path, int *size) {
File file (path, "rb");
if (!file) {
*size = 0;
return nullptr;
}
*size = static_cast <int> (file.length ());
auto data = Memory::get <uint8> (*size);
file.read (data, *size);
return data;
}
static void defaultUnload (void *buffer) {
Memory::release (buffer);
}
static String loadToString (StringRef filename) {
int32 result = 0;
auto buffer = defaultLoad (filename.chars (), &result);
if (result > 0 && buffer) {
String data (reinterpret_cast <char *> (buffer), result);
defaultUnload (buffer);
return data;
}
return "";
}
};
class MemFile final : public DenyCopying {
private:
enum : char {
Eof = static_cast <char> (-1)
};
private:
uint8 *contents_ = nullptr;
size_t length_ {};
size_t seek_ {};
public:
explicit MemFile () = default;
MemFile (StringRef file) {
open (file);
}
~MemFile () {
close ();
}
public:
bool open (StringRef file) {
length_ = 0;
seek_ = 0;
contents_ = MemFileStorage::instance ().load (file.chars (), reinterpret_cast <int *> (&length_));
if (!contents_) {
return false;
}
return true;
}
void close () {
MemFileStorage::instance ().unload (contents_);
length_ = 0;
seek_ = 0;
contents_ = nullptr;
}
char get () {
if (!contents_ || seek_ >= length_) {
return Eof;
}
return static_cast <char> (contents_[seek_++]);
}
char *getString (char *buffer, size_t count) {
if (!contents_ || seek_ >= length_) {
return nullptr;
}
size_t index = 0;
buffer[0] = 0;
for (; index < count - 1;) {
if (seek_ < length_) {
buffer[index] = contents_[seek_++];
if (buffer[index++] == '\n') {
break;
}
}
else {
break;
}
}
buffer[index] = 0;
return index ? buffer : nullptr;
}
bool getLine (String &line) {
char ch;
SmallArray <char> data (255);
line.clear ();
while ((ch = get ()) != Eof && !eof ()) {
data.push (ch);
if (ch == '\n') {
break;
}
}
if (!data.empty ()) {
line.assign (data.data (), data.length ());
}
return !line.empty ();
}
size_t read (void *buffer, size_t size, size_t count = 1) {
if (!contents_ || length_ <= seek_ || !buffer || !size || !count) {
return 0;
}
size_t blocksRead = size * count <= length_ - seek_ ? size * count : length_ - seek_;
memcpy (buffer, &contents_[seek_], blocksRead);
seek_ += blocksRead;
return blocksRead / size;
}
bool seek (size_t offset, int origin) {
if (!contents_ || seek_ >= length_) {
return false;
}
if (origin == SEEK_SET) {
if (offset >= length_) {
return false;
}
seek_ = offset;
}
else if (origin == SEEK_END) {
if (offset >= length_) {
return false;
}
seek_ = length_ - offset;
}
else {
if (seek_ + offset >= length_) {
return false;
}
seek_ += offset;
}
return true;
}
size_t length () const {
return length_;
}
bool eof () const {
return seek_ >= length_;
}
void rewind () {
seek_ = 0;
}
public:
explicit operator bool () const {
return !!contents_ && length_ > 0;
}
};
CR_NAMESPACE_END

View file

@ -1,236 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-basic.h>
#include <crlib/cr-array.h>
#include <crlib/cr-string.h>
#include <crlib/cr-twin.h>
CR_NAMESPACE_BEGIN
template <typename T> struct Hash;
template <> struct Hash <String> {
uint32 operator () (const String &key) const noexcept {
return key.hash ();
}
};
template <> struct Hash <StringRef> {
uint32 operator () (const StringRef &key) const noexcept {
return key.hash ();
}
};
template <> struct Hash <const char *> {
uint32 operator () (const char *key) const noexcept {
return StringRef::fnv1a32 (key);
}
};
template <> struct Hash <int32> {
uint32 operator () (int32 key) const noexcept {
auto result = static_cast <uint32> (key);
result = ((result >> 16) ^ result) * 0x119de1f3;
result = ((result >> 16) ^ result) * 0x119de1f3;
result = (result >> 16) ^ result;
return result;
}
};
template <typename T> struct EmptyHash {
uint32 operator () (T key) const noexcept {
return static_cast <uint32> (key);
}
};
namespace detail {
template <typename K, typename V> struct HashEntry final : DenyCopying {
public:
K key {};
V value {};
bool used { false };
public:
HashEntry () = default;
~HashEntry () = default;
public:
HashEntry (HashEntry &&rhs) noexcept : used (rhs.used), key (cr::move (rhs.key)), value (cr::move (rhs.value))
{ }
public:
HashEntry &operator = (HashEntry &&rhs) noexcept {
if (this != &rhs) {
key = cr::move (rhs.key);
value = cr::move (rhs.value);
used = rhs.used;
}
return *this;
}
};
}
template <typename K, typename V, typename H = Hash <K>> class HashMap final : public DenyCopying {
public:
using Entries = detail::HashEntry <K, V> [];
private:
size_t capacity_ {};
size_t length_ {};
H hash_;
UniquePtr <Entries> contents_;
public:
explicit HashMap (const size_t capacity = 3) : capacity_ (capacity), length_ (0) {
contents_ = cr::makeUnique <Entries> (capacity);
}
HashMap (HashMap &&rhs) noexcept : contents_ (cr::move (rhs.contents_)), hash_ (cr::move (rhs.hash_)), capacity_ (rhs.capacity_), length_ (rhs.length_)
{ }
~HashMap () = default;
private:
size_t getIndex (const K &key, size_t length) const {
return hash_ (key) % length;
}
void rehash (size_t targetCapacity) {
if (length_ + targetCapacity < capacity_) {
return;
}
auto capacity = capacity_ ? capacity_ : 3;
while (length_ + targetCapacity > capacity) {
capacity *= 2;
}
auto contents = cr::makeUnique <Entries> (capacity);
for (size_t i = 0; i < capacity_; ++i) {
if (contents_[i].used) {
auto result = put (contents_[i].key, contents, capacity);
contents[result.second].value = cr::move (contents_[i].value);
}
}
contents_ = cr::move (contents);
capacity_ = capacity;
}
Twin <bool, size_t> put (const K &key, UniquePtr <Entries> &contents, const size_t capacity) {
size_t index = getIndex (key, capacity);
for (size_t i = 0; i < capacity; ++i) {
if (!contents[index].used) {
contents[index].key = key;
contents[index].used = true;
return { true, index };
}
if (contents[index].key == key) {
return { false, index };
}
index++;
if (index == capacity) {
index = 0;
}
}
return { false, 0 };
}
public:
bool empty () const {
return !length_;
}
size_t length () const {
return length_;
}
bool has (const K &key) const {
if (empty ()) {
return false;
}
size_t index = getIndex (key, capacity_);
for (size_t i = 0; i < capacity_; ++i) {
if (contents_[index].used && contents_[index].key == key) {
return true;
}
if (++index == capacity_) {
break;
}
}
return false;
}
void erase (const K &key) {
size_t index = getIndex (key, capacity_);
for (size_t i = 0; i < capacity_; ++i) {
if (contents_[index].used && contents_[index].key == key) {
contents_[index].used = false;
--length_;
break;
}
if (++index == capacity_) {
break;
}
}
}
void clear () {
length_ = 0;
for (size_t i = 0; i < capacity_; ++i) {
contents_[i].used = false;
}
rehash (0);
}
void foreach (Lambda <void (const K &, const V &)> callback) {
for (size_t i = 0; i < capacity_; ++i) {
if (contents_[i].used) {
callback (contents_[i].key, contents_[i].value);
}
}
}
public:
V &operator [] (const K &key) {
if (length_ >= capacity_) {
rehash (length_ << 1);
}
auto result = put (key, contents_, capacity_);
if (result.first) {
++length_;
}
return contents_[result.second].value;
}
HashMap &operator = (HashMap &&rhs) noexcept {
if (this != &rhs) {
contents_ = cr::move (rhs.contents_);
hash_ = cr::move (rhs.hash_);
length_ = rhs.length_;
capacity_ = rhs.capacity_;
}
return *this;
}
};
CR_NAMESPACE_END

View file

@ -1,515 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <stdio.h>
#include <crlib/cr-string.h>
#include <crlib/cr-files.h>
#include <crlib/cr-logger.h>
#include <crlib/cr-twin.h>
#include <crlib/cr-platform.h>
#include <crlib/cr-uniqueptr.h>
#include <crlib/cr-random.h>
#if defined (CR_LINUX) || defined (CR_OSX)
# include <netinet/in.h>
# include <sys/socket.h>
# include <sys/types.h>
# include <sys/uio.h>
# include <arpa/inet.h>
# include <unistd.h>
# include <errno.h>
# include <netdb.h>
# include <fcntl.h>
#elif defined (CR_WINDOWS)
# include <winsock2.h>
# include <ws2tcpip.h>
#endif
// status codes for http client
CR_DECLARE_SCOPED_ENUM (HttpClientResult,
Continue = 100,
SwitchingProtocol = 101,
Processing = 102,
EarlyHints = 103,
Ok = 200,
Created = 201,
Accepted = 202,
NonAuthoritativeInformation = 203,
NoContent = 204,
ResetContent = 205,
PartialContent = 206,
MultiStatus = 207,
AlreadyReported = 208,
ImUsed = 226,
MultipleChoice = 300,
MovedPermanently = 301,
Found = 302,
SeeOther = 303,
NotModified = 304,
UseProxy = 305,
TemporaryRedirect = 307,
PermanentRedirect = 308,
BadRequest = 400,
Unauthorized = 401,
PaymentRequired = 402,
Forbidden = 403,
NotFound = 404,
MethodNotAllowed = 405,
NotAcceptable = 406,
ProxyAuthenticationRequired = 407,
RequestTimeout = 408,
Conflict = 409,
Gone = 410,
LengthRequired = 411,
PreconditionFailed = 412,
PayloadTooLarge = 413,
UriTooLong = 414,
UnsupportedMediaType = 415,
RangeNotSatisfiable = 416,
ExpectationFailed = 417,
ImaTeapot = 418,
MisdirectedRequest = 421,
UnprocessableEntity = 422,
Locked = 423,
FailedDependency = 424,
TooEarly = 425,
UpgradeRequired = 426,
PreconditionRequired = 428,
TooManyRequests = 429,
RequestHeaderFieldsTooLarge = 431,
UnavailableForLegalReasons = 451,
InternalServerError = 500,
NotImplemented = 501,
BadGateway = 502,
ServiceUnavailable = 503,
GatewayTimeout = 504,
HttpVersionNotSupported = 505,
VariantAlsoNegotiates = 506,
InsufficientStorage = 507,
LoopDetected = 508,
NotExtended = 510,
NetworkAuthenticationRequired = 511,
SocketError = -1,
ConnectError = -2,
HttpOnly = -3,
Undefined = -4,
NoLocalFile = -5,
LocalFileExists = -6
)
CR_NAMESPACE_BEGIN
namespace detail {
// simple http uri omitting query-string and port
struct HttpUri {
String path, protocol, host;
public:
static HttpUri parse (StringRef uri) {
HttpUri result;
if (uri.empty ()) {
return result;
}
size_t protocol = uri.find ("://");
if (protocol != String::InvalidIndex) {
result.protocol = uri.substr (0, protocol);
size_t hostIndex = uri.find ("/", protocol + 3);
if (hostIndex != String::InvalidIndex) {
result.path = uri.substr (hostIndex + 1);
result.host = uri.substr (protocol + 3, hostIndex - protocol - 3);
return result;
}
}
return result;
}
};
struct SocketInit {
public:
static void start () {
#if defined(CR_WINDOWS)
WSADATA wsa;
if (WSAStartup (MAKEWORD (2, 2), &wsa) != 0) {
logger.error ("Unable to inialize sockets.");
}
#endif
}
};
}
class Socket final : public DenyCopying {
private:
int32 socket_;
uint32 timeout_;
public:
Socket () : socket_ (-1), timeout_ (2)
{ }
~Socket () {
disconnect ();
}
public:
bool connect (StringRef hostname) {
addrinfo hints {}, *result = nullptr;
plat.bzero (&hints, sizeof (hints));
constexpr auto NumericServ = 0x00000008;
hints.ai_flags = NumericServ;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo (hostname.chars (), "80", &hints, &result) != 0) {
return false;
}
socket_ = static_cast <int> (socket (result->ai_family, result->ai_socktype, 0));
if (socket_ < 0) {
freeaddrinfo (result);
return false;
}
auto getTimeouts = [&]() -> Twin <char *, int32> {
#if defined (CR_WINDOWS)
DWORD tv = timeout_ * 1000;
#else
timeval tv { static_cast <time_t> (timeout_), 0 };
#endif
return { reinterpret_cast <char *> (&tv), static_cast <int32> (sizeof (tv)) };
};
auto timeouts = getTimeouts ();
if (setsockopt (socket_, SOL_SOCKET, SO_RCVTIMEO, timeouts.first, timeouts.second) == -1) {
logger.message ("Unable to set SO_RCVTIMEO.");
}
if (setsockopt (socket_, SOL_SOCKET, SO_SNDTIMEO, timeouts.first, timeouts.second) == -1) {
logger.message ("Unable to set SO_SNDTIMEO.");
}
if (::connect (socket_, result->ai_addr, static_cast <int32> (result->ai_addrlen)) == -1) {
disconnect ();
freeaddrinfo (result);
return false;
}
freeaddrinfo (result);
return true;
}
void setTimeout (uint32 timeout) {
timeout_ = timeout;
}
void disconnect () {
#if defined(CR_WINDOWS)
if (socket_ != -1) {
closesocket (socket_);
}
#else
if (socket_ != -1)
close (socket_);
#endif
}
public:
template <typename U> int32 send (const U *buffer, int32 length) const {
return ::send (socket_, reinterpret_cast <const char *> (buffer), length, 0);
}
template <typename U> int32 recv (U *buffer, int32 length) {
return ::recv (socket_, reinterpret_cast <char *> (buffer), length, 0);
}
public:
static int32 CR_STDCALL sendto (int socket, const void *message, size_t length, int flags, const struct sockaddr *dest, int32 destLength) {
#if defined (CR_WINDOWS)
WSABUF buffer = { static_cast <ULONG> (length), const_cast <char *> (reinterpret_cast <const char *> (message)) };
DWORD sendLength = 0;
if (WSASendTo (socket, &buffer, 1, &sendLength, flags, dest, destLength, NULL, NULL) == SOCKET_ERROR) {
errno = WSAGetLastError ();
return -1;
}
return static_cast <int32> (sendLength);
#else
iovec iov = { const_cast <void *> (message), length };
msghdr msg {};
msg.msg_name = reinterpret_cast <void *> (const_cast <struct sockaddr *> (dest));
msg.msg_namelen = destLength;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
return sendmsg (socket, &msg, flags);
#endif
}
};
// simple http client for downloading/uploading files only
class HttpClient final : public Singleton <HttpClient> {
private:
enum : int32 {
MaxReceiveErrors = 12,
DefaultSocketTimeout = 32
};
private:
String userAgent_ = "crlib";
HttpClientResult statusCode_ = HttpClientResult::Undefined;
int32 chunkSize_ = 4096;
bool initialized_ = false;
public:
HttpClient () = default;
~HttpClient () = default;
private:
HttpClientResult parseResponseHeader (Socket *socket, uint8 *buffer) {
bool isFinished = false;
int32 pos = 0, symbols = 0, errors = 0;
// prase response header
while (!isFinished && pos < chunkSize_) {
if (socket->recv (&buffer[pos], 1) < 1) {
if (++errors > MaxReceiveErrors) {
isFinished = true;
}
else {
continue;
}
}
switch (buffer[pos]) {
case '\r':
break;
case '\n':
isFinished = (symbols == 0);
symbols = 0;
break;
default:
++symbols;
break;
}
++pos;
}
String response { reinterpret_cast <const char *> (buffer) };
size_t responseCodeStart = response.find ("HTTP/1.1");
if (responseCodeStart != String::InvalidIndex) {
String respCode = response.substr (responseCodeStart + 9, 3);
respCode.trim ();
return static_cast <HttpClientResult> (respCode.int_ ());
}
return HttpClientResult::NotFound;
}
public:
void startup () {
detail::SocketInit::start ();
initialized_ = true;
}
// simple blocked download
bool downloadFile (StringRef url, StringRef localPath, int32 timeout = DefaultSocketTimeout) {
if (plat.win && !initialized_) {
plat.abort ("Sockets not initialized.");
}
if (File::exists (localPath)) {
statusCode_ = HttpClientResult::LocalFileExists;
return false;
}
auto uri = detail::HttpUri::parse (url);
auto socket = cr::makeUnique <Socket> ();
// no https...
if (uri.protocol == "https") {
statusCode_ = HttpClientResult::HttpOnly;
return false;
}
socket->setTimeout (timeout);
// unable to connect...
if (!socket->connect (uri.host)) {
statusCode_ = HttpClientResult::ConnectError;
return false;
}
String request;
request.appendf ("GET /%s HTTP/1.1\r\n", uri.path);
request.append ("Accept: */*\r\n");
request.append ("Connection: close\r\n");
request.append ("Keep-Alive: 115\r\n");
request.appendf ("User-Agent: %s\r\n", userAgent_);
request.appendf ("Host: %s\r\n\r\n", uri.host);
if (socket->send (request.chars (), static_cast <int32> (request.length ())) < 1) {
statusCode_ = HttpClientResult::SocketError;
return false;
}
SmallArray <uint8> buffer (chunkSize_);
statusCode_ = parseResponseHeader (socket.get (), buffer.data ());
if (statusCode_ != HttpClientResult::Ok) {
return false;
}
// receive the file
File file (localPath, "wb");
if (!file) {
statusCode_ = HttpClientResult::Undefined;
return false;
}
int32 length = 0;
int32 errors = 0;
for (;;) {
length = socket->recv (buffer.data (), chunkSize_);
if (length > 0) {
file.write (buffer.data (), length);
}
else if (++errors > 12) {
break;
}
}
statusCode_ = HttpClientResult::Ok;
return true;
}
bool uploadFile (StringRef url, StringRef localPath, const int32 timeout = DefaultSocketTimeout) {
if (plat.win && !initialized_) {
plat.abort ("Sockets not initialized.");
}
if (!File::exists (localPath)) {
statusCode_ = HttpClientResult::NoLocalFile;
return false;
}
auto uri = detail::HttpUri::parse (url);
auto socket = cr::makeUnique <Socket> ();
// no https...
if (uri.protocol == "https") {
statusCode_ = HttpClientResult::HttpOnly;
return false;
}
socket->setTimeout (timeout);
// unable to connect...
if (!socket->connect (uri.host)) {
statusCode_ = HttpClientResult::ConnectError;
return false;
}
// receive the file
File file (localPath, "rb");
if (!file) {
statusCode_ = HttpClientResult::Undefined;
return false;
}
String boundaryName = localPath;
size_t boundarySlash = localPath.findLastOf ("\\/");
if (boundarySlash != String::InvalidIndex) {
boundaryName = localPath.substr (boundarySlash + 1);
}
StringRef boundaryLine = strings.format ("---crlib_upload_boundary_%d%d%d%d", rg.get (0, 9), rg.get (0, 9), rg.get (0, 9), rg.get (0, 9));
String request, start, end;
start.appendf ("--%s\r\n", boundaryLine);
start.appendf ("Content-Disposition: form-data; name='file'; filename='%s'\r\n", boundaryName);
start.append ("Content-Type: application/octet-stream\r\n\r\n");
end.appendf ("\r\n--%s--\r\n\r\n", boundaryLine);
request.appendf ("POST /%s HTTP/1.1\r\n", uri.path);
request.appendf ("Host: %s\r\n", uri.host);
request.appendf ("User-Agent: %s\r\n", userAgent_);
request.appendf ("Content-Type: multipart/form-data; boundary=%s\r\n", boundaryLine);
request.appendf ("Content-Length: %d\r\n\r\n", file.length () + start.length () + end.length ());
// send the main request
if (socket->send (request.chars (), static_cast <int32> (request.length ())) < 1) {
statusCode_ = HttpClientResult::SocketError;
return false;
}
// send boundary start
if (socket->send (start.chars (), static_cast <int32> (start.length ())) < 1) {
statusCode_ = HttpClientResult::SocketError;
return false;
}
SmallArray <uint8> buffer (chunkSize_);
int32 length = 0;
for (;;) {
length = static_cast <int32> (file.read (buffer.data (), 1, chunkSize_));
if (length > 0) {
socket->send (buffer.data (), length);
}
else {
break;
}
}
// send boundary end
if (socket->send (end.chars (), static_cast <int32> (end.length ())) < 1) {
statusCode_ = HttpClientResult::SocketError;
return false;
}
statusCode_ = parseResponseHeader (socket.get (), buffer.data ());
return statusCode_ == HttpClientResult::Ok;
}
public:
void setUserAgent (StringRef ua) {
userAgent_ = ua;
}
HttpClientResult getLastStatusCode () {
return statusCode_;
}
void setChunkSize (int32 chunkSize) {
chunkSize_ = chunkSize;
}
};
// expose global http client
CR_EXPOSE_GLOBAL_SINGLETON (HttpClient, http);
CR_NAMESPACE_END

View file

@ -1,169 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-memory.h>
#include <crlib/cr-uniqueptr.h>
CR_NAMESPACE_BEGIN
template <typename> class Lambda;
template <typename R, typename ...Args> class Lambda <R (Args...)> {
private:
enum : uint32 {
LamdaSmallBufferLength = sizeof (void *) * 16
};
private:
class LambdaFunctorWrapper {
public:
LambdaFunctorWrapper () = default;
virtual ~LambdaFunctorWrapper () = default;
public:
virtual void move (uint8 *to) = 0;
virtual void small (uint8 *to) const = 0;
virtual R invoke (Args &&...) = 0;
virtual UniquePtr <LambdaFunctorWrapper> clone () const = 0;
};
template <typename T> class LambdaFunctor : public LambdaFunctorWrapper {
private:
T callable_;
public:
LambdaFunctor (const T &callable) : LambdaFunctorWrapper (), callable_ (callable)
{ }
LambdaFunctor (T &&callable) : LambdaFunctorWrapper (), callable_ (cr::move (callable))
{ }
~LambdaFunctor () override = default;
public:
void move (uint8 *to) override {
new (to) LambdaFunctor <T> (cr::move (callable_));
}
void small (uint8 *to) const override {
new (to) LambdaFunctor <T> (callable_);
}
R invoke (Args &&... args) override {
return callable_ (cr::forward <Args> (args)...);
}
UniquePtr <LambdaFunctorWrapper> clone () const override {
return makeUnique <LambdaFunctor <T>> (callable_);
}
};
union {
UniquePtr <LambdaFunctorWrapper> functor_;
uint8 small_[LamdaSmallBufferLength] { };
};
bool ssoObject_ = false;
private:
void destroy () {
if (ssoObject_) {
reinterpret_cast <LambdaFunctorWrapper *> (small_)->~LambdaFunctorWrapper ();
}
else {
functor_.reset ();
}
}
void swap (Lambda &rhs) noexcept {
cr::swap (rhs, *this);
}
public:
explicit Lambda () noexcept : Lambda (nullptr)
{ }
Lambda (decltype (nullptr)) noexcept : functor_ (nullptr), ssoObject_ (false)
{ }
Lambda (const Lambda &rhs) {
if (rhs.ssoObject_) {
reinterpret_cast <const LambdaFunctorWrapper *> (rhs.small_)->small (small_);
}
else {
new (small_) UniquePtr <LambdaFunctorWrapper> (rhs.functor_->clone ());
}
ssoObject_ = rhs.ssoObject_;
}
Lambda (Lambda &&rhs) noexcept {
if (rhs.ssoObject_) {
reinterpret_cast <LambdaFunctorWrapper *> (rhs.small_)->move (small_);
new (rhs.small_) UniquePtr <LambdaFunctorWrapper> (nullptr);
}
else {
new (small_) UniquePtr <LambdaFunctorWrapper> (cr::move (rhs.functor_));
}
ssoObject_ = rhs.ssoObject_;
rhs.ssoObject_ = false;
}
template <typename F> Lambda (F function) {
if (cr::fix (sizeof (function) > LamdaSmallBufferLength)) {
ssoObject_ = false;
new (small_) UniquePtr <LambdaFunctorWrapper> (makeUnique <LambdaFunctor <F>> (cr::move (function)));
}
else {
ssoObject_ = true;
new (small_) LambdaFunctor <F> (cr::move (function));
}
}
~Lambda () {
destroy ();
}
public:
Lambda &operator = (const Lambda &rhs) {
destroy ();
Lambda tmp (rhs);
swap (tmp);
return *this;
}
Lambda &operator = (Lambda &&rhs) noexcept {
destroy ();
if (rhs.ssoObject_) {
reinterpret_cast <LambdaFunctorWrapper *> (rhs.small_)->move (small_);
new (rhs.small_) UniquePtr <LambdaFunctorWrapper> (nullptr);
}
else {
new (small_) UniquePtr <LambdaFunctorWrapper> (cr::move (rhs.functor_));
}
ssoObject_ = rhs.ssoObject_;
rhs.ssoObject_ = false;
return *this;
}
explicit operator bool () const noexcept {
return ssoObject_ || !!functor_;
}
public:
R operator () (Args ...args) {
return ssoObject_ ? reinterpret_cast <LambdaFunctorWrapper *> (small_)->invoke (cr::forward <Args> (args)...) : functor_->invoke (cr::forward <Args> (args)...);
}
};
CR_NAMESPACE_END

View file

@ -1,132 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-basic.h>
#include <crlib/cr-string.h>
#if defined (CR_LINUX) || defined (CR_OSX)
# include <dlfcn.h>
# include <errno.h>
# include <fcntl.h>
# include <sys/stat.h>
# include <unistd.h>
#endif
CR_NAMESPACE_BEGIN
// handling dynamic library loading
class SharedLibrary final : public DenyCopying {
public:
using Handle = void *;
private:
Handle handle_ = nullptr;
bool unloadable_ = true;
public:
explicit SharedLibrary () = default;
SharedLibrary (StringRef file) {
if (file.empty ()) {
return;
}
load (file);
}
~SharedLibrary () {
unload ();
}
public:
bool load (StringRef file, bool unloadable = true) noexcept {
if (*this) {
unload ();
}
unloadable_ = unloadable;
#if defined (CR_WINDOWS)
handle_ = LoadLibraryA (file.chars ());
#else
auto loadFlags = RTLD_NOW | RTLD_LOCAL;
#if defined (CR_LINUX) && !defined (__SANITIZE_ADDRESS__)
loadFlags |= RTLD_DEEPBIND;
#endif
handle_ = dlopen (file.chars (), loadFlags);
#endif
return handle_ != nullptr;
}
bool locate (Handle address) {
unloadable_ = false;
#if defined (CR_WINDOWS)
MEMORY_BASIC_INFORMATION mbi;
if (!VirtualQuery (address, &mbi, sizeof (mbi))) {
return false;
}
if (mbi.State != MEM_COMMIT) {
return false;
}
handle_ = reinterpret_cast <Handle> (mbi.AllocationBase);
#else
Dl_info dli;
plat.bzero (&dli, sizeof (dli));
if (dladdr (address, &dli)) {
return load (dli.dli_fname, false);
}
#endif
return handle_ != nullptr;
}
void unload () noexcept {
if (!handle_ || !unloadable_) {
return;
}
#if defined (CR_WINDOWS)
FreeLibrary (static_cast <HMODULE> (handle_));
#else
dlclose (handle_);
#endif
handle_ = nullptr;
}
template <typename R> R resolve (const char *function) const {
if (!*this) {
return nullptr;
}
return SharedLibrary::getSymbol <R> (handle (), function);
}
Handle handle () const {
return handle_;
}
public:
explicit operator bool () const {
return handle_ != nullptr;
}
public:
template <typename R> static inline R CR_STDCALL getSymbol (Handle module, const char *function) {
return reinterpret_cast <R> (
#if defined (CR_WINDOWS)
GetProcAddress (static_cast <HMODULE> (module), function)
#else
dlsym (module, function)
#endif
);
}
};
CR_NAMESPACE_END

View file

@ -1,112 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <time.h>
#include <crlib/cr-files.h>
#include <crlib/cr-lambda.h>
CR_NAMESPACE_BEGIN
class SimpleLogger final : public Singleton <SimpleLogger> {
public:
using PrintFunction = Lambda <void (const char *)>;
private:
String filename_;
PrintFunction printFun_;
public:
explicit SimpleLogger () = default;
~SimpleLogger () = default;
public:
class LogFile final {
private:
File handle_;
public:
LogFile (StringRef filename) {
handle_.open (filename, "at");
}
~LogFile () {
handle_.close ();
}
public:
void print (StringRef msg) {
if (!handle_) {
return;
}
handle_.puts (msg.chars ());
}
};
private:
void logToFile (const char *level, const char *msg) {
time_t ticks = time (&ticks);
tm timeinfo {};
#if defined (CR_WINDOWS)
localtime_s (&timeinfo, &ticks);
#else
localtime_r (&ticks, &timeinfo);
#endif
auto timebuf = strings.chars ();
strftime (timebuf, StringBuffer::StaticBufferSize, "%Y-%m-%d %H:%M:%S", &timeinfo);
LogFile lf (filename_);
lf.print (strings.format ("%s (%s): %s\n", timebuf, level, msg));
}
public:
template <typename ...Args> void fatal (const char *fmt, Args &&...args) {
auto msg = strings.format (fmt, cr::forward <Args> (args)...);
logToFile ("FATAL", msg);
if (printFun_) {
printFun_ (msg);
}
plat.abort (msg);
}
template <typename ...Args> void error (const char *fmt, Args &&...args) {
auto msg = strings.format (fmt, cr::forward <Args> (args)...);
logToFile ("ERROR", msg);
if (printFun_) {
printFun_ (msg);
}
}
template <typename ...Args> void message (const char *fmt, Args &&...args) {
auto msg = strings.format (fmt, cr::forward <Args> (args)...);
logToFile ("INFO", msg);
if (printFun_) {
printFun_ (msg);
}
}
public:
void initialize (StringRef filename, PrintFunction printFunction) {
printFun_ = cr::move (printFunction);
filename_ = filename;
}
};
// expose global instance
CR_EXPOSE_GLOBAL_SINGLETON (SimpleLogger, logger);
CR_NAMESPACE_END

View file

@ -1,135 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-basic.h>
#if defined (CR_HAS_SSE)
# include <pmmintrin.h>
#endif
#include <math.h>
CR_NAMESPACE_BEGIN
constexpr float kFloatEpsilon = 0.01f;
constexpr float kFloatEqualEpsilon = 0.001f;
constexpr float kFloatCmpEpsilon = 1.192092896e-07f;
constexpr float kMathPi = 3.141592653589793115997963468544185161590576171875f;
constexpr float kMathPiHalf = kMathPi * 0.5f;
constexpr float kDegreeToRadians = kMathPi / 180.0f;
constexpr float kRadiansToDegree = 180.0f / kMathPi;
constexpr bool fzero (const float e) {
return cr::abs (e) < kFloatEpsilon;
}
constexpr bool fequal (const float a, const float b) {
return cr:: abs (a - b) < kFloatEqualEpsilon;
}
constexpr float rad2deg (const float r) {
return r * kRadiansToDegree;
}
constexpr float deg2rad (const float d) {
return d * kDegreeToRadians;
}
constexpr float modAngles (const float a) {
return 360.0f / 65536.0f * (static_cast <int> (a * (65536.0f / 360.0f)) & 65535);
}
constexpr float normalizeAngles (const float a) {
return 360.0f / 65536.0f * (static_cast <int> ((a + 180.0f) * (65536.0f / 360.0f)) & 65535) - 180.0f;
}
constexpr float anglesDifference (const float a, const float b) {
return normalizeAngles (a - b);
}
inline float sinf (const float value) {
return ::sinf (value);
}
inline float cosf (const float value) {
return ::cosf (value);
}
inline float atanf (const float value) {
return ::atanf (value);
}
inline float atan2f (const float y, const float x) {
return ::atan2f (y, x);
}
inline float powf (const float x, const float y) {
return ::powf (x, y);
}
inline float sqrtf (const float value) {
return ::sqrtf (value);
}
inline float tanf (const float value) {
return ::tanf (value);
}
inline float ceilf (const float value) {
return ::ceilf (value);
}
inline void sincosf (const float x, const float y, const float z, float *sines, float *cosines) {
#if defined (CR_HAS_SSE)
auto set = _mm_set_ps (x, y, z, 0.0f);
auto _mm_sin = [] (__m128 rad) -> __m128 {
static auto pi2 = _mm_set_ps1 (kMathPi * 2);
static auto rp1 = _mm_set_ps1 (4.0f / kMathPi);
static auto rp2 = _mm_set_ps1 (-4.0f / (kMathPi * kMathPi));
static auto val = _mm_cmpnlt_ps (rad, _mm_set_ps1 (kMathPi));
static auto csi = _mm_castsi128_ps (_mm_set1_epi32 (0x80000000));
val = _mm_and_ps (val, pi2);
rad = _mm_sub_ps (rad, val);
val = _mm_cmpngt_ps (rad, _mm_set_ps1 (-kMathPi));
val = _mm_and_ps (val, pi2);
rad = _mm_add_ps (rad, val);
val = _mm_mul_ps (_mm_andnot_ps (csi, rad), rp2);
val = _mm_add_ps (val, rp1);
auto si = _mm_mul_ps (val, rad);
val = _mm_mul_ps (_mm_andnot_ps (csi, si), si);
val = _mm_sub_ps (val, si);
val = _mm_mul_ps (val, _mm_set_ps1 (0.225f));
return _mm_add_ps (val, si);
};
static auto hpi = _mm_set_ps1 (kMathPiHalf);
auto s = _mm_sin (set);
auto c = _mm_sin (_mm_add_ps (set, hpi));
_mm_store_ps (sines, _mm_shuffle_ps (s, s, _MM_SHUFFLE (0, 1, 2, 3)));
_mm_store_ps (cosines, _mm_shuffle_ps (c, c, _MM_SHUFFLE (0, 1, 2, 3)));
#else
sines[0] = cr::sinf (x);
sines[1] = cr::sinf (y);
sines[2] = cr::sinf (z);
cosines[0] = cr::cosf (x);
cosines[1] = cr::cosf (y);
cosines[2] = cr::cosf (z);
#endif
}
CR_NAMESPACE_END

View file

@ -1,52 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-basic.h>
#include <crlib/cr-movable.h>
#include <crlib/cr-platform.h>
// provide placment new to avoid stdc++ <new> header
inline void *operator new (const size_t, void *ptr) noexcept {
return ptr;
}
CR_NAMESPACE_BEGIN
// internal memory manager
class Memory final {
public:
Memory () = default;
~Memory () = default;
public:
template <typename T> static T *get (const size_t length = 1) {
auto memory = reinterpret_cast <T *> (malloc (cr::max <size_t> (1u, length * sizeof (T))));
if (!memory) {
plat.abort ();
}
return memory;
}
template <typename T> static void release (T *memory) {
free (memory);
memory = nullptr;
}
public:
template <typename T, typename ...Args> static void construct (T *memory, Args &&...args) {
new (memory) T (cr::forward <Args> (args)...);
}
template <typename T> static void destruct (T *memory) {
memory->~T ();
}
};
CR_NAMESPACE_END

View file

@ -1,56 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-basic.h>
CR_NAMESPACE_BEGIN
namespace detail {
template <typename T> struct ClearRef {
using Type = T;
};
template <typename T> struct ClearRef <T &> {
using Type = T;
};
template <typename T> struct ClearRef <T &&> {
using Type = T;
};
}
template <typename T> typename detail::ClearRef <T>::Type constexpr &&move (T &&type) noexcept {
return static_cast <typename detail::ClearRef <T>::Type &&> (type);
}
template <typename T> constexpr T &&forward (typename detail::ClearRef <T>::Type &type) noexcept {
return static_cast <T &&> (type);
}
template <typename T> constexpr T &&forward (typename detail::ClearRef <T>::Type &&type) noexcept {
return static_cast <T &&> (type);
}
template <typename T> inline void swap (T &left, T &right) noexcept {
auto temp = cr::move (left);
left = cr::move (right);
right = cr::move (temp);
}
template <typename T, size_t S> inline void swap (T (&left)[S], T (&right)[S]) noexcept {
if (&left == &right) {
return;
}
auto begin = left;
auto end = begin + S;
for (auto temp = right; begin != end; ++begin, ++temp) {
cr::swap (*begin, *temp);
}
}
CR_NAMESPACE_END

View file

@ -1,39 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-memory.h>
#include <crlib/cr-platform.h>
void *operator new (size_t size) {
return cr::Memory::get <void *> (size);
}
void *operator new [] (size_t size) {
return cr::Memory::get <void *> (size);
}
void operator delete (void *ptr) noexcept {
cr::Memory::release (ptr);
}
void operator delete [] (void *ptr) noexcept {
cr::Memory::release (ptr);
}
void operator delete (void *ptr, size_t) noexcept {
cr::Memory::release (ptr);
}
void operator delete [] (void *ptr, size_t) noexcept {
cr::Memory::release (ptr);
}
CR_LINKAGE_C void __cxa_pure_virtual () {
cr::plat.abort ("pure virtual function call");
}

View file

@ -1,301 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
CR_NAMESPACE_BEGIN
// detects the build platform
#if defined(__linux__)
# define CR_LINUX
#elif defined(__APPLE__)
# define CR_OSX
#elif defined(_WIN32)
# define CR_WINDOWS
#endif
#if defined(__ANDROID__)
# define CR_ANDROID
# if defined(LOAD_HARDFP)
# define CR_ANDROID_HARD_FP
# endif
#endif
// detects the compiler
#if defined(_MSC_VER)
# define CR_CXX_MSVC _MSC_VER
#endif
#if defined(__clang__)
# define CR_CXX_CLANG __clang__
#endif
#if defined(__INTEL_COMPILER)
# define CR_CXX_INTEL __INTEL_COMPILER
#endif
#if defined(__GNUC__)
# define CR_CXX_GCC __GNUC__
#endif
// configure macroses
#define CR_LINKAGE_C extern "C"
#if defined(CR_WINDOWS)
# define CR_EXPORT CR_LINKAGE_C __declspec (dllexport)
# define CR_STDCALL __stdcall
#elif defined(CR_LINUX) || defined(CR_OSX)
# define CR_EXPORT CR_LINKAGE_C __attribute__((visibility("default")))
# define CR_STDCALL
#else
# error "Can't configure export macros. Compiler unrecognized."
#endif
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(__amd64) || (defined(_MSC_VER) && defined(_M_X64))
# define CR_ARCH_X64
#elif defined(__i686) || defined(__i686__) || defined(__i386) || defined(__i386__) || defined(i386) || (defined(_MSC_VER) && defined(_M_IX86))
# define CR_ARCH_X86
#endif
#if defined(__arm__)
# define CR_ARCH_ARM
# if defined(__aarch64__)
# define CR_ARCH_ARM64
# endif
#endif
#if (defined(CR_ARCH_X86) || defined(CR_ARCH_X64)) && !defined(CR_DEBUG)
# define CR_HAS_SSE
#endif
#if defined(CR_HAS_SSE)
# if defined (CR_CXX_MSVC)
# define CR_ALIGN16 __declspec (align (16))
# else
# define CR_ALIGN16 __attribute__((aligned(16)))
# endif
#endif
// disable warnings regarding intel compiler
#if defined(CR_CXX_INTEL)
# pragma warning (disable : 3280) // declaration hides member "XXX" (declared at line XX)
# pragma warning (disable : 2415) // variable "XXX" of static storage duration was declared but never referenced
# pragma warning (disable : 873) // function "operator new(size_t={unsigned int}, void *)" has no corresponding operator delete (to be called if an exception is thrown during initialization of an allocated object)
# pragma warning (disable : 383) // value copied to temporary, reference to temporary used
# pragma warning (disable : 11074 11075) // remarks about inlining bla-bla-bla
#endif
// msvc provides us placement new by default
#if defined (CR_CXX_MSVC)
# define __PLACEMENT_NEW_INLINE 1
#endif
// disabled gcc warnings
#if defined (CR_CXX_GCC)
# pragma GCC diagnostic ignored "-Wignored-attributes"
#endif
// avoid linking to GLIBC_2.27
#if defined (CR_LINUX) && !defined (CR_CXX_INTEL)
__asm__ (".symver powf, powf@GLIBC_2.0");
#endif
CR_NAMESPACE_END
#if defined(CR_WINDOWS)
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# include <direct.h>
# if defined (max)
# undef max
# endif
# if defined (min)
# undef min
# endif
#else
# include <unistd.h>
# include <strings.h>
# include <sys/stat.h>
# include <sys/time.h>
#endif
#include <stdio.h>
#include <assert.h>
#include <locale.h>
#include <string.h>
#include <stdarg.h>
#if defined (CR_ANDROID)
# include <android/log.h>
#endif
#include <time.h>
CR_NAMESPACE_BEGIN
// helper struct for platform detection
struct Platform : public Singleton <Platform> {
bool win = false;
bool nix = false;
bool osx = false;
bool android = false;
bool hfp = false;
bool x64 = false;
bool arm = false;
char appName[64] = {};
Platform () {
#if defined(CR_WINDOWS)
win = true;
#endif
#if defined(CR_ANDROID)
android = true;
# if defined (CR_ANDROID_HARD_FP)
hfp = true;
# endif
#endif
#if defined(CR_LINUX)
nix = true;
#endif
#if defined(CR_OSX)
osx = true;
#endif
#if defined(CR_ARCH_X64) || defined(CR_ARCH_ARM64)
x64 = true;
#endif
#if defined(CR_ARCH_ARM)
arm = true;
android = true;
#endif
}
// set the app name
void setAppName (const char *name) {
snprintf (appName, cr::bufsize (appName), "%s", name);
}
// helper platform-dependant functions
template <typename U> bool checkPointer (U *ptr) {
#if defined(CR_WINDOWS)
if (IsBadCodePtr (reinterpret_cast <FARPROC> (ptr))) {
return false;
}
#else
(void) (ptr);
#endif
return true;
}
bool createDirectory (const char *dir) {
int result = 0;
#if defined(CR_WINDOWS)
result = _mkdir (dir);
#else
result = mkdir (dir, 0777);
#endif
return !!result;
}
bool removeFile (const char *dir) {
#if defined(CR_WINDOWS)
_unlink (dir);
#else
unlink (dir);
#endif
return true;
}
bool hasModule (const char *mod) {
#if defined(CR_WINDOWS)
return GetModuleHandleA (mod) != nullptr;
#else
(void) (mod);
return true;
#endif
}
float seconds () {
#if defined(CR_WINDOWS)
LARGE_INTEGER count, freq;
count.QuadPart = 0;
freq.QuadPart = 0;
QueryPerformanceFrequency (&freq);
QueryPerformanceCounter (&count);
return static_cast <float> (count.QuadPart / freq.QuadPart);
#else
timeval tv;
gettimeofday (&tv, nullptr);
static auto startTime = tv.tv_sec;
return static_cast <float> (tv.tv_sec - startTime);
#endif
}
void abort (const char *msg = "OUT OF MEMORY!") noexcept {
fprintf (stderr, "%s\n", msg);
#if defined (CR_ANDROID)
__android_log_write (ANDROID_LOG_ERROR, appName, msg);
#endif
#if defined(CR_WINDOWS)
DestroyWindow (GetForegroundWindow ());
MessageBoxA (GetActiveWindow (), msg, appName, MB_ICONSTOP);
#endif
::abort ();
}
// anologue of memset
template <typename U> void bzero (U *ptr, size_t len) noexcept {
#if defined (CR_WINDOWS)
memset (ptr, 0, len);
#else
auto zeroing = reinterpret_cast <uint8 *> (ptr);
for (size_t i = 0; i < len; ++i) {
zeroing[i] = 0;
}
#endif
}
const char *env (const char *var) {
static char result[256];
bzero (result, sizeof (result));
#if defined(CR_WINDOWS) && !defined(CR_CXX_GCC)
char *buffer = nullptr;
size_t size = 0;
if (_dupenv_s (&buffer, &size, var) == 0 && buffer != nullptr) {
strncpy_s (result, buffer, sizeof (result));
free (buffer);
}
#else
strncpy (result, getenv (var), cr::bufsize (result));
#endif
return result;
}
};
// expose platform singleton
CR_EXPOSE_GLOBAL_SINGLETON (Platform, plat);
CR_NAMESPACE_END

View file

@ -1,71 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-basic.h>
CR_NAMESPACE_BEGIN
// based on: https://github.com/jeudesprits/PSWyhash/blob/master/Sources/CWyhash/include/wyhash.h
class Random : public Singleton <Random> {
private:
uint64 div_ { static_cast <uint64> (1) << 32ull };
uint64 state_ { static_cast <uint64> (time (nullptr)) };
public:
explicit Random () = default;
~Random () = default;
private:
uint64 wyrand64 () {
constexpr uint64 wyp0 = 0xa0761d6478bd642full, wyp1 = 0xe7037ed1a0b428dbull;
state_ += wyp0;
return mul (state_ ^ wyp1, state_);
}
uint32 wyrand32 () {
return static_cast <uint32> (wyrand64 ());
}
private:
uint64_t rotr (uint64 v, uint32 k) {
return (v >> k) | (v << (64 - k));
}
uint64 mul (uint64 a, uint64 b) {
uint64 hh = (a >> 32) * (b >> 32);
uint64 hl = (b >> 32) * static_cast <uint32> (b);
uint64 lh = static_cast <uint32> (a) * (b >> 32);
uint64 ll = static_cast <uint64> (static_cast <double> (a) * static_cast <double> (b));
return rotr (hl, 32) ^ rotr (lh, 32) ^ hh ^ ll;
}
public:
template <typename U, typename Void = void> U get (U, U) = delete;
template <typename Void = void> int32 get (int32 low, int32 high) {
return static_cast <int32> (wyrand32 () * (static_cast <double> (high) - static_cast <double> (low) + 1.0) / div_ + static_cast <double> (low));
}
template <typename Void = void> float get (float low, float high) {
return static_cast <float> (wyrand32 () * (static_cast <double> (high) - static_cast <double> (low)) / (div_ - 1) + static_cast <double> (low));
}
public:
bool chance (int32 limit) {
return get <int32> (0, 100) < limit;
}
};
// expose global random generator
CR_EXPOSE_GLOBAL_SINGLETON (Random, rg);
CR_NAMESPACE_END

File diff suppressed because it is too large Load diff

View file

@ -1,56 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-basic.h>
#include <crlib/cr-movable.h>
CR_NAMESPACE_BEGIN
// simple pair (twin)
template <typename A, typename B> class Twin final {
public:
A first;
B second;
public:
template <typename T, typename U> Twin (T &&a, U &&b) : first (cr::forward <T> (a)), second (cr::forward <U> (b)) { }
template <typename T, typename U> Twin (const Twin <T, U> &rhs) : first (rhs.first), second (rhs.second) { }
template <typename T, typename U> Twin (Twin <T, U> &&rhs) noexcept : first (cr::move (rhs.first)), second (cr::move (rhs.second)) { }
public:
explicit Twin () = default;
~Twin () = default;
public:
template <typename T, typename U> Twin &operator = (const Twin <T, U> &rhs) {
first = rhs.first;
second = rhs.second;
return *this;
}
template <typename T, typename U> Twin &operator = (Twin <T, U> &&rhs) {
first = cr::move (rhs.first);
second = cr::move (rhs.second);
return *this;
}
// specialized operators for binary heap, do not use as it's test only second element
public:
friend bool operator < (const Twin &a, const Twin &b) {
return a.second < b.second;
}
friend bool operator > (const Twin &a, const Twin &b) {
return b.second < a.second;
}
};
CR_NAMESPACE_END

View file

@ -1,312 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-array.h>
CR_NAMESPACE_BEGIN
// see https://github.com/encode84/ulz/
class ULZ final : public Singleton <ULZ> {
public:
enum : int32 {
Excess = 16,
UncompressFailure = -1
};
private:
enum : int32 {
WindowBits = 17,
WindowSize = cr::bit (WindowBits),
WindowMask = WindowSize - 1,
MinMatch = 4,
MaxChain = cr::bit (5),
HashBits = 19,
HashLength = cr::bit (HashBits),
EmptyHash = -1,
};
private:
SmallArray <int32> hashTable_;
SmallArray <int32> prevTable_;
public:
explicit ULZ () {
hashTable_.resize (HashLength);
prevTable_.resize (WindowSize);
}
~ULZ () = default;
public:
int32 compress (uint8 *in, int32 inputLength, uint8 *out) {
for (auto &htb : hashTable_) {
htb = EmptyHash;
}
auto op = out;
int32 anchor = 0;
int32 cur = 0;
while (cur < inputLength) {
const int32 maxMatch = inputLength - cur;
int32 bestLength = 0;
int32 dist = 0;
if (maxMatch >= MinMatch) {
const auto limit = cr::max <int32> (cur - WindowSize, EmptyHash);
int32 chainLength = MaxChain;
int32 lookup = hashTable_[hash32 (&in[cur])];
while (lookup > limit) {
if (in[lookup + bestLength] == in[cur + bestLength] && load <uint32> (&in[lookup]) == load <uint32> (&in[cur])) {
int32 length = MinMatch;
while (length < maxMatch && in[lookup + length] == in[cur + length]) {
++length;
}
if (length > bestLength) {
bestLength = length;
dist = cur - lookup;
if (length == maxMatch) {
break;
}
}
}
if (--chainLength == 0) {
break;
}
lookup = prevTable_[lookup & WindowMask];
}
}
if (bestLength == MinMatch && (cur - anchor) >= (7 + 128)) {
bestLength = 0;
}
if (bestLength >= MinMatch && bestLength < maxMatch && (cur - anchor) != 6) {
const auto next = cur + 1;
const auto target = bestLength + 1;
const auto limit = cr::max <int32> (next - WindowSize, EmptyHash);
int32 chainLength = MaxChain;
int32 lookup = hashTable_[hash32 (&in[next])];
while (lookup > limit) {
if (in[lookup + bestLength] == in[next + bestLength] && load <uint32> (&in[lookup]) == load <uint32> (&in[next])) {
int32 length = MinMatch;
while (length < target && in[lookup + length] == in[next + length]) {
++length;
}
if (length == target) {
bestLength = 0;
break;
}
}
if (--chainLength == 0) {
break;
}
lookup = prevTable_[lookup & WindowMask];
}
}
if (bestLength >= MinMatch) {
const auto length = bestLength - MinMatch;
const auto token = ((dist >> 12) & 16) + cr::min <int32> (length, 15);
if (anchor != cur) {
const auto run = cur - anchor;
if (run >= 7) {
add (op, (7 << 5) + token);
encode (op, run - 7);
}
else {
add (op, (run << 5) + token);
}
copy (op, &in[anchor], run);
op += run;
}
else {
add (op, token);
}
if (length >= 15) {
encode (op, length - 15);
}
store16 (op, static_cast <uint16> (dist));
op += 2;
while (bestLength-- != 0) {
const auto hash = hash32 (&in[cur]);
prevTable_[cur & WindowMask] = hashTable_[hash];
hashTable_[hash] = cur++;
}
anchor = cur;
}
else {
const auto hash = hash32 (&in[cur]);
prevTable_[cur & WindowMask] = hashTable_[hash];
hashTable_[hash] = cur++;
}
}
if (anchor != cur) {
const auto run = cur - anchor;
if (run >= 7) {
add (op, 7 << 5);
encode (op, run - 7);
}
else {
add (op, run << 5);
}
copy (op, &in[anchor], run);
op += run;
}
return static_cast <int32> (op - out);
}
int32 uncompress (uint8 *in, int32 inputLength, uint8 *out, int32 outLength) {
auto op = out;
auto ip = in;
const auto opEnd = op + outLength;
const auto ipEnd = ip + inputLength;
while (ip < ipEnd) {
const auto token = *ip++;
if (token >= 32) {
auto run = token >> 5;
if (run == 7) {
run += decode (ip);
}
if ((opEnd - op) < run || (ipEnd - ip) < run) {
return UncompressFailure;
}
copy (op, ip, run);
op += run;
ip += run;
if (ip >= ipEnd) {
break;
}
}
auto length = (token & 15) + MinMatch;
if (length == (15 + MinMatch)) {
length += decode (ip);
}
if ((opEnd - op) < length) {
return UncompressFailure;
}
const auto dist = ((token & 16) << 12) + load <uint16> (ip);
ip += 2;
auto cp = op - dist;
if ((op - out) < dist) {
return UncompressFailure;
}
if (dist >= 8) {
copy (op, cp, length);
op += length;
}
else {
for (int32 i = 0; i < 4; ++i) {
*op++ = *cp++;
}
while (length-- != 4) {
*op++ = *cp++;
}
}
}
return static_cast <int32> (ip == ipEnd) ? static_cast <int32> (op - out) : UncompressFailure;
}
private:
template <typename U> U load (void *ptr) {
U ret;
memcpy (&ret, ptr, sizeof (U));
return ret;
}
void store16 (void *ptr, uint16 val) {
memcpy (ptr, &val, sizeof (uint16));
}
void copy64 (void *dst, void *src) {
memcpy (dst, src, sizeof (uint64));
}
uint32 hash32 (void *ptr) {
return (load <uint32> (ptr) * 0x9e3779b9) >> (32 - HashBits);
}
void copy (uint8 *dst, uint8 *src, int32 count) {
copy64 (dst, src);
for (int32 i = 8; i < count; i += 8) {
copy64 (dst + i, src + i);
}
}
void add (uint8 *&dst, int32 val) {
*dst++ = static_cast <uint8> (val);
}
void encode (uint8 *&ptr, uint32 val) {
while (val >= 128) {
val -= 128;
*ptr++ = 128 + (val & 127);
val >>= 7;
}
*ptr++ = static_cast <uint8> (val);
}
uint32 decode (uint8 *&ptr) {
uint32 val = 0;
for (int32 i = 0; i <= 21; i += 7) {
const uint32 cur = *ptr++;
val += cur << i;
if (cur < 128) {
break;
}
}
return val;
}
};
// expose global ulz object
CR_EXPOSE_GLOBAL_SINGLETON (ULZ, ulz);
CR_NAMESPACE_END

View file

@ -1,206 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-basic.h>
#include <crlib/cr-memory.h>
#include <crlib/cr-movable.h>
CR_NAMESPACE_BEGIN
// simple unique ptr
template <typename T> class UniquePtr final : public DenyCopying {
private:
T *ptr_ {};
public:
UniquePtr () = default;
explicit UniquePtr (T *ptr) : ptr_ (ptr)
{ }
UniquePtr (UniquePtr &&rhs) noexcept : ptr_ (rhs.release ())
{ }
template <typename U> UniquePtr (UniquePtr <U> &&rhs) noexcept : ptr_ (rhs.release ())
{ }
~UniquePtr () {
destroy ();
}
public:
T *get () const {
return ptr_;
}
T *release () {
auto ret = ptr_;
ptr_ = nullptr;
return ret;
}
void reset (T *ptr = nullptr) {
destroy ();
ptr_ = ptr;
}
private:
void destroy () {
delete ptr_;
ptr_ = nullptr;
}
public:
UniquePtr &operator = (UniquePtr &&rhs) noexcept {
if (this != &rhs) {
reset (rhs.release ());
}
return *this;
}
template <typename U> UniquePtr &operator = (UniquePtr <U> &&rhs) noexcept {
if (this != &rhs) {
reset (rhs.release ());
}
return *this;
}
UniquePtr &operator = (decltype (nullptr)) {
destroy ();
return *this;
}
T &operator * () const {
return *ptr_;
}
T *operator -> () const {
return ptr_;
}
explicit operator bool () const {
return ptr_ != nullptr;
}
};
template <typename T> class UniquePtr <T[]> final : public DenyCopying {
private:
T *ptr_ { };
public:
UniquePtr () = default;
explicit UniquePtr (T *ptr) : ptr_ (ptr)
{ }
UniquePtr (UniquePtr &&rhs) noexcept : ptr_ (rhs.release ())
{ }
template <typename U> UniquePtr (UniquePtr <U> &&rhs) noexcept : ptr_ (rhs.release ())
{ }
~UniquePtr () {
destroy ();
}
public:
T *get () const {
return ptr_;
}
T *release () {
auto ret = ptr_;
ptr_ = nullptr;
return ret;
}
void reset (T *ptr = nullptr) {
destroy ();
ptr_ = ptr;
}
private:
void destroy () {
delete[] ptr_;
ptr_ = nullptr;
}
public:
UniquePtr &operator = (UniquePtr &&rhs) noexcept {
if (this != &rhs) {
reset (rhs.release ());
}
return *this;
}
template <typename U> UniquePtr &operator = (UniquePtr <U> &&rhs) noexcept {
if (this != &rhs) {
reset (rhs.release ());
}
return *this;
}
UniquePtr &operator = (decltype (nullptr)) {
destroy ();
return *this;
}
T &operator [] (size_t index) {
return ptr_[index];
}
const T &operator [] (size_t index) const {
return ptr_[index];
}
explicit operator bool () const {
return ptr_ != nullptr;
}
};
namespace detail {
template <typename T> struct ClearExtent {
using Type = T;
};
template <typename T> struct ClearExtent <T[]> {
using Type = T;
};
template <typename T, size_t N> struct ClearExtent <T[N]> {
using Type = T;
};
template <typename T> struct UniqueIf {
using SingleObject = UniquePtr <T>;
};
template <typename T> struct UniqueIf<T[]> {
using UnknownBound = UniquePtr <T[]>;
};
template <typename T, size_t N> struct UniqueIf <T[N]> {
using KnownBound = void;
};
}
template <typename T, typename... Args> typename detail::UniqueIf <T>::SingleObject makeUnique (Args &&... args) {
return UniquePtr <T> (new T (cr::forward <Args> (args)...));
}
template <typename T> typename detail::UniqueIf <T>::UnknownBound makeUnique (size_t size) {
using Type = typename detail::ClearExtent <T>::Type;
return UniquePtr<T> (new Type[size] ());
}
template <typename T, typename... Args> typename detail::UniqueIf <T>::KnownBound makeUnique (Args &&...) = delete;
CR_NAMESPACE_END

View file

@ -1,325 +0,0 @@
//
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
// Copyright © 2004-2021 YaPB Project <yapb@jeefo.net>.
//
// SPDX-License-Identifier: MIT
//
#pragma once
#include <crlib/cr-math.h>
CR_NAMESPACE_BEGIN
// small simd operations for 3d vector
#if defined (CR_HAS_SSE)
template <typename T> class CR_ALIGN16 SimdWrap {
private:
__m128 wrap_dp_sse2 (__m128 v1, __m128 v2) {
auto mul = _mm_mul_ps (v1, v2);
auto res = _mm_add_ps (_mm_shuffle_ps (v2, mul, _MM_SHUFFLE (1, 0, 0, 0)), mul);
mul = _mm_add_ps (_mm_shuffle_ps (mul, res, _MM_SHUFFLE (0, 3, 0, 0)), res);
return _mm_shuffle_ps (mul, mul, _MM_SHUFFLE (2, 2, 2, 2));
}
public:
union {
__m128 m;
struct {
T x, y, z;
} vec;
};
SimdWrap (const T &x, const T &y, const T &z) {
m = _mm_set_ps (0.0f, z, y, x);
}
SimdWrap (const T &x, const T &y) {
m = _mm_set_ps (0.0f, 0.0f, y, x);
}
SimdWrap (__m128 m) : m (m)
{ }
public:
SimdWrap normalize () {
return { _mm_div_ps (m, _mm_sqrt_ps (wrap_dp_sse2 (m, m))) };
}
};
#endif
// 3dmath vector
template <typename T> class Vec3D {
public:
T x {};
T y {};
T z {};
public:
Vec3D (const T &scaler = 0.0f) : x (scaler), y (scaler), z (scaler)
{ }
Vec3D (const T &x, const T &y, const T &z) : x (x), y (y), z (z)
{ }
Vec3D (T *rhs) : x (rhs[0]), y (rhs[1]), z (rhs[2])
{ }
#if defined (CR_HAS_SSE)
Vec3D (const SimdWrap <T> &rhs) : x (rhs.vec.x), y (rhs.vec.y), z (rhs.vec.z)
{ }
#endif
Vec3D (const Vec3D &) = default;
Vec3D (decltype (nullptr)) {
clear ();
}
public:
operator T * () {
return &x;
}
operator const T * () const {
return &x;
}
Vec3D operator + (const Vec3D &rhs) const {
return { x + rhs.x, y + rhs.y, z + rhs.z };
}
Vec3D operator - (const Vec3D &rhs) const {
return { x - rhs.x, y - rhs.y, z - rhs.z };
}
Vec3D operator - () const {
return { -x, -y, -z };
}
friend Vec3D operator * (const T &scale, const Vec3D &rhs) {
return { rhs.x * scale, rhs.y * scale, rhs.z * scale };
}
Vec3D operator * (const T &scale) const {
return { scale * x, scale * y, scale * z };
}
Vec3D operator / (const T &rhs) const {
const auto inv = 1 / (rhs + kFloatEqualEpsilon);
return { inv * x, inv * y, inv * z };
}
// cross product
Vec3D operator ^ (const Vec3D &rhs) const {
return { y * rhs.z - z * rhs.y, z * rhs.x - x * rhs.z, x * rhs.y - y * rhs.x };
}
// dot product
T operator | (const Vec3D &rhs) const {
return x * rhs.x + y * rhs.y + z * rhs.z;
}
const Vec3D &operator += (const Vec3D &rhs) {
x += rhs.x;
y += rhs.y;
z += rhs.z;
return *this;
}
const Vec3D &operator -= (const Vec3D &rhs) {
x -= rhs.x;
y -= rhs.y;
z -= rhs.z;
return *this;
}
const Vec3D &operator *= (const T &rhs) {
x *= rhs;
y *= rhs;
z *= rhs;
return *this;
}
const Vec3D &operator /= (const T &rhs) {
const auto inv = 1 / (rhs + kFloatEqualEpsilon);
x *= inv;
y *= inv;
z *= inv;
return *this;
}
bool operator == (const Vec3D &rhs) const {
return cr::fequal (x, rhs.x) && cr::fequal (y, rhs.y) && cr::fequal (z, rhs.z);
}
bool operator != (const Vec3D &rhs) const {
return !operator == (rhs);
}
void operator = (decltype (nullptr)) {
clear ();
}
const float &operator [] (const int i) const {
return &(x)[i];
}
float &operator [] (const int i) {
return &(x)[i];
}
Vec3D &operator = (const Vec3D &) = default;
public:
T length () const {
return cr::sqrtf (lengthSq ());
}
T length2d () const {
return cr::sqrtf (cr::square (x) + cr::square (y));
}
T lengthSq () const {
return cr::square (x) + cr::square (y) + cr::square (z);
}
Vec3D get2d () const {
return { x, y, 0.0f };
}
Vec3D normalize () const {
#if defined (CR_HAS_SSE)
return SimdWrap <T> { x, y, z }.normalize ();
#else
auto len = length () + cr::kFloatCmpEpsilon;
if (cr::fzero (len)) {
return { 0.0f, 0.0f, 1.0f };
}
len = 1.0f / len;
return { x * len, y * len, z * len };
#endif
}
Vec3D normalize2d () const {
#if defined (CR_HAS_SSE)
return SimdWrap <T> { x, y }.normalize ();
#else
auto len = length2d () + cr::kFloatCmpEpsilon;
if (cr::fzero (len)) {
return { 0.0f, 1.0f, 0.0f };
}
len = 1.0f / len;
return { x * len, y * len, 0.0f };
#endif
}
bool empty () const {
return cr::fzero (x) && cr::fzero (y) && cr::fzero (z);
}
void clear () {
x = y = z = 0.0f;
}
Vec3D clampAngles () {
x = cr::normalizeAngles (x);
y = cr::normalizeAngles (y);
z = 0.0f;
return *this;
}
T pitch () const {
if (cr::fzero (z)) {
return 0.0f;
}
return cr::deg2rad (cr::atan2f (z, length2d ()));
}
T yaw () const {
if (cr::fzero (x) && cr::fzero (y)) {
return 0.0f;
}
return cr::rad2deg (cr:: atan2f (y, x));
}
Vec3D angles () const {
if (cr::fzero (x) && cr::fzero (y)) {
return { z > 0.0f ? 90.0f : 270.0f, 0.0, 0.0f };
}
return { cr::rad2deg (cr::atan2f (z, length2d ())), cr::rad2deg (cr::atan2f (y, x)), 0.0f };
}
void angleVectors (Vec3D *forward, Vec3D *right, Vec3D *upward) const {
enum { pitch, yaw, roll, unused, max };
T sines[max] = { 0.0f, 0.0f, 0.0f, 0.0f };
T cosines[max] = { 0.0f, 0.0f, 0.0f, 0.0f };
// compute the sine and cosine compontents
cr::sincosf (cr::deg2rad (x), cr::deg2rad (y), cr::deg2rad (z), sines, cosines);
if (forward) {
*forward = {
cosines[pitch] * cosines[yaw],
cosines[pitch] * sines[yaw],
-sines[pitch]
};
}
if (right) {
*right = {
-sines[roll] * sines[pitch] * cosines[yaw] + cosines[roll] * sines[yaw],
-sines[roll] * sines[pitch] * sines[yaw] - cosines[roll] * cosines[yaw],
-sines[roll] * cosines[pitch]
};
}
if (upward) {
*upward = {
cosines[roll] * sines[pitch] * cosines[yaw] + sines[roll] * sines[yaw],
upward->y = cosines[roll] * sines[pitch] * sines[yaw] - sines[roll] * cosines[yaw],
upward->z = cosines[roll] * cosines[pitch]
};
}
}
const Vec3D &forward () {
static Vec3D s_fwd {};
angleVectors (&s_fwd, nullptr, nullptr);
return s_fwd;
}
const Vec3D &upward () {
static Vec3D s_up {};
angleVectors (nullptr, nullptr, &s_up);
return s_up;
}
const Vec3D &right () {
static Vec3D s_right {};
angleVectors (nullptr, &s_right, nullptr);
return s_right;
}
};
// default is float
using Vector = Vec3D <float>;
CR_NAMESPACE_END