savepoint, changelog later..
This commit is contained in:
parent
7d3c4a0be0
commit
1bc1fd1913
45 changed files with 12866 additions and 10981 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
Copyright (c) 2003-2018, YaPB Dev Team
|
Copyright (c) 2003-2019, YaPB Development Team
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
|
||||||
1936
include/corelib.h
1936
include/corelib.h
File diff suppressed because it is too large
Load diff
78
include/crlib/cr-alloc.h
Normal file
78
include/crlib/cr-alloc.h
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <crlib/cr-basic.h>
|
||||||
|
#include <crlib/cr-movable.h>
|
||||||
|
#include <crlib/cr-platform.h>
|
||||||
|
|
||||||
|
CR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// default allocator for cr-objects
|
||||||
|
class Allocator : public Singleton <Allocator> {
|
||||||
|
public:
|
||||||
|
Allocator () = default;
|
||||||
|
~Allocator () = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename T> T *allocate (const size_t length = 1) {
|
||||||
|
auto ptr = reinterpret_cast <T *> (calloc (length, sizeof (T)));
|
||||||
|
|
||||||
|
if (!ptr) {
|
||||||
|
plat.abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// calloc on linux with debug enabled doesn't always zero out memory
|
||||||
|
#if defined (CR_DEBUG) && !defined (CR_WINDOWS)
|
||||||
|
auto *zeroing = reinterpret_cast <uint8 *> (ptr);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < length; ++i) {
|
||||||
|
zeroing[i] = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void deallocate (T *ptr) {
|
||||||
|
if (ptr) {
|
||||||
|
free (reinterpret_cast <T *> (ptr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename T, typename ...Args> void construct (T *d, Args &&...args) {
|
||||||
|
new (d) T (cr::forward <Args> (args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void destruct (T *d) {
|
||||||
|
d->~T ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename T, typename ...Args> T *create (Args &&...args) {
|
||||||
|
auto d = allocate <T> ();
|
||||||
|
new (d) T (cr::forward <Args> (args)...);
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void destroy (T *ptr) {
|
||||||
|
if (ptr) {
|
||||||
|
destruct (ptr);
|
||||||
|
deallocate (ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static auto &alloc = Allocator::get ();
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
390
include/crlib/cr-array.h
Normal file
390
include/crlib/cr-array.h
Normal file
|
|
@ -0,0 +1,390 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <crlib/cr-basic.h>
|
||||||
|
#include <crlib/cr-alloc.h>
|
||||||
|
#include <crlib/cr-movable.h>
|
||||||
|
#include <crlib/cr-random.h>
|
||||||
|
|
||||||
|
// policy to reserve memory
|
||||||
|
CR_DECLARE_SCOPED_ENUM (ReservePolicy,
|
||||||
|
MultipleByTwo,
|
||||||
|
PlusOne
|
||||||
|
);
|
||||||
|
|
||||||
|
CR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// simple array class like std::vector
|
||||||
|
template <typename T, ReservePolicy R = ReservePolicy::MultipleByTwo> class Array : public DenyCopying {
|
||||||
|
public:
|
||||||
|
T *m_data = nullptr;
|
||||||
|
size_t m_capacity = 0;
|
||||||
|
size_t m_length = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Array () = default;
|
||||||
|
|
||||||
|
Array (const size_t amount) {
|
||||||
|
reserve (amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
Array (Array &&rhs) noexcept {
|
||||||
|
m_data = rhs.m_data;
|
||||||
|
m_length = rhs.m_length;
|
||||||
|
m_capacity = rhs.m_capacity;
|
||||||
|
|
||||||
|
rhs.reset ();
|
||||||
|
}
|
||||||
|
|
||||||
|
~Array () {
|
||||||
|
destroy ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void destructElements () noexcept {
|
||||||
|
for (size_t i = 0; i < m_length; ++i) {
|
||||||
|
alloc.destruct (&m_data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void transferElements (T *dest, T *src, size_t length) noexcept {
|
||||||
|
for (size_t i = 0; i < length; ++i) {
|
||||||
|
alloc.construct (&dest[i], cr::move (src[i]));
|
||||||
|
alloc.destruct (&src[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy () {
|
||||||
|
destructElements ();
|
||||||
|
alloc.deallocate (m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset () {
|
||||||
|
m_data = nullptr;
|
||||||
|
m_capacity = 0;
|
||||||
|
m_length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool reserve (const size_t amount) {
|
||||||
|
if (m_length + amount < m_capacity) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
auto capacity = m_capacity ? m_capacity : 8;
|
||||||
|
|
||||||
|
if (cr::fix (R == ReservePolicy::MultipleByTwo)) {
|
||||||
|
while (m_length + amount > capacity) {
|
||||||
|
capacity *= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
capacity = amount + m_capacity + 1;
|
||||||
|
}
|
||||||
|
auto data = alloc.allocate <T> (capacity);
|
||||||
|
|
||||||
|
transferElements (data, m_data, m_length);
|
||||||
|
alloc.deallocate (m_data);
|
||||||
|
|
||||||
|
m_data = data;
|
||||||
|
m_capacity = capacity;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool resize (const size_t amount) {
|
||||||
|
if (amount < m_length) {
|
||||||
|
while (amount < m_length) {
|
||||||
|
discard ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (amount > m_length) {
|
||||||
|
if (!ensure (amount)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
size_t pushLength = amount - m_length;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < pushLength; ++i) {
|
||||||
|
push (T ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ensure (const size_t amount) {
|
||||||
|
if (amount <= m_length) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return reserve (amount - m_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length () const {
|
||||||
|
return m_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t capacity () const {
|
||||||
|
return m_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U> bool set (size_t index, U &&object) {
|
||||||
|
if (index >= m_capacity) {
|
||||||
|
if (!reserve (index + 1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
alloc.construct (&m_data[index], cr::forward <U> (object));
|
||||||
|
|
||||||
|
if (index >= m_length) {
|
||||||
|
m_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 = (m_length > index ? m_length : index) + count;
|
||||||
|
|
||||||
|
if (capacity >= m_capacity && !reserve (capacity)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= m_length) {
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
alloc.construct (&m_data[i + index], cr::forward <U> (objects[i]));
|
||||||
|
}
|
||||||
|
m_length = capacity;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
for (i = m_length; i > index; --i) {
|
||||||
|
m_data[i + count - 1] = cr::move (m_data[i - 1]);
|
||||||
|
}
|
||||||
|
for (i = 0; i < count; ++i) {
|
||||||
|
alloc.construct (&m_data[i + index], cr::forward <U> (objects[i]));
|
||||||
|
}
|
||||||
|
m_length += count;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool insert (size_t at, const Array &rhs) {
|
||||||
|
if (&rhs == this) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return insert (at, &rhs.m_data[0], rhs.m_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool erase (const size_t index, const size_t count) {
|
||||||
|
if (index + count > m_capacity) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_length -= count;
|
||||||
|
|
||||||
|
for (size_t i = index; i < m_length; ++i) {
|
||||||
|
m_data[i] = cr::move (m_data[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;
|
||||||
|
}
|
||||||
|
alloc.construct (&m_data[m_length], cr::forward <U> (object));
|
||||||
|
m_length++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ...Args> bool emplace (Args &&...args) {
|
||||||
|
if (!reserve (1)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
alloc.construct (&m_data[m_length], cr::forward <Args> (args)...);
|
||||||
|
m_length++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
T pop () {
|
||||||
|
auto object = cr::move (m_data[m_length - 1]);
|
||||||
|
discard ();
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
void discard () {
|
||||||
|
erase (m_length - 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t index (const T &object) const {
|
||||||
|
return &object - &m_data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
void shuffle () {
|
||||||
|
for (size_t i = m_length; i >= 1; --i) {
|
||||||
|
cr::swap (m_data[i - 1], m_data[rg.int_ (i, m_length - 2)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reverse () {
|
||||||
|
for (size_t i = 0; i < m_length / 2; ++i) {
|
||||||
|
cr::swap (m_data[i], m_data[m_length - 1 - i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U> bool extend (U &&rhs) {
|
||||||
|
if (m_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 ();
|
||||||
|
m_length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty () const {
|
||||||
|
return m_length == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool shrink () {
|
||||||
|
if (m_length == m_capacity || !m_length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto data = alloc.allocate <T> (m_length);
|
||||||
|
transferElements (data, m_data, m_length);
|
||||||
|
|
||||||
|
alloc.deallocate (m_data);
|
||||||
|
|
||||||
|
m_data = data;
|
||||||
|
m_capacity = m_length;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T &at (size_t index) const {
|
||||||
|
return m_data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
T &at (size_t index) {
|
||||||
|
return m_data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const T &first () const {
|
||||||
|
return m_data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
T &first () {
|
||||||
|
return m_data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
T &last () {
|
||||||
|
return m_data[m_length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const T &last () const {
|
||||||
|
return m_data[m_length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const T &random () const {
|
||||||
|
return m_data[rg.int_ <size_t> (0, m_length - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
T &random () {
|
||||||
|
return m_data[rg.int_ <size_t> (0u, m_length - 1u)];
|
||||||
|
}
|
||||||
|
|
||||||
|
T *data () {
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
T *data () const {
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Array &operator = (Array &&rhs) noexcept {
|
||||||
|
if (this != &rhs) {
|
||||||
|
destroy ();
|
||||||
|
|
||||||
|
m_data = rhs.m_data;
|
||||||
|
m_length = rhs.m_length;
|
||||||
|
m_capacity = rhs.m_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 m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
T *begin () const {
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
T *end () {
|
||||||
|
return m_data + m_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
T *end () const {
|
||||||
|
return m_data + m_length;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
|
|
||||||
128
include/crlib/cr-basic.h
Normal file
128
include/crlib/cr-basic.h
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// our global namaespace
|
||||||
|
#define CR_NAMESPACE_BEGIN namespace cr {
|
||||||
|
#define CR_NAMESPACE_END }
|
||||||
|
|
||||||
|
// undef base max
|
||||||
|
#if defined (max)
|
||||||
|
# undef max
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// undef base min
|
||||||
|
#if defined (min)
|
||||||
|
# undef min
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.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> struct Singleton : private DenyCopying {
|
||||||
|
public:
|
||||||
|
static inline T &get () {
|
||||||
|
static T ref_;
|
||||||
|
return ref_;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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__); \
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
|
|
||||||
|
// platform-dependant-stuff
|
||||||
|
#include <crlib/cr-platform.h>
|
||||||
141
include/crlib/cr-binheap.h
Normal file
141
include/crlib/cr-binheap.h
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <crlib/cr-array.h>
|
||||||
|
|
||||||
|
CR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// simple priority queue
|
||||||
|
template <typename T> class BinaryHeap final : public DenyCopying {
|
||||||
|
private:
|
||||||
|
Array <T> m_data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit BinaryHeap () = default;
|
||||||
|
|
||||||
|
BinaryHeap (BinaryHeap &&rhs) noexcept : m_data (cr::move (rhs.m_data))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
~BinaryHeap () = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename U> bool push (U &&item) {
|
||||||
|
if (!m_data.push (cr::move (item))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
size_t length = m_data.length ();
|
||||||
|
|
||||||
|
if (length > 1) {
|
||||||
|
percolateUp (length - 1);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ...Args> bool emplace (Args &&...args) {
|
||||||
|
if (!m_data.emplace (cr::forward <Args> (args)...)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
size_t length = m_data.length ();
|
||||||
|
|
||||||
|
if (length > 1) {
|
||||||
|
percolateUp (length - 1);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T &top () const {
|
||||||
|
return m_data[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
T pop () {
|
||||||
|
if (m_data.length () == 1) {
|
||||||
|
return m_data.pop ();
|
||||||
|
}
|
||||||
|
auto key (cr::move (m_data[0]));
|
||||||
|
|
||||||
|
m_data[0] = cr::move (m_data.last ());
|
||||||
|
m_data.discard ();
|
||||||
|
|
||||||
|
percolateDown (0);
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
size_t length () const {
|
||||||
|
return m_data.length ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty () const {
|
||||||
|
return !m_data.length ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear () {
|
||||||
|
m_data.clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void percolateUp (size_t index) {
|
||||||
|
while (index != 0) {
|
||||||
|
size_t parent = this->parent (index);
|
||||||
|
|
||||||
|
if (m_data[parent] <= m_data[index]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cr::swap (m_data[index], m_data[parent]);
|
||||||
|
index = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void percolateDown (size_t index) {
|
||||||
|
while (this->left (index) < m_data.length ()) {
|
||||||
|
size_t best = this->left (index);
|
||||||
|
|
||||||
|
if (this->right (index) < m_data.length ()) {
|
||||||
|
size_t right_index = this->right (index);
|
||||||
|
|
||||||
|
if (m_data[right_index] < m_data[best]) {
|
||||||
|
best = right_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_data[index] <= m_data[best]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cr::swap (m_data[index], m_data[best]);
|
||||||
|
|
||||||
|
index = best;
|
||||||
|
best = this->left (index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BinaryHeap &operator = (BinaryHeap &&rhs) noexcept {
|
||||||
|
if (this != &rhs) {
|
||||||
|
m_data = cr::move (rhs.m_data);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr size_t left (size_t index) {
|
||||||
|
return index << 1 | 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr size_t right (size_t index) {
|
||||||
|
return ++index << 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr size_t parent (size_t index) {
|
||||||
|
return --index >> 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
41
include/crlib/cr-color.h
Normal file
41
include/crlib/cr-color.h
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#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:
|
||||||
|
explicit Color (int32 r, int32 g, int32 b) : red (r), green (g), blue (b) { }
|
||||||
|
|
||||||
|
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
|
||||||
40
include/crlib/cr-complete.h
Normal file
40
include/crlib/cr-complete.h
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <crlib/cr-platform.h>
|
||||||
|
#include <crlib/cr-basic.h>
|
||||||
|
#include <crlib/cr-alloc.h>
|
||||||
|
#include <crlib/cr-array.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-dict.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>
|
||||||
|
|
||||||
|
CR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
namespace types {
|
||||||
|
using StringArray = Array <String>;
|
||||||
|
using IntArray = Array <int>;
|
||||||
|
};
|
||||||
|
|
||||||
|
using namespace cr::types;
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
237
include/crlib/cr-dict.h
Normal file
237
include/crlib/cr-dict.h
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#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 for hashing our string
|
||||||
|
template <typename K> struct StringHash {
|
||||||
|
uint32 operator () (const K &key) const {
|
||||||
|
char *str = const_cast <char *> (key.chars ());
|
||||||
|
uint32 hash = 0;
|
||||||
|
|
||||||
|
while (*str++) {
|
||||||
|
hash = ((hash << 5) + hash) + *str;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// template for hashing integers
|
||||||
|
template <typename K> struct IntHash {
|
||||||
|
uint32 operator () (K key) const {
|
||||||
|
key = ((key >> 16) ^ key) * 0x119de1f3;
|
||||||
|
key = ((key >> 16) ^ key) * 0x119de1f3;
|
||||||
|
key = (key >> 16) ^ key;
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
struct DictionaryList {
|
||||||
|
uint32 index;
|
||||||
|
DictionaryList *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename K, typename V> struct DictionaryBucket {
|
||||||
|
uint32 hash = static_cast <size_t> (-1);
|
||||||
|
K key = K ();
|
||||||
|
V value = V ();
|
||||||
|
|
||||||
|
public:
|
||||||
|
DictionaryBucket () = default;
|
||||||
|
~DictionaryBucket () = default;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// basic dictionary
|
||||||
|
template <class K, class V, class H = StringHash <K>, size_t HashSize = 36> class Dictionary final : public DenyCopying {
|
||||||
|
public:
|
||||||
|
static constexpr size_t kInvalidIndex = static_cast <size_t> (-1);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Array <detail::DictionaryList *> m_table;
|
||||||
|
Array <detail::DictionaryBucket <K, V>> m_buckets;
|
||||||
|
H m_hasher;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32 hash (const K &key) const {
|
||||||
|
return m_hasher (key);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t findIndexOrAllocate (const K &key, bool allocate) {
|
||||||
|
auto hashed = hash (key);
|
||||||
|
auto pos = hashed % m_table.length ();
|
||||||
|
|
||||||
|
for (auto bucket = m_table[pos]; bucket != nullptr; bucket = bucket->next) {
|
||||||
|
if (m_buckets[bucket->index].hash == hashed) {
|
||||||
|
return bucket->index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allocate) {
|
||||||
|
size_t created = m_buckets.length ();
|
||||||
|
m_buckets.resize (created + 1);
|
||||||
|
|
||||||
|
auto allocated = alloc.allocate <detail::DictionaryList> ();
|
||||||
|
|
||||||
|
allocated->index = created;
|
||||||
|
allocated->next = m_table[pos];
|
||||||
|
|
||||||
|
m_table[pos] = allocated;
|
||||||
|
|
||||||
|
m_buckets[created].key = key;
|
||||||
|
m_buckets[created].hash = hashed;
|
||||||
|
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
return kInvalidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t findIndex (const K &key) const {
|
||||||
|
return const_cast <Dictionary *> (this)->findIndexOrAllocate (key, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Dictionary () {
|
||||||
|
reset ();
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary (Dictionary &&rhs) noexcept : m_table (cr::move (rhs.m_table)), m_buckets (cr::move (rhs.m_buckets)), m_hasher (cr::move (rhs.m_hasher))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
~Dictionary () {
|
||||||
|
clear ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool exists (const K &key) const {
|
||||||
|
return findIndex (key) != kInvalidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty () const {
|
||||||
|
return m_buckets.empty ();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length () const {
|
||||||
|
return m_buckets.length ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool find (const K &key, V &value) const {
|
||||||
|
size_t index = findIndex (key);
|
||||||
|
|
||||||
|
if (index == kInvalidIndex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
value = m_buckets[index].value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U> bool push (const K &key, U &&value) {
|
||||||
|
operator [] (key) = cr::forward <U> (value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool remove (const K &key) {
|
||||||
|
auto hashed = hash (key);
|
||||||
|
|
||||||
|
auto pos = hashed % m_table.length ();
|
||||||
|
auto *bucket = m_table[pos];
|
||||||
|
|
||||||
|
detail::DictionaryList *next = nullptr;
|
||||||
|
|
||||||
|
while (bucket != nullptr) {
|
||||||
|
if (m_buckets[bucket->index].hash == hashed) {
|
||||||
|
if (!next) {
|
||||||
|
m_table[pos] = bucket->next;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
next->next = bucket->next;
|
||||||
|
}
|
||||||
|
m_buckets.erase (bucket->index, 1);
|
||||||
|
|
||||||
|
alloc.deallocate (bucket);
|
||||||
|
bucket = nullptr;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
next = bucket;
|
||||||
|
bucket = bucket->next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear () {
|
||||||
|
for (auto object : m_table) {
|
||||||
|
while (object != nullptr) {
|
||||||
|
auto next = object->next;
|
||||||
|
|
||||||
|
alloc.deallocate (object);
|
||||||
|
object = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_table.clear ();
|
||||||
|
m_buckets.clear ();
|
||||||
|
|
||||||
|
reset ();
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset () {
|
||||||
|
m_table.resize (HashSize);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < HashSize; ++i) {
|
||||||
|
m_table[i] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
V &operator [] (const K &key) {
|
||||||
|
return m_buckets[findIndexOrAllocate (key, true)].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const V &operator [] (const K &key) const {
|
||||||
|
return m_buckets[findIndex (key)].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary &operator = (Dictionary &&rhs) noexcept {
|
||||||
|
if (this != &rhs) {
|
||||||
|
m_table = cr::move (rhs.m_table);
|
||||||
|
m_buckets = cr::move (rhs.m_buckets);
|
||||||
|
m_hasher = cr::move (rhs.m_hasher);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for range-based loops
|
||||||
|
public:
|
||||||
|
detail::DictionaryBucket <K, V> *begin () {
|
||||||
|
return m_buckets.begin ();
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::DictionaryBucket <K, V> *begin () const {
|
||||||
|
return m_buckets.begin ();
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::DictionaryBucket <K, V> *end () {
|
||||||
|
return m_buckets.end ();
|
||||||
|
}
|
||||||
|
|
||||||
|
detail::DictionaryBucket <K, V> *end () const {
|
||||||
|
return m_buckets.end ();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
334
include/crlib/cr-files.h
Normal file
334
include/crlib/cr-files.h
Normal file
|
|
@ -0,0 +1,334 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#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 *m_handle = nullptr;
|
||||||
|
size_t m_length = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit File () = default;
|
||||||
|
|
||||||
|
File (const String &file, const String &mode = "rt") {
|
||||||
|
open (file, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
~File () {
|
||||||
|
close ();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
|
||||||
|
bool open (const String &file, const String &mode) {
|
||||||
|
if ((m_handle = fopen (file.chars (), mode.chars ())) == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fseek (m_handle, 0L, SEEK_END);
|
||||||
|
m_length = ftell (m_handle);
|
||||||
|
fseek (m_handle, 0L, SEEK_SET);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close () {
|
||||||
|
if (m_handle != nullptr) {
|
||||||
|
fclose (m_handle);
|
||||||
|
m_handle = nullptr;
|
||||||
|
}
|
||||||
|
m_length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eof () const {
|
||||||
|
return !!feof (m_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool flush () const {
|
||||||
|
return !!fflush (m_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
int getChar () const {
|
||||||
|
return fgetc (m_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *getString (char *buffer, int count) const {
|
||||||
|
return fgets (buffer, count, m_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getLine (String &line) {
|
||||||
|
line.clear ();
|
||||||
|
int ch;
|
||||||
|
|
||||||
|
while ((ch = getChar ()) != EOF && !eof ()) {
|
||||||
|
line += static_cast <char> (ch);
|
||||||
|
|
||||||
|
if (ch == '\n') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !eof ();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ...Args> size_t puts (const char *fmt, Args ...args) {
|
||||||
|
if (!*this) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return fprintf (m_handle, fmt, cr::forward <Args> (args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool puts (const String &buffer) {
|
||||||
|
if (!*this) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (fputs (buffer.chars (), m_handle) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int putChar (int ch) {
|
||||||
|
return fputc (ch, m_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t read (void *buffer, size_t size, size_t count = 1) {
|
||||||
|
return fread (buffer, size, count, m_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t write (void *buffer, size_t size, size_t count = 1) {
|
||||||
|
return fwrite (buffer, size, count, m_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool seek (long offset, int origin) {
|
||||||
|
if (fseek (m_handle, offset, origin) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rewind () {
|
||||||
|
::rewind (m_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length () const {
|
||||||
|
return m_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit operator bool () const {
|
||||||
|
return m_handle != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static inline bool exists (const String &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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 m_load = nullptr;
|
||||||
|
FreeFunction m_free = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline MemFileStorage () = default;
|
||||||
|
inline ~MemFileStorage () = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void initizalize (LoadFunction loader, FreeFunction unloader) {
|
||||||
|
m_load = cr::move (loader);
|
||||||
|
m_free = cr::move (unloader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
uint8 *load (const String &file, int *size) {
|
||||||
|
if (m_load) {
|
||||||
|
return m_load (file.chars (), size);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unload (void *buffer) {
|
||||||
|
if (m_free) {
|
||||||
|
m_free (buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class MemFile final : public DenyCopying {
|
||||||
|
private:
|
||||||
|
static constexpr char kEOF = static_cast <char> (-1);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8 *m_data = nullptr;
|
||||||
|
size_t m_length = 0, m_pos = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MemFile () = default;
|
||||||
|
|
||||||
|
MemFile (const String &file) {
|
||||||
|
open (file);
|
||||||
|
}
|
||||||
|
|
||||||
|
~MemFile () {
|
||||||
|
close ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool open (const String &file) {
|
||||||
|
m_length = 0;
|
||||||
|
m_pos = 0;
|
||||||
|
m_data = MemFileStorage::get ().load (file.chars (), reinterpret_cast <int *> (&m_length));
|
||||||
|
|
||||||
|
if (!m_data) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void close () {
|
||||||
|
MemFileStorage::get ().unload (m_data);
|
||||||
|
|
||||||
|
m_length = 0;
|
||||||
|
m_pos = 0;
|
||||||
|
m_data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
char getChar () {
|
||||||
|
if (!m_data || m_pos >= m_length) {
|
||||||
|
return kEOF;
|
||||||
|
}
|
||||||
|
auto ch = m_data[m_pos];
|
||||||
|
m_pos++;
|
||||||
|
|
||||||
|
return static_cast <char> (ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *getString (char *buffer, size_t count) {
|
||||||
|
if (!m_data || m_pos >= m_length) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
size_t index = 0;
|
||||||
|
buffer[0] = 0;
|
||||||
|
|
||||||
|
for (; index < count - 1;) {
|
||||||
|
if (m_pos < m_length) {
|
||||||
|
buffer[index] = m_data[m_pos++];
|
||||||
|
|
||||||
|
if (buffer[index++] == '\n') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffer[index] = 0;
|
||||||
|
return index ? buffer : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getLine (String &line) {
|
||||||
|
line.clear ();
|
||||||
|
char ch;
|
||||||
|
|
||||||
|
while ((ch = getChar ()) != kEOF) {
|
||||||
|
line += ch;
|
||||||
|
|
||||||
|
if (ch == '\n') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !eof ();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t read (void *buffer, size_t size, size_t count = 1) {
|
||||||
|
if (!m_data || m_length <= m_pos || !buffer || !size || !count) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t blocks_read = size * count <= m_length - m_pos ? size * count : m_length - m_pos;
|
||||||
|
|
||||||
|
memcpy (buffer, &m_data[m_pos], blocks_read);
|
||||||
|
m_pos += blocks_read;
|
||||||
|
|
||||||
|
return blocks_read / size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool seek (size_t offset, int origin) {
|
||||||
|
if (!m_data || m_pos >= m_length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (origin == SEEK_SET) {
|
||||||
|
if (offset >= m_length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_pos = offset;
|
||||||
|
}
|
||||||
|
else if (origin == SEEK_END) {
|
||||||
|
if (offset >= m_length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_pos = m_length - offset;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (m_pos + offset >= m_length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_pos += offset;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length () const {
|
||||||
|
return m_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool eof () const {
|
||||||
|
return m_pos >= m_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rewind () {
|
||||||
|
m_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit operator bool () const {
|
||||||
|
return !!m_data && m_length > 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
425
include/crlib/cr-http.h
Normal file
425
include/crlib/cr-http.h
Normal file
|
|
@ -0,0 +1,425 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <crlib/cr-string.h>
|
||||||
|
#include <crlib/cr-files.h>
|
||||||
|
#include <crlib/cr-logger.h>
|
||||||
|
#include <crlib/cr-platform.h>
|
||||||
|
|
||||||
|
#if defined (CR_LINUX) || defined (CR_OSX)
|
||||||
|
# include <netinet/in.h>
|
||||||
|
# include <sys/socket.h>
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <arpa/inet.h>
|
||||||
|
# include <unistd.h>
|
||||||
|
# include <errno.h>
|
||||||
|
# include <netdb.h>
|
||||||
|
# include <fcntl.h>
|
||||||
|
#elif defined (CR_WINDOWS)
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# include <windows.h>
|
||||||
|
# include <winsock2.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// status codes for http client
|
||||||
|
CR_DECLARE_SCOPED_ENUM (HttpClientResult,
|
||||||
|
OK = 0,
|
||||||
|
NotFound,
|
||||||
|
Forbidden,
|
||||||
|
SocketError,
|
||||||
|
ConnectError,
|
||||||
|
HttpOnly,
|
||||||
|
Undefined,
|
||||||
|
NoLocalFile = -1,
|
||||||
|
LocalFileExists = -2
|
||||||
|
);
|
||||||
|
|
||||||
|
CR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class Socket final : public DenyCopying {
|
||||||
|
private:
|
||||||
|
int32 m_socket;
|
||||||
|
uint32 m_timeout;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Socket () : m_socket (-1), m_timeout (2) {
|
||||||
|
#if defined(CR_WINDOWS)
|
||||||
|
WSADATA wsa;
|
||||||
|
|
||||||
|
if (WSAStartup (MAKEWORD (1, 1), &wsa) != 0) {
|
||||||
|
logger.error ("Unable to inialize sockets.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
~Socket () {
|
||||||
|
disconnect ();
|
||||||
|
#if defined (CR_WINDOWS)
|
||||||
|
WSACleanup ();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool connect (const String &hostname) {
|
||||||
|
auto host = gethostbyname (hostname.chars ());
|
||||||
|
|
||||||
|
if (!host) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_socket = static_cast <int> (socket (AF_INET, SOCK_STREAM, 0));
|
||||||
|
|
||||||
|
if (m_socket < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto getTimeouts = [&] () -> Twin <char *, size_t> {
|
||||||
|
#if defined (CR_WINDOWS)
|
||||||
|
DWORD tv = m_timeout * 1000;
|
||||||
|
#else
|
||||||
|
timeval tv { static_cast <time_t> (m_timeout), 0 };
|
||||||
|
#endif
|
||||||
|
return { reinterpret_cast <char *> (&tv), sizeof (tv) };
|
||||||
|
};
|
||||||
|
auto timeouts = getTimeouts ();
|
||||||
|
|
||||||
|
setsockopt (m_socket, SOL_SOCKET, SO_RCVTIMEO, timeouts.first, timeouts.second);
|
||||||
|
setsockopt (m_socket, SOL_SOCKET, SO_SNDTIMEO, timeouts.first, timeouts.second);
|
||||||
|
|
||||||
|
sockaddr_in dest;
|
||||||
|
memset (&dest, 0, sizeof (dest));
|
||||||
|
|
||||||
|
dest.sin_family = AF_INET;
|
||||||
|
dest.sin_port = htons (80);
|
||||||
|
dest.sin_addr.s_addr = inet_addr (inet_ntoa (*(reinterpret_cast <in_addr *> (host->h_addr))));
|
||||||
|
|
||||||
|
if (::connect (m_socket, reinterpret_cast <sockaddr *> (&dest), static_cast <int> (sizeof (dest))) == -1) {
|
||||||
|
disconnect ();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTimeout (uint32 timeout) {
|
||||||
|
m_timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
void disconnect () {
|
||||||
|
#if defined(CR_WINDOWS)
|
||||||
|
if (m_socket != -1) {
|
||||||
|
closesocket (m_socket);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (m_socket != -1)
|
||||||
|
close (m_socket);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename U> int32 send (const U *buffer, int32 length) const {
|
||||||
|
return ::send (m_socket, reinterpret_cast <const char *> (buffer), length, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U> int32 recv (U *buffer, int32 length) {
|
||||||
|
return ::recv (m_socket, reinterpret_cast <char *> (buffer), length, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
// simple http uri omitting query-string and port
|
||||||
|
struct HttpUri {
|
||||||
|
String path, protocol, host;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static HttpUri parse (const String &uri) {
|
||||||
|
HttpUri result;
|
||||||
|
|
||||||
|
if (uri.empty ()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
size_t protocol = uri.find ("://");
|
||||||
|
|
||||||
|
if (protocol != String::kInvalidIndex) {
|
||||||
|
result.protocol = uri.substr (0, protocol);
|
||||||
|
|
||||||
|
size_t host = uri.find ("/", protocol + 3);
|
||||||
|
|
||||||
|
if (host != String::kInvalidIndex) {
|
||||||
|
result.path = uri.substr (host + 1);
|
||||||
|
result.host = uri.substr (protocol + 3, host - protocol - 3);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// simple http client for downloading/uploading files only
|
||||||
|
class HttpClient final : public Singleton <HttpClient> {
|
||||||
|
private:
|
||||||
|
static constexpr int32 kMaxRecvErrors = 12;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Socket m_socket;
|
||||||
|
String m_userAgent = "crlib";
|
||||||
|
HttpClientResult m_code = HttpClientResult::Undefined;
|
||||||
|
int32 m_chunkSize = 4096;
|
||||||
|
|
||||||
|
public:
|
||||||
|
HttpClient () = default;
|
||||||
|
~HttpClient () = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
HttpClientResult parseResponseHeader (uint8 *buffer) {
|
||||||
|
bool isFinished = false;
|
||||||
|
int32 pos = 0, symbols = 0, errors = 0;
|
||||||
|
|
||||||
|
// prase response header
|
||||||
|
while (!isFinished && pos < m_chunkSize) {
|
||||||
|
if (m_socket.recv (&buffer[pos], 1) < 1) {
|
||||||
|
if (++errors > kMaxRecvErrors) {
|
||||||
|
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::kInvalidIndex) {
|
||||||
|
String respCode = response.substr (responseCodeStart + 9, 3).trim ();
|
||||||
|
|
||||||
|
if (respCode == "200") {
|
||||||
|
return HttpClientResult::OK;
|
||||||
|
}
|
||||||
|
else if (respCode == "403") {
|
||||||
|
return HttpClientResult::Forbidden;
|
||||||
|
}
|
||||||
|
else if (respCode == "404") {
|
||||||
|
return HttpClientResult::NotFound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return HttpClientResult::NotFound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// simple blocked download
|
||||||
|
bool downloadFile (const String &url, const String &localPath) {
|
||||||
|
if (File::exists (localPath.chars ())) {
|
||||||
|
m_code = HttpClientResult::LocalFileExists;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto uri = detail::HttpUri::parse (url);
|
||||||
|
|
||||||
|
// no https...
|
||||||
|
if (uri.protocol == "https") {
|
||||||
|
m_code = HttpClientResult::HttpOnly;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// unable to connect...
|
||||||
|
if (!m_socket.connect (uri.host)) {
|
||||||
|
m_code = HttpClientResult::ConnectError;
|
||||||
|
m_socket.disconnect ();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String request;
|
||||||
|
request.appendf ("GET /%s HTTP/1.1\r\n", uri.path.chars ());
|
||||||
|
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", m_userAgent.chars ());
|
||||||
|
request.appendf ("Host: %s\r\n\r\n", uri.host.chars ());
|
||||||
|
|
||||||
|
if (m_socket.send (request.chars (), static_cast <int32> (request.length ())) < 1) {
|
||||||
|
m_code = HttpClientResult::SocketError;
|
||||||
|
m_socket.disconnect ();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Array <uint8, ReservePolicy::PlusOne> buffer (m_chunkSize);
|
||||||
|
m_code = parseResponseHeader (buffer.data ());
|
||||||
|
|
||||||
|
if (m_code != HttpClientResult::OK) {
|
||||||
|
m_socket.disconnect ();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// receive the file
|
||||||
|
File file (localPath, "wb");
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
m_code = HttpClientResult::Undefined;
|
||||||
|
m_socket.disconnect ();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int32 length = 0;
|
||||||
|
int32 errors = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
length = m_socket.recv (buffer.data (), m_chunkSize);
|
||||||
|
|
||||||
|
if (length > 0) {
|
||||||
|
file.write (buffer.data (), length);
|
||||||
|
}
|
||||||
|
else if (++errors > 12) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file.close ();
|
||||||
|
|
||||||
|
m_socket.disconnect ();
|
||||||
|
m_code = HttpClientResult::OK;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool uploadFile (const String &url, const String &localPath) {
|
||||||
|
if (!File::exists (localPath.chars ())) {
|
||||||
|
m_code = HttpClientResult::NoLocalFile;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
auto uri = detail::HttpUri::parse (url);
|
||||||
|
|
||||||
|
// no https...
|
||||||
|
if (uri.protocol == "https") {
|
||||||
|
m_code = HttpClientResult::HttpOnly;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// unable to connect...
|
||||||
|
if (!m_socket.connect (uri.host)) {
|
||||||
|
m_code = HttpClientResult::ConnectError;
|
||||||
|
m_socket.disconnect ();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// receive the file
|
||||||
|
File file (localPath, "rb");
|
||||||
|
|
||||||
|
if (!file) {
|
||||||
|
m_code = HttpClientResult::Undefined;
|
||||||
|
m_socket.disconnect ();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String boundaryName = localPath;
|
||||||
|
size_t boundarySlash = localPath.findLastOf ("\\/");
|
||||||
|
|
||||||
|
if (boundarySlash != String::kInvalidIndex) {
|
||||||
|
boundaryName = localPath.substr (boundarySlash + 1);
|
||||||
|
}
|
||||||
|
const String &kBoundary = "---crlib_upload_boundary_1337";
|
||||||
|
|
||||||
|
String request, start, end;
|
||||||
|
start.appendf ("--%s\r\n", kBoundary.chars ());
|
||||||
|
start.appendf ("Content-Disposition: form-data; name='file'; filename='%s'\r\n", boundaryName.chars ());
|
||||||
|
start.append ("Content-Type: application/octet-stream\r\n\r\n");
|
||||||
|
|
||||||
|
end.appendf ("\r\n--%s--\r\n\r\n", kBoundary.chars ());
|
||||||
|
|
||||||
|
request.appendf ("POST /%s HTTP/1.1\r\n", uri.path.chars ());
|
||||||
|
request.appendf ("Host: %s\r\n", uri.host.chars ());
|
||||||
|
request.appendf ("User-Agent: %s\r\n", m_userAgent.chars ());
|
||||||
|
request.appendf ("Content-Type: multipart/form-data; boundary=%s\r\n", kBoundary.chars ());
|
||||||
|
request.appendf ("Content-Length: %d\r\n\r\n", file.length () + start.length () + end.length ());
|
||||||
|
|
||||||
|
// send the main request
|
||||||
|
if (m_socket.send (request.chars (), static_cast <int32> (request.length ())) < 1) {
|
||||||
|
m_code = HttpClientResult::SocketError;
|
||||||
|
m_socket.disconnect ();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send boundary start
|
||||||
|
if (m_socket.send (start.chars (), static_cast <int32> (start.length ())) < 1) {
|
||||||
|
m_code = HttpClientResult::SocketError;
|
||||||
|
m_socket.disconnect ();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Array <uint8, ReservePolicy::PlusOne> buffer (m_chunkSize);
|
||||||
|
int32 length = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
length = static_cast <int32> (file.read (buffer.data (), 1, m_chunkSize));
|
||||||
|
|
||||||
|
if (length > 0) {
|
||||||
|
m_socket.send (buffer.data (), length);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send boundary end
|
||||||
|
if (m_socket.send (end.chars (), static_cast <int32> (end.length ())) < 1) {
|
||||||
|
m_code = HttpClientResult::SocketError;
|
||||||
|
m_socket.disconnect ();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
m_code = parseResponseHeader (buffer.data ());
|
||||||
|
m_socket.disconnect ();
|
||||||
|
|
||||||
|
return m_code == HttpClientResult::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setUserAgent (const String &ua) {
|
||||||
|
m_userAgent = ua;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpClientResult getLastStatusCode () {
|
||||||
|
return m_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setChunkSize (int32 chunkSize) {
|
||||||
|
m_chunkSize = chunkSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTimeout (uint32 timeout) {
|
||||||
|
m_socket.setTimeout (timeout);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// expose global http client
|
||||||
|
static auto &http = HttpClient::get ();
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
173
include/crlib/cr-lambda.h
Normal file
173
include/crlib/cr-lambda.h
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <crlib/cr-alloc.h>
|
||||||
|
#include <crlib/cr-uniqueptr.h>
|
||||||
|
|
||||||
|
CR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
static constexpr uint32 kLambdaSmallBufferSize = sizeof (void *) * 16;
|
||||||
|
|
||||||
|
template <typename> class Lambda;
|
||||||
|
template <typename R, typename ...Args> class Lambda <R (Args...)> {
|
||||||
|
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;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void operator delete (void *ptr) {
|
||||||
|
alloc.deallocate (ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> class LambdaFunctor : public LambdaFunctorWrapper {
|
||||||
|
private:
|
||||||
|
T m_callable;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LambdaFunctor (const T &callable) : LambdaFunctorWrapper (), m_callable (callable)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
LambdaFunctor (T &&callable) : LambdaFunctorWrapper (), m_callable (cr::move (callable))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
~LambdaFunctor () override = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void move (uint8 *to) override {
|
||||||
|
new (to) LambdaFunctor<T> (cr::move (m_callable));
|
||||||
|
}
|
||||||
|
|
||||||
|
void small (uint8 *to) const override {
|
||||||
|
new (to) LambdaFunctor<T> (m_callable);
|
||||||
|
}
|
||||||
|
|
||||||
|
R invoke (Args &&... args) override {
|
||||||
|
return m_callable (cr::forward <Args> (args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
UniquePtr <LambdaFunctorWrapper> clone () const override {
|
||||||
|
return createUniqueBase <LambdaFunctor <T>, LambdaFunctorWrapper> (m_callable);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
UniquePtr <LambdaFunctorWrapper> m_functor;
|
||||||
|
uint8 m_small[kLambdaSmallBufferSize];
|
||||||
|
};
|
||||||
|
|
||||||
|
bool m_smallObject;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void destroy () {
|
||||||
|
if (m_smallObject) {
|
||||||
|
reinterpret_cast <LambdaFunctorWrapper *> (m_small)->~LambdaFunctorWrapper ();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_functor.reset ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap (Lambda &rhs) noexcept {
|
||||||
|
cr::swap (rhs, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Lambda () noexcept : Lambda (nullptr)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Lambda (decltype (nullptr)) noexcept : m_functor (nullptr), m_smallObject (false)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Lambda (const Lambda &rhs) {
|
||||||
|
if (rhs.m_smallObject) {
|
||||||
|
reinterpret_cast <const LambdaFunctorWrapper *> (rhs.m_small)->small (m_small);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
new (m_small) UniquePtr <LambdaFunctorWrapper> (rhs.m_functor->clone ());
|
||||||
|
}
|
||||||
|
m_smallObject = rhs.m_smallObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
Lambda (Lambda &&rhs) noexcept {
|
||||||
|
if (rhs.m_smallObject) {
|
||||||
|
reinterpret_cast <LambdaFunctorWrapper *> (rhs.m_small)->move (m_small);
|
||||||
|
new (rhs.m_small) UniquePtr <LambdaFunctorWrapper> (nullptr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
new (m_small) UniquePtr <LambdaFunctorWrapper> (cr::move (rhs.m_functor));
|
||||||
|
}
|
||||||
|
m_smallObject = rhs.m_smallObject;
|
||||||
|
rhs.m_smallObject = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename F> Lambda (F function) {
|
||||||
|
if (cr::fix (sizeof (function) > kLambdaSmallBufferSize)) {
|
||||||
|
m_smallObject = false;
|
||||||
|
new (m_small) UniquePtr <LambdaFunctorWrapper> (createUniqueBase <LambdaFunctor <F>, LambdaFunctorWrapper> (cr::move (function)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_smallObject = true;
|
||||||
|
new (m_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.m_smallObject) {
|
||||||
|
reinterpret_cast <LambdaFunctorWrapper *> (rhs.m_small)->move (m_small);
|
||||||
|
new (rhs.m_small) UniquePtr <LambdaFunctorWrapper> (nullptr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
new (m_small) UniquePtr <LambdaFunctorWrapper> (cr::move (rhs.m_functor));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_smallObject = rhs.m_smallObject;
|
||||||
|
rhs.m_smallObject = false;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool () const noexcept {
|
||||||
|
return m_smallObject || !!m_functor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
R operator () (Args ...args) {
|
||||||
|
return m_smallObject ? reinterpret_cast <LambdaFunctorWrapper *> (m_small)->invoke (cr::forward <Args> (args)...) : m_functor->invoke (cr::forward <Args> (args)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
89
include/crlib/cr-library.h
Normal file
89
include/crlib/cr-library.h
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#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>
|
||||||
|
#elif defined (CR_WINDOWS)
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
CR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// handling dynamic library loading
|
||||||
|
class SharedLibrary final : public DenyCopying {
|
||||||
|
private:
|
||||||
|
void *m_handle = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SharedLibrary () = default;
|
||||||
|
|
||||||
|
SharedLibrary (const String &file) {
|
||||||
|
if (file.empty ()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
load (file);
|
||||||
|
}
|
||||||
|
|
||||||
|
~SharedLibrary () {
|
||||||
|
unload ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline bool load (const String &file) noexcept {
|
||||||
|
#ifdef CR_WINDOWS
|
||||||
|
m_handle = LoadLibraryA (file.chars ());
|
||||||
|
#else
|
||||||
|
m_handle = dlopen (file.chars (), RTLD_NOW);
|
||||||
|
#endif
|
||||||
|
return m_handle != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unload () noexcept {
|
||||||
|
if (!*this) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#ifdef CR_WINDOWS
|
||||||
|
FreeLibrary (static_cast <HMODULE> (m_handle));
|
||||||
|
#else
|
||||||
|
dlclose (m_handle);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename R> R resolve (const char *function) const {
|
||||||
|
if (!*this) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return reinterpret_cast <R> (
|
||||||
|
#ifdef CR_WINDOWS
|
||||||
|
GetProcAddress (static_cast <HMODULE> (m_handle), function)
|
||||||
|
#else
|
||||||
|
dlsym (m_handle, function)
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit operator bool () const {
|
||||||
|
return m_handle != nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
98
include/crlib/cr-logger.h
Normal file
98
include/crlib/cr-logger.h
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <crlib/cr-files.h>
|
||||||
|
#include <crlib/cr-lambda.h>
|
||||||
|
|
||||||
|
#if defined (CR_WINDOWS)
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
class SimpleLogger final : public Singleton <SimpleLogger> {
|
||||||
|
public:
|
||||||
|
using PrintFunction = Lambda <void (const char *)>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
File m_handle;
|
||||||
|
PrintFunction m_printer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SimpleLogger () = default;
|
||||||
|
|
||||||
|
~SimpleLogger () {
|
||||||
|
m_handle.close ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void logToFile (const char *level, const char *msg) {
|
||||||
|
if (!m_handle) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
time_t ticks = time (&ticks);
|
||||||
|
auto tm = localtime (&ticks);
|
||||||
|
|
||||||
|
auto timebuf = strings.chars ();
|
||||||
|
strftime (timebuf, StringBuffer::StaticBufferSize, "%Y-%m-%d %H:%M:%S", tm);
|
||||||
|
|
||||||
|
m_handle.puts ("%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 (m_printer) {
|
||||||
|
m_printer (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 (m_printer) {
|
||||||
|
m_printer (msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ...Args> void message (const char *fmt, Args ...args) {
|
||||||
|
auto msg = strings.format (fmt, cr::forward <Args> (args)...);
|
||||||
|
|
||||||
|
logToFile ("INFO", msg);
|
||||||
|
|
||||||
|
if (m_printer) {
|
||||||
|
m_printer (msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
void initialize (const String &filename, PrintFunction printFunction) {
|
||||||
|
if (m_handle) {
|
||||||
|
m_handle.close ();
|
||||||
|
}
|
||||||
|
m_printer = cr::move (printFunction);
|
||||||
|
m_handle.open (filename, "at");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// expose global instance
|
||||||
|
static auto &logger = SimpleLogger::get ();
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
179
include/crlib/cr-math.h
Normal file
179
include/crlib/cr-math.h
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <crlib/cr-basic.h>
|
||||||
|
|
||||||
|
#if defined (CR_HAS_SSE2)
|
||||||
|
# include <immintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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 kMathPiReciprocal = 1.0f / kMathPi;
|
||||||
|
constexpr float kMathPiHalf = kMathPi / 2;
|
||||||
|
|
||||||
|
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 radiansToDegrees (const float r) {
|
||||||
|
return r * kRadiansToDegree;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr float degreesToRadians (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) {
|
||||||
|
const auto sign = static_cast <int32> (value * kMathPiReciprocal);
|
||||||
|
const float calc = (value - static_cast <float> (sign) * kMathPi);
|
||||||
|
|
||||||
|
const float sqr = cr::square (calc);
|
||||||
|
const float res = 1.00000000000000000000e+00f + sqr * (-1.66666671633720397949e-01f + sqr * (8.33333376795053482056e-03f + sqr * (-1.98412497411482036114e-04f +
|
||||||
|
sqr * (2.75565571428160183132e-06f + sqr * (-2.50368472620721149724e-08f + sqr * (1.58849267073435385100e-10f + sqr * -6.58925550841432672300e-13f))))));
|
||||||
|
|
||||||
|
return (sign & 1) ? -calc * res : value * res;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float cosf (const float value) {
|
||||||
|
const auto sign = static_cast <int32> (value * kMathPiReciprocal);
|
||||||
|
const float calc = (value - static_cast <float> (sign) * kMathPi);
|
||||||
|
|
||||||
|
const float sqr = cr::square (calc);
|
||||||
|
const float res = sqr * (-5.00000000000000000000e-01f + sqr * (4.16666641831398010254e-02f + sqr * (-1.38888671062886714935e-03f + sqr * (2.48006890615215525031e-05f +
|
||||||
|
sqr * (-2.75369927749125054106e-07f + sqr * (2.06207229069832465029e-09f + sqr * -9.77507137733812925262e-12f))))));
|
||||||
|
|
||||||
|
const float f = -1.00000000000000000000e+00f;
|
||||||
|
|
||||||
|
return (sign & 1) ? f - res : -f + res;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float atanf (const float x) {
|
||||||
|
const float sqr = cr::square (x);
|
||||||
|
return x * (48.70107004404898384f + sqr * (49.5326263772254345f + sqr * 9.40604244231624f)) / (48.70107004404996166f + sqr * (65.7663163908956299f + sqr * (21.587934067020262f + sqr)));
|
||||||
|
};
|
||||||
|
|
||||||
|
inline float atan2f (const float y, const float x) {
|
||||||
|
const float ax = cr::abs (x);
|
||||||
|
const float ay = cr::abs (y);
|
||||||
|
|
||||||
|
if (ax < 1e-7f && ay < 1e-7f) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ax > ay) {
|
||||||
|
if (x < 0.0f) {
|
||||||
|
if (y >= 0.0f) {
|
||||||
|
return atanf (y / x) + kMathPi;
|
||||||
|
}
|
||||||
|
return atanf (y / x) - kMathPi;
|
||||||
|
}
|
||||||
|
return atanf (y / x);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (y < 0.0f) {
|
||||||
|
return atanf (-x / y) - kMathPiHalf;
|
||||||
|
}
|
||||||
|
return atanf (-x / y) + kMathPiHalf;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float powf (const float x, const float y) {
|
||||||
|
union {
|
||||||
|
float d;
|
||||||
|
int x;
|
||||||
|
} res { x };
|
||||||
|
|
||||||
|
res.x = static_cast <int> (y * (res.x - 1064866805) + 1064866805);
|
||||||
|
return res.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float sqrtf (const float value) {
|
||||||
|
return powf (value, 0.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float tanf (const float value) {
|
||||||
|
return sinf (value) / cosf (value);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr float ceilf (const float x) {
|
||||||
|
return static_cast <float> (65536 - static_cast <int> (65536.0f - x));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sincosf (const float x, const float y, const float z, float *sines, float *cosines) {
|
||||||
|
#if defined (CR_HAS_SSE2)
|
||||||
|
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
|
||||||
58
include/crlib/cr-movable.h
Normal file
58
include/crlib/cr-movable.h
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#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
|
||||||
172
include/crlib/cr-platform.h
Normal file
172
include/crlib/cr-platform.h
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#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
|
||||||
|
#elif defined(__clang__)
|
||||||
|
# define CR_CXX_CLANG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// configure export macros
|
||||||
|
#if defined(CR_WINDOWS)
|
||||||
|
# define CR_EXPORT extern "C" __declspec (dllexport)
|
||||||
|
#elif defined(CR_LINUX) || defined(CR_OSX)
|
||||||
|
# define CR_EXPORT extern "C" __attribute__((visibility("default")))
|
||||||
|
#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(CR_ARCH_X86) || defined(CR_ARCH_X64)) && !defined(CR_DEBUG)
|
||||||
|
# define CR_HAS_SSE2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
|
|
||||||
|
#if defined(CR_WINDOWS)
|
||||||
|
# include <direct.h>
|
||||||
|
# define stricmp _stricmp
|
||||||
|
#else
|
||||||
|
# include <unistd.h>
|
||||||
|
# include <sys/stat.h>
|
||||||
|
# define stricmp strcasecmp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#if defined (CR_ANDROID)
|
||||||
|
# include <android/log.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
CR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// helper struct for platform detection
|
||||||
|
struct Platform : public Singleton <Platform> {
|
||||||
|
bool isWindows = false;
|
||||||
|
bool isLinux = false;
|
||||||
|
bool isOSX = false;
|
||||||
|
bool isAndroid = false;
|
||||||
|
bool isAndroidHardFP = false;
|
||||||
|
bool isX64 = false;
|
||||||
|
|
||||||
|
Platform () {
|
||||||
|
#if defined(CR_WINDOWS)
|
||||||
|
isWindows = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CR_ANDROID)
|
||||||
|
isAndroid = true;
|
||||||
|
|
||||||
|
# if defined (CR_ANDROID_HARD_FP)
|
||||||
|
isAndroidHardFP = true;
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CR_LINUX)
|
||||||
|
isLinux = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (CR_OSX)
|
||||||
|
isOSX = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined (CR_ARCH_X64)
|
||||||
|
isX64 = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 removeDirectory (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
|
||||||
|
}
|
||||||
|
|
||||||
|
void abort (const char *msg = "OUT OF MEMORY!") noexcept {
|
||||||
|
fprintf (stderr, "%s\n", msg);
|
||||||
|
|
||||||
|
#if defined (CR_ANDROID)
|
||||||
|
__android_log_write (ANDROID_LOG_ERROR, "crlib.fatal", msg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CR_WINDOWS)
|
||||||
|
if (msg) {
|
||||||
|
DestroyWindow (GetForegroundWindow ());
|
||||||
|
MessageBoxA (GetActiveWindow (), msg, "crlib.fatal", MB_ICONSTOP);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
::abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// expose platform singleton
|
||||||
|
static auto &plat = Platform::get ();
|
||||||
|
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
66
include/crlib/cr-random.h
Normal file
66
include/crlib/cr-random.h
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <crlib/cr-basic.h>
|
||||||
|
|
||||||
|
CR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// random number generator see: https://github.com/preshing/RandomSequence/
|
||||||
|
class Random final : public Singleton <Random> {
|
||||||
|
private:
|
||||||
|
uint32 m_index, m_offset;
|
||||||
|
uint64 m_divider;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Random () {
|
||||||
|
const auto base = static_cast <uint32> (time (nullptr));
|
||||||
|
const auto offset = base + 1;
|
||||||
|
|
||||||
|
m_index = premute (premute (base) + 0x682f0161);
|
||||||
|
m_offset = premute (premute (offset) + 0x46790905);
|
||||||
|
m_divider = (static_cast <uint64> (1)) << 32;
|
||||||
|
}
|
||||||
|
~Random () = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32 premute (uint32 index) {
|
||||||
|
static constexpr auto prime = 4294967291u;
|
||||||
|
|
||||||
|
if (index >= prime) {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
const uint32 residue = (static_cast <uint64> (index) * index) % prime;
|
||||||
|
return (index <= prime / 2) ? residue : prime - residue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 generate () {
|
||||||
|
return premute ((premute (m_index++) + m_offset) ^ 0x5bf03635);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename U> U int_ (U low, U high) {
|
||||||
|
return static_cast <U> (generate () * (static_cast <double> (high) - static_cast <double> (low) + 1.0) / m_divider + static_cast <double> (low));
|
||||||
|
}
|
||||||
|
|
||||||
|
float float_ (float low, float high) {
|
||||||
|
return static_cast <float> (generate () * (static_cast <double> (high) - static_cast <double> (low)) / (m_divider - 1) + static_cast <double> (low));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U> bool chance (const U max, const U maxChance = 100) {
|
||||||
|
return int_ <U> (0, maxChance) < max;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// expose global random generator
|
||||||
|
static auto &rg = Random::get ();
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
870
include/crlib/cr-string.h
Normal file
870
include/crlib/cr-string.h
Normal file
|
|
@ -0,0 +1,870 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <crlib/cr-basic.h>
|
||||||
|
#include <crlib/cr-alloc.h>
|
||||||
|
#include <crlib/cr-movable.h>
|
||||||
|
#include <crlib/cr-twin.h>
|
||||||
|
#include <crlib/cr-uniqueptr.h>
|
||||||
|
|
||||||
|
CR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// small-string optimized string class, sso stuff based on: https://github.com/elliotgoodrich/SSO-23/
|
||||||
|
class String final {
|
||||||
|
public:
|
||||||
|
static constexpr size_t kInvalidIndex = static_cast <size_t> (-1);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr size_t kExcessSpace = 32;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using Length = Twin <size_t, size_t>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
union Data {
|
||||||
|
struct Big {
|
||||||
|
char excess[kExcessSpace - sizeof (char *) - 2 * sizeof (size_t)];
|
||||||
|
char *ptr;
|
||||||
|
size_t length;
|
||||||
|
size_t capacity;
|
||||||
|
} big;
|
||||||
|
|
||||||
|
struct Small {
|
||||||
|
char str[sizeof (Big) / sizeof (char) - 1];
|
||||||
|
uint8 length;
|
||||||
|
} small;
|
||||||
|
} m_data;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static size_t const kSmallCapacity = sizeof (typename Data::Big) / sizeof (char) - 1;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit String () {
|
||||||
|
reset ();
|
||||||
|
assign ("", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
String (const char *str, size_t length = 0) {
|
||||||
|
reset ();
|
||||||
|
assign (str, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
String (const String &str) {
|
||||||
|
reset ();
|
||||||
|
assign (str.data (), str.length ());
|
||||||
|
}
|
||||||
|
|
||||||
|
String (const char ch) {
|
||||||
|
reset ();
|
||||||
|
assign (ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
String (String &&rhs) noexcept {
|
||||||
|
m_data = rhs.m_data;
|
||||||
|
rhs.setMoved ();
|
||||||
|
}
|
||||||
|
|
||||||
|
~String () {
|
||||||
|
destroy ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename T> static uint8 &getMostSignificantByte (T &object) {
|
||||||
|
return *(reinterpret_cast <uint8 *> (&object) + sizeof (object) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N> static bool getLeastSignificantBit (uint8 byte) {
|
||||||
|
return byte & cr::bit (N);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N> static bool getMostSignificantBit (uint8 byte) {
|
||||||
|
return byte & cr::bit (CHAR_BIT - N - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N> static void setLeastSignificantBit (uint8 &byte, bool bit) {
|
||||||
|
if (bit) {
|
||||||
|
byte |= cr::bit (N);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
byte &= ~cr::bit (N);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t N> static void setMostSignificantBit (uint8 &byte, bool bit) {
|
||||||
|
if (bit) {
|
||||||
|
byte |= cr::bit (CHAR_BIT - N - 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
byte &= ~cr::bit (CHAR_BIT - N - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy () {
|
||||||
|
if (!isSmall ()) {
|
||||||
|
alloc.deallocate (m_data.big.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset () {
|
||||||
|
m_data.small.length = 0;
|
||||||
|
m_data.small.str[0] = '\0';
|
||||||
|
|
||||||
|
m_data.big.ptr = nullptr;
|
||||||
|
m_data.big.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void endString (const char *str, size_t at) {
|
||||||
|
const_cast <char *> (str)[at] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void moveString (const char *dst, const char *src, size_t length) {
|
||||||
|
if (!dst) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memmove (const_cast <char *> (dst), src, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *data () const {
|
||||||
|
return isSmall () ? m_data.small.str : m_data.big.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMoved () {
|
||||||
|
setSmallLength (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLength (size_t amount, size_t capacity) {
|
||||||
|
if (amount <= kSmallCapacity) {
|
||||||
|
endString (m_data.small.str, amount);
|
||||||
|
setSmallLength (static_cast <uint8> (amount));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
endString (m_data.big.ptr, amount);
|
||||||
|
setDataNonSmall (amount, capacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isSmall () const {
|
||||||
|
return !getLeastSignificantBit <0> (m_data.small.length) && !getLeastSignificantBit <1> (m_data.small.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSmallLength (uint8 length) {
|
||||||
|
m_data.small.length = static_cast <char> (kSmallCapacity - length) << 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getSmallLength () const {
|
||||||
|
return kSmallCapacity - ((m_data.small.length >> 2) & 63u);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDataNonSmall (size_t length, size_t capacity) {
|
||||||
|
uint8 &lengthHighByte = getMostSignificantByte (length);
|
||||||
|
uint8 &capacityHighByte = getMostSignificantByte (capacity);
|
||||||
|
|
||||||
|
const bool lengthHasHighBit = getMostSignificantBit <0> (lengthHighByte);
|
||||||
|
const bool capacityHasHighBit = getMostSignificantBit <0> (capacityHighByte);
|
||||||
|
const bool capacityHasSecHighBit = getMostSignificantBit <1> (capacityHighByte);
|
||||||
|
|
||||||
|
setMostSignificantBit <0> (lengthHighByte, capacityHasSecHighBit);
|
||||||
|
|
||||||
|
capacityHighByte <<= 2;
|
||||||
|
setLeastSignificantBit <0> (capacityHighByte, capacityHasHighBit);
|
||||||
|
setLeastSignificantBit <1> (capacityHighByte, !lengthHasHighBit);
|
||||||
|
|
||||||
|
m_data.big.length = length;
|
||||||
|
m_data.big.capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
Length getDataNonSmall () const {
|
||||||
|
size_t length = m_data.big.length;
|
||||||
|
size_t capacity = m_data.big.capacity;
|
||||||
|
|
||||||
|
uint8 &lengthHighByte = getMostSignificantByte (length);
|
||||||
|
uint8 &capacityHighByte = getMostSignificantByte (capacity);
|
||||||
|
|
||||||
|
const bool capacityHasHighBit = getLeastSignificantBit <0> (capacityHighByte);
|
||||||
|
const bool lengthHasHighBit = !getLeastSignificantBit <1> (capacityHighByte);
|
||||||
|
const bool capacityHasSecHighBit = getMostSignificantBit <0> (lengthHighByte);
|
||||||
|
|
||||||
|
setMostSignificantBit <0> (lengthHighByte, lengthHasHighBit);
|
||||||
|
|
||||||
|
capacityHighByte >>= 2;
|
||||||
|
setMostSignificantBit <0> (capacityHighByte, capacityHasHighBit);
|
||||||
|
setMostSignificantBit <1> (capacityHighByte, capacityHasSecHighBit);
|
||||||
|
|
||||||
|
return { length, capacity };
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
String &assign (const char *str, size_t length = 0) {
|
||||||
|
length = length > 0 ? length : strlen (str);
|
||||||
|
|
||||||
|
if (length <= kSmallCapacity) {
|
||||||
|
moveString (m_data.small.str, str, length);
|
||||||
|
|
||||||
|
endString (m_data.small.str, length);
|
||||||
|
setSmallLength (static_cast <uint8> (length));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto capacity = cr::max (kSmallCapacity * 2, length);
|
||||||
|
m_data.big.ptr = alloc.allocate <char> (capacity + 1);
|
||||||
|
|
||||||
|
if (m_data.big.ptr) {
|
||||||
|
moveString (m_data.big.ptr, str, length);
|
||||||
|
|
||||||
|
endString (m_data.big.ptr, length);
|
||||||
|
setDataNonSmall (length, capacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String &assign (const String &str, size_t length = 0) {
|
||||||
|
return assign (str.chars (), length);
|
||||||
|
}
|
||||||
|
|
||||||
|
String &assign (const char ch) {
|
||||||
|
const char str[] { ch, '\0' };
|
||||||
|
return assign (str, strlen (str));
|
||||||
|
}
|
||||||
|
|
||||||
|
String &append (const char *str, size_t length = 0) {
|
||||||
|
if (empty ()) {
|
||||||
|
return assign (str, length);
|
||||||
|
}
|
||||||
|
length = length > 0 ? length : strlen (str);
|
||||||
|
|
||||||
|
size_t oldLength = this->length ();
|
||||||
|
size_t newLength = oldLength + length;
|
||||||
|
|
||||||
|
resize (newLength);
|
||||||
|
|
||||||
|
moveString (&data ()[oldLength], str, length);
|
||||||
|
endString (data (), newLength);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String &append (const String &str, size_t length = 0) {
|
||||||
|
return append (str.chars (), length);
|
||||||
|
}
|
||||||
|
|
||||||
|
String &append (const char ch) {
|
||||||
|
const char str[] { ch, '\0' };
|
||||||
|
return append (str, strlen (str));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ...Args> String &assignf (const char *fmt, Args ...args) {
|
||||||
|
const size_t size = snprintf (nullptr, 0, fmt, args...);
|
||||||
|
|
||||||
|
Array <char, ReservePolicy::PlusOne> buffer (size + 1);
|
||||||
|
snprintf (buffer.data (), size + 1, fmt, cr::forward <Args> (args)...);
|
||||||
|
|
||||||
|
return assign (buffer.data ());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ...Args> String &appendf (const char *fmt, Args ...args) {
|
||||||
|
if (empty ()) {
|
||||||
|
return assignf (fmt, cr::forward <Args> (args)...);
|
||||||
|
}
|
||||||
|
const size_t size = snprintf (nullptr, 0, fmt, args...) + length ();
|
||||||
|
|
||||||
|
Array <char, ReservePolicy::PlusOne> buffer (size + 1);
|
||||||
|
snprintf (buffer.data (), size + 1, fmt, cr::forward <Args> (args)...);
|
||||||
|
|
||||||
|
return append (buffer.data ());
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize (size_t amount) {
|
||||||
|
size_t oldLength = length ();
|
||||||
|
|
||||||
|
if (amount <= kSmallCapacity) {
|
||||||
|
if (!isSmall ()) {
|
||||||
|
auto ptr = m_data.big.ptr;
|
||||||
|
|
||||||
|
moveString (m_data.small.str, ptr, cr::min (oldLength, amount));
|
||||||
|
alloc.deallocate (ptr);
|
||||||
|
}
|
||||||
|
setLength (amount, 0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
size_t newCapacity = 0;
|
||||||
|
|
||||||
|
if (isSmall ()) {
|
||||||
|
newCapacity = cr::max (amount, kSmallCapacity * 2);
|
||||||
|
auto ptr = alloc.allocate <char> (newCapacity + 1);
|
||||||
|
|
||||||
|
moveString (ptr, m_data.small.str, cr::min (oldLength, amount));
|
||||||
|
m_data.big.ptr = ptr;
|
||||||
|
}
|
||||||
|
else if (amount < capacity ()) {
|
||||||
|
newCapacity = capacity ();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newCapacity = cr::max (amount, capacity () * 3 / 2);
|
||||||
|
auto ptr = alloc.allocate <char> (newCapacity + 1);
|
||||||
|
|
||||||
|
moveString (ptr, m_data.big.ptr, cr::min (oldLength, amount));
|
||||||
|
alloc.deallocate (m_data.big.ptr);
|
||||||
|
|
||||||
|
m_data.big.ptr = ptr;
|
||||||
|
}
|
||||||
|
setLength (amount, newCapacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool insert (size_t index, const String &str) {
|
||||||
|
if (str.empty ()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t strLength = str.length ();
|
||||||
|
const size_t dataLength = length ();
|
||||||
|
|
||||||
|
if (index >= dataLength) {
|
||||||
|
append (str.chars (), strLength);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resize (dataLength + strLength);
|
||||||
|
|
||||||
|
for (size_t i = dataLength; i > index; --i) {
|
||||||
|
at (i + strLength - 1) = at (i - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < strLength; ++i) {
|
||||||
|
at (i + index) = str.at (i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool erase (size_t index, size_t count = 1) {
|
||||||
|
const size_t dataLength = length ();
|
||||||
|
|
||||||
|
if (index + count > dataLength) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const size_t newLength = dataLength - count;
|
||||||
|
|
||||||
|
for (size_t i = index; i < newLength; ++i) {
|
||||||
|
at (i) = at (i + count);
|
||||||
|
}
|
||||||
|
resize (newLength);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t find (char pattern, size_t start = 0) const {
|
||||||
|
for (size_t i = start; i < length (); ++i) {
|
||||||
|
if (at (i) == pattern) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kInvalidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t find (const String &pattern, size_t start = 0) const {
|
||||||
|
const size_t patternLength = pattern.length ();
|
||||||
|
const size_t dataLength = length ();
|
||||||
|
|
||||||
|
if (patternLength > dataLength || start > dataLength) {
|
||||||
|
return kInvalidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = start; i <= dataLength - patternLength; ++i) {
|
||||||
|
size_t index = 0;
|
||||||
|
|
||||||
|
for (; at (index) && index < patternLength; ++index) {
|
||||||
|
if (at (i + index) != pattern.at (index)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pattern.at (index)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kInvalidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t rfind (char pattern) const {
|
||||||
|
for (size_t i = length (); i != 0; i--) {
|
||||||
|
if (at (i) == pattern) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kInvalidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t rfind (const String &pattern) const {
|
||||||
|
const size_t patternLength = pattern.length ();
|
||||||
|
const size_t dataLength = length ();
|
||||||
|
|
||||||
|
if (patternLength > dataLength) {
|
||||||
|
return kInvalidIndex;
|
||||||
|
}
|
||||||
|
bool match = true;
|
||||||
|
|
||||||
|
for (size_t i = dataLength - 1; i >= patternLength; i--) {
|
||||||
|
match = true;
|
||||||
|
|
||||||
|
for (size_t j = patternLength - 1; j > 0; j--) {
|
||||||
|
if (at (i + j) != pattern.at (j)) {
|
||||||
|
match = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kInvalidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t findFirstOf (const String &pattern, size_t start = 0) const {
|
||||||
|
const size_t patternLength = pattern.length ();
|
||||||
|
const size_t dataLength = length ();
|
||||||
|
|
||||||
|
for (size_t i = start; i < dataLength; ++i) {
|
||||||
|
for (size_t j = 0; j < patternLength; ++j) {
|
||||||
|
if (at (i) == pattern.at (j)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kInvalidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t findLastOf (const String &pattern) const {
|
||||||
|
const size_t patternLength = pattern.length ();
|
||||||
|
const size_t dataLength = length ();
|
||||||
|
|
||||||
|
for (size_t i = dataLength - 1; i > 0; i--) {
|
||||||
|
for (size_t j = 0; j < patternLength; ++j) {
|
||||||
|
if (at (i) == pattern.at (j)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kInvalidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t findFirstNotOf (const String &pattern, size_t start = 0) const {
|
||||||
|
const size_t patternLength = pattern.length ();
|
||||||
|
const size_t dataLength = length ();
|
||||||
|
|
||||||
|
bool different = true;
|
||||||
|
|
||||||
|
for (size_t i = start; i < dataLength; ++i) {
|
||||||
|
different = true;
|
||||||
|
|
||||||
|
for (size_t j = 0; j < patternLength; ++j) {
|
||||||
|
if (at (i) == pattern.at (j)) {
|
||||||
|
different = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (different) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kInvalidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t findLastNotOf (const String &pattern) const {
|
||||||
|
const size_t patternLength = pattern.length ();
|
||||||
|
const size_t dataLength = length ();
|
||||||
|
|
||||||
|
bool different = true;
|
||||||
|
|
||||||
|
for (size_t i = dataLength - 1; i > 0; i--) {
|
||||||
|
different = true;
|
||||||
|
|
||||||
|
for (size_t j = 0; j < patternLength; ++j) {
|
||||||
|
if (at (i) == pattern.at (j)) {
|
||||||
|
different = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (different) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kInvalidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
size_t countChar (char ch) const {
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0, e = length (); i != e; ++i) {
|
||||||
|
if (at (i) == ch) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t countStr (const String &pattern) const {
|
||||||
|
const size_t patternLen = pattern.length ();
|
||||||
|
const size_t dataLength = length ();
|
||||||
|
|
||||||
|
if (patternLen > dataLength) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0, e = dataLength - patternLen + 1; i != e; ++i) {
|
||||||
|
if (substr (i, patternLen).compare (pattern)) {
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
String substr (size_t start, size_t count = kInvalidIndex) const {
|
||||||
|
start = cr::min (start, length ());
|
||||||
|
|
||||||
|
if (count == kInvalidIndex) {
|
||||||
|
count = length ();
|
||||||
|
}
|
||||||
|
return String (data () + start, cr::min (count, length () - start));
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t replace (const String &needle, const String &to) {
|
||||||
|
if (needle.empty () || to.empty ()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t replaced = 0, pos = 0;
|
||||||
|
|
||||||
|
while (pos < length ()) {
|
||||||
|
pos = find (needle, pos);
|
||||||
|
|
||||||
|
if (pos == kInvalidIndex) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
erase (pos, needle.length ());
|
||||||
|
insert (pos, to);
|
||||||
|
|
||||||
|
pos += to.length ();
|
||||||
|
replaced++;
|
||||||
|
}
|
||||||
|
return replaced;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool startsWith (const String &prefix) const {
|
||||||
|
const size_t prefixLength = prefix.length ();
|
||||||
|
const size_t dataLength = length ();
|
||||||
|
|
||||||
|
return prefixLength <= dataLength && strncmp (data (), prefix.data (), prefixLength) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool endsWith (const String &suffix) const {
|
||||||
|
const size_t suffixLength = suffix.length ();
|
||||||
|
const size_t dataLength = length ();
|
||||||
|
|
||||||
|
return suffixLength <= dataLength && strncmp (data () + dataLength - suffixLength, suffix.data (), suffixLength) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Array <String> split (const String &delim) const {
|
||||||
|
Array <String> tokens;
|
||||||
|
size_t prev = 0, pos = 0;
|
||||||
|
|
||||||
|
while ((pos = find (delim, pos)) != kInvalidIndex) {
|
||||||
|
tokens.push (substr (prev, pos - prev));
|
||||||
|
prev = ++pos;
|
||||||
|
}
|
||||||
|
tokens.push (substr (prev, pos - prev));
|
||||||
|
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length () const {
|
||||||
|
if (isSmall ()) {
|
||||||
|
return getSmallLength ();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return getDataNonSmall ().first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t capacity () const {
|
||||||
|
if (isSmall ()) {
|
||||||
|
return sizeof (m_data) - 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return getDataNonSmall ().second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool small () const {
|
||||||
|
return isSmall ();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty () const {
|
||||||
|
return length () == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear () {
|
||||||
|
assign ("");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *chars () const {
|
||||||
|
return data ();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char &at (size_t index) const {
|
||||||
|
return begin ()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
char &at (size_t index) {
|
||||||
|
return begin ()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 compare (const String &rhs) const {
|
||||||
|
return strcmp (rhs.data (), data ());
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 compare (const char *rhs) const {
|
||||||
|
return strcmp (rhs, data ());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains (const String &rhs) const {
|
||||||
|
return find (rhs) != kInvalidIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
String &lowercase () {
|
||||||
|
for (auto &ch : *this) {
|
||||||
|
ch = static_cast <char> (::tolower (ch));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String &uppercase () {
|
||||||
|
for (auto &ch : *this) {
|
||||||
|
ch = static_cast <char> (::toupper (ch));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 int_ () const {
|
||||||
|
return atoi (data ());
|
||||||
|
}
|
||||||
|
|
||||||
|
float float_ () const {
|
||||||
|
return static_cast <float> (atof (data ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
String <rim (const String &characters = "\r\n\t ") {
|
||||||
|
size_t begin = length ();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < begin; ++i) {
|
||||||
|
if (characters.find (at (i)) == kInvalidIndex) {
|
||||||
|
begin = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this = substr (begin, length () - begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
String &rtrim (const String &characters = "\r\n\t ") {
|
||||||
|
size_t end = 0;
|
||||||
|
|
||||||
|
for (size_t i = length (); i > 0; --i) {
|
||||||
|
if (characters.find (at (i - 1)) == kInvalidIndex) {
|
||||||
|
end = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this = substr (0, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
String &trim (const String &characters = "\r\n\t ") {
|
||||||
|
return ltrim (characters).rtrim (characters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
String &operator = (String &&rhs) noexcept {
|
||||||
|
destroy ();
|
||||||
|
|
||||||
|
m_data = rhs.m_data;
|
||||||
|
rhs.setMoved ();
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
String &operator = (const String &rhs) {
|
||||||
|
return assign (rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
String &operator = (const char *rhs) {
|
||||||
|
return assign (rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
String &operator = (char rhs) {
|
||||||
|
return assign (rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
String &operator += (const String &rhs) {
|
||||||
|
return append (rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
String &operator += (const char *rhs) {
|
||||||
|
return append (rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char &operator [] (size_t index) const {
|
||||||
|
return at (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
char &operator [] (size_t index) {
|
||||||
|
return at (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend String operator + (const String &lhs, char rhs) {
|
||||||
|
return String (lhs).append (rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend String operator + (char lhs, const String &rhs) {
|
||||||
|
return String (lhs).append (rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend String operator + (const String &lhs, const char *rhs) {
|
||||||
|
return String (lhs).append (rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend String operator + (const char *lhs, const String &rhs) {
|
||||||
|
return String (lhs).append (rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend String operator + (const String &lhs, const String &rhs) {
|
||||||
|
return String (lhs).append (rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator == (const String &lhs, const String &rhs) {
|
||||||
|
return lhs.compare (rhs) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator < (const String &lhs, const String &rhs) {
|
||||||
|
return lhs.compare (rhs) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator > (const String &lhs, const String &rhs) {
|
||||||
|
return lhs.compare (rhs) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator == (const char *lhs, const String &rhs) {
|
||||||
|
return rhs.compare (lhs) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator == (const String &lhs, const char *rhs) {
|
||||||
|
return lhs.compare (rhs) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator != (const String &lhs, const String &rhs) {
|
||||||
|
return lhs.compare (rhs) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator != (const char *lhs, const String &rhs) {
|
||||||
|
return rhs.compare (lhs) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator != (const String &lhs, const char *rhs) {
|
||||||
|
return lhs.compare (rhs) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static String join (const Array <String> &sequence, const String &delim, size_t start = 0) {
|
||||||
|
if (sequence.empty ()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sequence.length () == 1) {
|
||||||
|
return sequence.at (0);
|
||||||
|
}
|
||||||
|
String result;
|
||||||
|
|
||||||
|
for (size_t index = start; index < sequence.length (); ++index) {
|
||||||
|
if (index != start) {
|
||||||
|
result += delim + sequence[index];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result += sequence[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for range-based loops
|
||||||
|
public:
|
||||||
|
char *begin () {
|
||||||
|
return const_cast <char *> (data ());
|
||||||
|
}
|
||||||
|
|
||||||
|
char *begin () const {
|
||||||
|
return const_cast <char *> (data ());
|
||||||
|
}
|
||||||
|
|
||||||
|
char *end () {
|
||||||
|
return begin () + length ();
|
||||||
|
}
|
||||||
|
|
||||||
|
char *end () const {
|
||||||
|
return begin () + length ();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// simple rotation-string pool for holding temporary data passed to different modules and for formatting
|
||||||
|
class StringBuffer final : public Singleton <StringBuffer> {
|
||||||
|
public:
|
||||||
|
enum : size_t {
|
||||||
|
StaticBufferSize = static_cast <size_t> (768),
|
||||||
|
RotationCount = static_cast <size_t> (32)
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
char m_data[RotationCount + 1][StaticBufferSize] {};
|
||||||
|
size_t m_rotate = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StringBuffer () = default;
|
||||||
|
~StringBuffer () = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
char *chars () {
|
||||||
|
if (++m_rotate >= RotationCount) {
|
||||||
|
m_rotate = 0;
|
||||||
|
}
|
||||||
|
return m_data[cr::clamp <size_t> (m_rotate, 0, RotationCount)];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U, typename ...Args> U *format (const U *fmt, Args ...args) {
|
||||||
|
auto buffer = Singleton <StringBuffer>::get ().chars ();
|
||||||
|
snprintf (buffer, StaticBufferSize, fmt, args...);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U> U *format (const U *fmt) {
|
||||||
|
auto buffer = Singleton <StringBuffer>::get ().chars ();
|
||||||
|
strncpy (buffer, fmt, StaticBufferSize);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// expose global string pool
|
||||||
|
static auto &strings = StringBuffer::get ();
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
75
include/crlib/cr-twin.h
Normal file
75
include/crlib/cr-twin.h
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#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 {
|
||||||
|
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 a.second <= b.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator > (const Twin &a, const Twin &b) {
|
||||||
|
return b.second < a.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator >= (const Twin &a, const Twin &b) {
|
||||||
|
return b.second <= a.second;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// creating pairs
|
||||||
|
template <typename A, typename B> constexpr Twin <A, B> makeTwin (A &&a, B &&b) {
|
||||||
|
return Twin <A, B> (cr::forward <A> (a), cr::forward <B> (b));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename A, typename B> constexpr Twin <A, B> makeTwin (const A &a, const B &b) {
|
||||||
|
return Twin <A, B> (a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
|
|
@ -9,62 +9,69 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <crlib/cr-array.h>
|
||||||
|
|
||||||
|
CR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
// see https://github.com/encode84/ulz/
|
// see https://github.com/encode84/ulz/
|
||||||
class FastLZ final : NonCopyable {
|
class ULZ final : DenyCopying {
|
||||||
public:
|
public:
|
||||||
static constexpr int EXCESS = 16;
|
enum : int32 {
|
||||||
static constexpr int WINDOW_BITS = 17;
|
Excess = 16,
|
||||||
static constexpr int WINDOW_SIZE = cr::bit (WINDOW_BITS);
|
UncompressFailure = -1
|
||||||
static constexpr int WINDOW_MASK = WINDOW_SIZE - 1;
|
};
|
||||||
|
|
||||||
static constexpr int MIN_MATCH = 4;
|
|
||||||
static constexpr int MAX_CHAIN = cr::bit (5);
|
|
||||||
|
|
||||||
static constexpr int HASH_BITS = 19;
|
|
||||||
static constexpr int HASH_SIZE = cr::bit (HASH_BITS);
|
|
||||||
static constexpr int NIL = -1;
|
|
||||||
static constexpr int UNCOMPRESS_RESULT_FAILED = -1;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int *m_hashTable;
|
enum : int32 {
|
||||||
int *m_prevTable;
|
WindowBits = 17,
|
||||||
|
WindowSize = cr::bit (WindowBits),
|
||||||
|
WindowMask = WindowSize - 1,
|
||||||
|
|
||||||
|
MinMatch = 4,
|
||||||
|
MaxChain = cr::bit (5),
|
||||||
|
|
||||||
|
HashBits = 19,
|
||||||
|
HashLength = cr::bit (HashBits),
|
||||||
|
EmptyHash = -1,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
Array <int32, ReservePolicy::PlusOne> m_hashTable;
|
||||||
|
Array <int32, ReservePolicy::PlusOne> m_prevTable;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FastLZ (void) {
|
ULZ () {
|
||||||
m_hashTable = new int[HASH_SIZE];
|
m_hashTable.resize (HashLength);
|
||||||
m_prevTable = new int[WINDOW_SIZE];
|
m_prevTable.resize (WindowSize);
|
||||||
}
|
|
||||||
|
|
||||||
~FastLZ (void) {
|
|
||||||
delete [] m_hashTable;
|
|
||||||
delete [] m_prevTable;
|
|
||||||
}
|
}
|
||||||
|
~ULZ () = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int compress (uint8 *in, int inLength, uint8 *out) {
|
int32 compress (uint8 *in, int32 inputLength, uint8 *out) {
|
||||||
for (int i = 0; i < HASH_SIZE; i++) {
|
for (auto &htb : m_hashTable) {
|
||||||
m_hashTable[i] = NIL;
|
htb = EmptyHash;
|
||||||
}
|
}
|
||||||
uint8 *op = out;
|
uint8 *op = out;
|
||||||
|
|
||||||
int anchor = 0;
|
int32 anchor = 0;
|
||||||
int cur = 0;
|
int32 cur = 0;
|
||||||
|
|
||||||
while (cur < inLength) {
|
while (cur < inputLength) {
|
||||||
const int maxMatch = inLength - cur;
|
const int32 maxMatch = inputLength - cur;
|
||||||
|
|
||||||
int bestLength = 0;
|
int32 bestLength = 0;
|
||||||
int dist = 0;
|
int32 dist = 0;
|
||||||
|
|
||||||
if (maxMatch >= MIN_MATCH) {
|
if (maxMatch >= MinMatch) {
|
||||||
const int limit = cr::max (cur - WINDOW_SIZE, NIL);
|
const int32 limit = cr::max <int32> (cur - WindowSize, EmptyHash);
|
||||||
|
|
||||||
int chainLength = MAX_CHAIN;
|
int32 chainLength = MaxChain;
|
||||||
int lookup = m_hashTable[hash32 (&in[cur])];
|
int32 lookup = m_hashTable[hash32 (&in[cur])];
|
||||||
|
|
||||||
while (lookup > limit) {
|
while (lookup > limit) {
|
||||||
if (in[lookup + bestLength] == in[cur + bestLength] && load32 (&in[lookup]) == load32 (&in[cur])) {
|
if (in[lookup + bestLength] == in[cur + bestLength] && load32 (&in[lookup]) == load32 (&in[cur])) {
|
||||||
int length = MIN_MATCH;
|
int32 length = MinMatch;
|
||||||
|
|
||||||
while (length < maxMatch && in[lookup + length] == in[cur + length]) {
|
while (length < maxMatch && in[lookup + length] == in[cur + length]) {
|
||||||
length++;
|
length++;
|
||||||
|
|
@ -83,31 +90,31 @@ public:
|
||||||
if (--chainLength == 0) {
|
if (--chainLength == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
lookup = m_prevTable[lookup & WINDOW_MASK];
|
lookup = m_prevTable[lookup & WindowMask];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bestLength == MIN_MATCH && (cur - anchor) >= (7 + 128)) {
|
if (bestLength == MinMatch && (cur - anchor) >= (7 + 128)) {
|
||||||
bestLength = 0;
|
bestLength = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bestLength >= MIN_MATCH && bestLength < maxMatch && (cur - anchor) != 6) {
|
if (bestLength >= MinMatch && bestLength < maxMatch && (cur - anchor) != 6) {
|
||||||
const int next = cur + 1;
|
const int32 next = cur + 1;
|
||||||
const int targetLength = bestLength + 1;
|
const int32 target = bestLength + 1;
|
||||||
const int limit = cr::max (next - WINDOW_SIZE, NIL);
|
const int32 limit = cr::max <int32> (next - WindowSize, EmptyHash);
|
||||||
|
|
||||||
int chainLength = MAX_CHAIN;
|
int32 chainLength = MaxChain;
|
||||||
int lookup = m_hashTable[hash32 (&in[next])];
|
int32 lookup = m_hashTable[hash32 (&in[next])];
|
||||||
|
|
||||||
while (lookup > limit) {
|
while (lookup > limit) {
|
||||||
if (in[lookup + bestLength] == in[next + bestLength] && load32 (&in[lookup]) == load32 (&in[next])) {
|
if (in[lookup + bestLength] == in[next + bestLength] && load32 (&in[lookup]) == load32 (&in[next])) {
|
||||||
int length = MIN_MATCH;
|
int32 length = MinMatch;
|
||||||
|
|
||||||
while (length < targetLength && in[lookup + length] == in[next + length]) {
|
while (length < target && in[lookup + length] == in[next + length]) {
|
||||||
length++;
|
length++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length == targetLength) {
|
if (length == target) {
|
||||||
bestLength = 0;
|
bestLength = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -116,16 +123,16 @@ public:
|
||||||
if (--chainLength == 0) {
|
if (--chainLength == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
lookup = m_prevTable[lookup & WINDOW_MASK];
|
lookup = m_prevTable[lookup & WindowMask];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bestLength >= MIN_MATCH) {
|
if (bestLength >= MinMatch) {
|
||||||
const int length = bestLength - MIN_MATCH;
|
const int32 length = bestLength - MinMatch;
|
||||||
const int token = ((dist >> 12) & 16) + cr::min (length, 15);
|
const int32 token = ((dist >> 12) & 16) + cr::min <int32> (length, 15);
|
||||||
|
|
||||||
if (anchor != cur) {
|
if (anchor != cur) {
|
||||||
const int run = cur - anchor;
|
const int32 run = cur - anchor;
|
||||||
|
|
||||||
if (run >= 7) {
|
if (run >= 7) {
|
||||||
add (op, (7 << 5) + token);
|
add (op, (7 << 5) + token);
|
||||||
|
|
@ -150,7 +157,7 @@ public:
|
||||||
while (bestLength-- != 0) {
|
while (bestLength-- != 0) {
|
||||||
const uint32 hash = hash32 (&in[cur]);
|
const uint32 hash = hash32 (&in[cur]);
|
||||||
|
|
||||||
m_prevTable[cur & WINDOW_MASK] = m_hashTable[hash];
|
m_prevTable[cur & WindowMask] = m_hashTable[hash];
|
||||||
m_hashTable[hash] = cur++;
|
m_hashTable[hash] = cur++;
|
||||||
}
|
}
|
||||||
anchor = cur;
|
anchor = cur;
|
||||||
|
|
@ -158,13 +165,13 @@ public:
|
||||||
else {
|
else {
|
||||||
const uint32 hash = hash32 (&in[cur]);
|
const uint32 hash = hash32 (&in[cur]);
|
||||||
|
|
||||||
m_prevTable[cur & WINDOW_MASK] = m_hashTable[hash];
|
m_prevTable[cur & WindowMask] = m_hashTable[hash];
|
||||||
m_hashTable[hash] = cur++;
|
m_hashTable[hash] = cur++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (anchor != cur) {
|
if (anchor != cur) {
|
||||||
const int run = cur - anchor;
|
const int32 run = cur - anchor;
|
||||||
|
|
||||||
if (run >= 7) {
|
if (run >= 7) {
|
||||||
add (op, 7 << 5);
|
add (op, 7 << 5);
|
||||||
|
|
@ -179,25 +186,25 @@ public:
|
||||||
return op - out;
|
return op - out;
|
||||||
}
|
}
|
||||||
|
|
||||||
int uncompress (uint8 *in, int inLength, uint8 *out, int outLength) {
|
int32 uncompress (uint8 *in, int32 inputLength, uint8 *out, int32 outLength) {
|
||||||
uint8 *op = out;
|
uint8 *op = out;
|
||||||
uint8 *ip = in;
|
uint8 *ip = in;
|
||||||
|
|
||||||
const uint8 *opEnd = op + outLength;
|
const uint8 *opEnd = op + outLength;
|
||||||
const uint8 *ipEnd = ip + inLength;
|
const uint8 *ipEnd = ip + inputLength;
|
||||||
|
|
||||||
while (ip < ipEnd) {
|
while (ip < ipEnd) {
|
||||||
const int token = *ip++;
|
const int32 token = *ip++;
|
||||||
|
|
||||||
if (token >= 32) {
|
if (token >= 32) {
|
||||||
int run = token >> 5;
|
int32 run = token >> 5;
|
||||||
|
|
||||||
if (run == 7) {
|
if (run == 7) {
|
||||||
run += decode (ip);
|
run += decode (ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((opEnd - op) < run || (ipEnd - ip) < run) {
|
if ((opEnd - op) < run || (ipEnd - ip) < run) {
|
||||||
return UNCOMPRESS_RESULT_FAILED;
|
return UncompressFailure;
|
||||||
}
|
}
|
||||||
copy (op, ip, run);
|
copy (op, ip, run);
|
||||||
|
|
||||||
|
|
@ -208,22 +215,22 @@ public:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int length = (token & 15) + MIN_MATCH;
|
int32 length = (token & 15) + MinMatch;
|
||||||
|
|
||||||
if (length == (15 + MIN_MATCH)) {
|
if (length == (15 + MinMatch)) {
|
||||||
length += decode (ip);
|
length += decode (ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((opEnd - op) < length) {
|
if ((opEnd - op) < length) {
|
||||||
return UNCOMPRESS_RESULT_FAILED;
|
return UncompressFailure;
|
||||||
}
|
}
|
||||||
const int dist = ((token & 16) << 12) + load16 (ip);
|
const int32 dist = ((token & 16) << 12) + load16 (ip);
|
||||||
ip += 2;
|
ip += 2;
|
||||||
|
|
||||||
uint8 *cp = op - dist;
|
uint8 *cp = op - dist;
|
||||||
|
|
||||||
if ((op - out) < dist) {
|
if ((op - out) < dist) {
|
||||||
return UNCOMPRESS_RESULT_FAILED;
|
return UncompressFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dist >= 8) {
|
if (dist >= 8) {
|
||||||
|
|
@ -232,7 +239,7 @@ public:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int32 i = 0; i < 4; ++i) {
|
||||||
*op++ = *cp++;
|
*op++ = *cp++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -241,7 +248,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (ip == ipEnd) ? op - out : UNCOMPRESS_RESULT_FAILED;
|
return static_cast <int32> (ip == ipEnd) ? static_cast <int32> (op - out) : UncompressFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -253,7 +260,7 @@ private:
|
||||||
return *reinterpret_cast <const uint32 *> (ptr);
|
return *reinterpret_cast <const uint32 *> (ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void store16 (void *ptr, int val) {
|
inline void store16 (void *ptr, int32 val) {
|
||||||
*reinterpret_cast <uint16 *> (ptr) = static_cast <uint16> (val);
|
*reinterpret_cast <uint16 *> (ptr) = static_cast <uint16> (val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -262,18 +269,18 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32 hash32 (void *ptr) {
|
inline uint32 hash32 (void *ptr) {
|
||||||
return (load32 (ptr) * 0x9E3779B9) >> (32 - HASH_BITS);
|
return (load32 (ptr) * 0x9E3779B9) >> (32 - HashBits);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void copy (uint8 *dst, uint8 *src, int count) {
|
inline void copy (uint8 *dst, uint8 *src, int32 count) {
|
||||||
copy64 (dst, src);
|
copy64 (dst, src);
|
||||||
|
|
||||||
for (int i = 8; i < count; i += 8) {
|
for (int32 i = 8; i < count; i += 8) {
|
||||||
copy64 (dst + i, src + i);
|
copy64 (dst + i, src + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void add (uint8 *&dst, int val) {
|
inline void add (uint8 *&dst, int32 val) {
|
||||||
*dst++ = static_cast <uint8> (val);
|
*dst++ = static_cast <uint8> (val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -290,7 +297,7 @@ private:
|
||||||
inline uint32 decode (uint8 *&ptr) {
|
inline uint32 decode (uint8 *&ptr) {
|
||||||
uint32 val = 0;
|
uint32 val = 0;
|
||||||
|
|
||||||
for (int i = 0; i <= 21; i += 7) {
|
for (int32 i = 0; i <= 21; i += 7) {
|
||||||
const uint32 cur = *ptr++;
|
const uint32 cur = *ptr++;
|
||||||
val += cur << i;
|
val += cur << i;
|
||||||
|
|
||||||
|
|
@ -301,3 +308,7 @@ private:
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
99
include/crlib/cr-uniqueptr.h
Normal file
99
include/crlib/cr-uniqueptr.h
Normal file
|
|
@ -0,0 +1,99 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <crlib/cr-basic.h>
|
||||||
|
#include <crlib/cr-movable.h>
|
||||||
|
|
||||||
|
CR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// simple unique ptr
|
||||||
|
template <typename T> class UniquePtr final : public DenyCopying {
|
||||||
|
private:
|
||||||
|
T *m_ptr = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
UniquePtr () = default;
|
||||||
|
explicit UniquePtr (T *ptr) : m_ptr (ptr)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
UniquePtr (UniquePtr &&rhs) noexcept : m_ptr (rhs.m_ptr) {
|
||||||
|
rhs.m_ptr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
~UniquePtr () {
|
||||||
|
destroy ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
T *get () const {
|
||||||
|
return m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
T *release () {
|
||||||
|
auto ret = m_ptr;
|
||||||
|
m_ptr = nullptr;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset (T *ptr = nullptr) {
|
||||||
|
destroy ();
|
||||||
|
m_ptr = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void destroy () {
|
||||||
|
if (m_ptr) {
|
||||||
|
alloc.destroy (m_ptr);
|
||||||
|
m_ptr = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
UniquePtr &operator = (UniquePtr &&rhs) noexcept {
|
||||||
|
if (this != &rhs) {
|
||||||
|
destroy ();
|
||||||
|
|
||||||
|
m_ptr = rhs.m_ptr;
|
||||||
|
rhs.m_ptr = nullptr;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
UniquePtr &operator = (decltype (nullptr)) {
|
||||||
|
destroy ();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
T &operator * () const {
|
||||||
|
return *m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
T *operator -> () const {
|
||||||
|
return m_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool () const {
|
||||||
|
return m_ptr != nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// create unique
|
||||||
|
template <typename T, typename... Args> UniquePtr <T> createUnique (Args &&... args) {
|
||||||
|
return UniquePtr <T> (alloc.create <T> (cr::forward <Args> (args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
// create unique (base class)
|
||||||
|
template <typename D, typename B, typename... Args> UniquePtr <B> createUniqueBase (Args &&... args) {
|
||||||
|
return UniquePtr <B> (alloc.create <D> (cr::forward <Args> (args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
232
include/crlib/cr-vector.h
Normal file
232
include/crlib/cr-vector.h
Normal file
|
|
@ -0,0 +1,232 @@
|
||||||
|
//
|
||||||
|
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
||||||
|
// Copyright (c) YaPB Development Team.
|
||||||
|
//
|
||||||
|
// This software is licensed under the BSD-style license.
|
||||||
|
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
||||||
|
// https://yapb.ru/license
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <crlib/cr-math.h>
|
||||||
|
|
||||||
|
CR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// 3dmath vector
|
||||||
|
class Vector final {
|
||||||
|
public:
|
||||||
|
float x = 0.0f, y = 0.0f, z = 0.0f;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Vector (const float scaler = 0.0f) : x (scaler), y (scaler), z (scaler)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
explicit Vector (const float _x, const float _y, const float _z) : x (_x), y (_y), z (_z)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Vector (float *rhs) : x (rhs[0]), y (rhs[1]), z (rhs[2])
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Vector (const Vector &) = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
operator float *() {
|
||||||
|
return &x;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator const float * () const {
|
||||||
|
return &x;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector operator + (const Vector &rhs) const {
|
||||||
|
return Vector (x + rhs.x, y + rhs.y, z + rhs.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector operator - (const Vector &rhs) const {
|
||||||
|
return Vector (x - rhs.x, y - rhs.y, z - rhs.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector operator - () const {
|
||||||
|
return Vector (-x, -y, -z);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend Vector operator * (const float scale, const Vector &rhs) {
|
||||||
|
return Vector (rhs.x * scale, rhs.y * scale, rhs.z * scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector operator * (const float scale) const {
|
||||||
|
return Vector (scale * x, scale * y, scale * z);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector operator / (const float div) const {
|
||||||
|
const float inv = 1 / div;
|
||||||
|
return Vector (inv * x, inv * y, inv * z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// cross product
|
||||||
|
Vector operator ^ (const Vector &rhs) const {
|
||||||
|
return Vector (y * rhs.z - z * rhs.y, z * rhs.x - x * rhs.z, x * rhs.y - y * rhs.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// dot product
|
||||||
|
float operator | (const Vector &rhs) const {
|
||||||
|
return x * rhs.x + y * rhs.y + z * rhs.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Vector &operator += (const Vector &rhs) {
|
||||||
|
x += rhs.x;
|
||||||
|
y += rhs.y;
|
||||||
|
z += rhs.z;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Vector &operator -= (const Vector &right) {
|
||||||
|
x -= right.x;
|
||||||
|
y -= right.y;
|
||||||
|
z -= right.z;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Vector &operator *= (float scale) {
|
||||||
|
x *= scale;
|
||||||
|
y *= scale;
|
||||||
|
z *= scale;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Vector &operator /= (float div) {
|
||||||
|
const float inv = 1 / div;
|
||||||
|
|
||||||
|
x *= inv;
|
||||||
|
y *= inv;
|
||||||
|
z *= inv;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator == (const Vector &rhs) const {
|
||||||
|
return cr::fequal (x, rhs.x) && cr::fequal (y, rhs.y) && cr::fequal (z, rhs.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator != (const Vector &rhs) const {
|
||||||
|
return !cr::fequal (x, rhs.x) && !cr::fequal (y, rhs.y) && !cr::fequal (z, rhs.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector &operator = (const Vector &) = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
float length () const {
|
||||||
|
return cr::sqrtf (lengthSq ());
|
||||||
|
}
|
||||||
|
|
||||||
|
float length2d () const {
|
||||||
|
return cr::sqrtf (x * x + y * y);
|
||||||
|
}
|
||||||
|
|
||||||
|
float lengthSq () const {
|
||||||
|
return x * x + y * y + z * z;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector get2d () const {
|
||||||
|
return Vector (x, y, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector normalize () const {
|
||||||
|
float len = length () + cr::kFloatCmpEpsilon;
|
||||||
|
|
||||||
|
if (cr::fzero (len)) {
|
||||||
|
return Vector (0.0f, 0.0f, 1.0f);
|
||||||
|
}
|
||||||
|
len = 1.0f / len;
|
||||||
|
return Vector (x * len, y * len, z * len);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector normalize2d () const {
|
||||||
|
float len = length2d () + cr::kFloatCmpEpsilon;
|
||||||
|
|
||||||
|
if (cr::fzero (len)) {
|
||||||
|
return Vector (0.0f, 1.0f, 0.0f);
|
||||||
|
}
|
||||||
|
len = 1.0f / len;
|
||||||
|
return Vector (x * len, y * len, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty () const {
|
||||||
|
return cr::fzero (x) && cr::fzero (y) && cr::fzero (z);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Vector &null () {
|
||||||
|
static const auto s_zero = Vector (0.0f, 0.0f, 0.0f);
|
||||||
|
return s_zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear () {
|
||||||
|
x = y = z = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector clampAngles () {
|
||||||
|
x = cr::normalizeAngles (x);
|
||||||
|
y = cr::normalizeAngles (y);
|
||||||
|
z = 0.0f;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
float pitch () const {
|
||||||
|
if (cr::fzero (x) && cr::fzero (y)) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
return cr::degreesToRadians (cr::atan2f (z, length2d ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
float yaw () const {
|
||||||
|
if (cr::fzero (x) && cr::fzero (y)) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
return cr::radiansToDegrees (cr:: atan2f (y, x));
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector angles () const {
|
||||||
|
if (cr::fzero (x) && cr::fzero (y)) {
|
||||||
|
return Vector (z > 0.0f ? 90.0f : 270.0f, 0.0, 0.0f);
|
||||||
|
}
|
||||||
|
return Vector (cr::radiansToDegrees (cr::atan2f (z, length2d ())), cr::radiansToDegrees (cr::atan2f (y, x)), 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildVectors (Vector *forward, Vector *right, Vector *upward) const {
|
||||||
|
enum { pitch, yaw, roll, unused, max };
|
||||||
|
|
||||||
|
float sines[max] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
|
float cosines[max] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
|
|
||||||
|
// compute the sine and cosine compontents
|
||||||
|
cr::sincosf (cr::degreesToRadians (x), cr::degreesToRadians (y), cr::degreesToRadians (z), sines, cosines);
|
||||||
|
|
||||||
|
if (forward) {
|
||||||
|
forward->x = cosines[pitch] * cosines[yaw];
|
||||||
|
forward->y = cosines[pitch] * sines[yaw];
|
||||||
|
forward->z = -sines[pitch];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (right) {
|
||||||
|
right->x = -sines[roll] * sines[pitch] * cosines[yaw] + cosines[roll] * sines[yaw];
|
||||||
|
right->y = -sines[roll] * sines[pitch] * sines[yaw] - cosines[roll] * cosines[yaw];
|
||||||
|
right->z = -sines[roll] * cosines[pitch];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (upward) {
|
||||||
|
upward->x = 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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// expose global null vector
|
||||||
|
static auto &nullvec = Vector::null ();
|
||||||
|
|
||||||
|
CR_NAMESPACE_END
|
||||||
364
include/engine.h
364
include/engine.h
|
|
@ -10,95 +10,91 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// line draw
|
// line draw
|
||||||
enum DrawLineType : int {
|
CR_DECLARE_SCOPED_ENUM (DrawLine,
|
||||||
DRAW_SIMPLE,
|
Simple,
|
||||||
DRAW_ARROW,
|
Arrow,
|
||||||
DRAW_NUM
|
Count
|
||||||
};
|
);
|
||||||
|
|
||||||
// trace ignore
|
// trace ignore
|
||||||
enum TraceIgnore : int {
|
CR_DECLARE_SCOPED_ENUM (TraceIgnore,
|
||||||
TRACE_IGNORE_NONE = 0,
|
None = 0,
|
||||||
TRACE_IGNORE_GLASS = cr::bit (0),
|
Glass = cr::bit (0),
|
||||||
TRACE_IGNORE_MONSTERS = cr::bit (1),
|
Monsters = cr::bit (1),
|
||||||
TRACE_IGNORE_EVERYTHING = TRACE_IGNORE_GLASS | TRACE_IGNORE_MONSTERS
|
Everything = Glass | Monsters
|
||||||
};
|
);
|
||||||
|
|
||||||
// variable type
|
// variable type
|
||||||
enum VarType : int {
|
CR_DECLARE_SCOPED_ENUM (Var,
|
||||||
VT_NORMAL = 0,
|
Normal = 0,
|
||||||
VT_READONLY,
|
ReadOnly,
|
||||||
VT_PASSWORD,
|
Password,
|
||||||
VT_NOSERVER,
|
NoServer,
|
||||||
VT_NOREGISTER
|
NoRegister
|
||||||
};
|
);
|
||||||
|
|
||||||
// netmessage functions
|
// netmessage functions
|
||||||
enum NetMsgId : int {
|
CR_DECLARE_SCOPED_ENUM (NetMsg,
|
||||||
NETMSG_UNDEFINED = -1,
|
None = -1,
|
||||||
NETMSG_VGUI = 1,
|
VGUI = 1,
|
||||||
NETMSG_SHOWMENU = 2,
|
ShowMenu = 2,
|
||||||
NETMSG_WEAPONLIST = 3,
|
WeaponList = 3,
|
||||||
NETMSG_CURWEAPON = 4,
|
CurWeapon = 4,
|
||||||
NETMSG_AMMOX = 5,
|
AmmoX = 5,
|
||||||
NETMSG_AMMOPICKUP = 6,
|
AmmoPickup = 6,
|
||||||
NETMSG_DAMAGE = 7,
|
Damage = 7,
|
||||||
NETMSG_MONEY = 8,
|
Money = 8,
|
||||||
NETMSG_STATUSICON = 9,
|
StatusIcon = 9,
|
||||||
NETMSG_DEATH = 10,
|
DeathMsg = 10,
|
||||||
NETMSG_SCREENFADE = 11,
|
ScreenFade = 11,
|
||||||
NETMSG_HLTV = 12,
|
HLTV = 12,
|
||||||
NETMSG_TEXTMSG = 13,
|
TextMsg = 13,
|
||||||
NETMSG_TEAMINFO = 14,
|
TeamInfo = 14,
|
||||||
NETMSG_BARTIME = 15,
|
BarTime = 15,
|
||||||
NETMSG_SENDAUDIO = 17,
|
SendAudio = 17,
|
||||||
NETMSG_SAYTEXT = 18,
|
SayText = 18,
|
||||||
NETMSG_BOTVOICE = 19,
|
BotVoice = 19,
|
||||||
NETMSG_NVGTOGGLE = 20,
|
NVGToggle = 20,
|
||||||
NETMSG_FLASHBAT = 21,
|
FlashBat = 21,
|
||||||
NETMSG_FLASHLIGHT = 22,
|
Fashlight = 22,
|
||||||
NETMSG_ITEMSTATUS = 23,
|
ItemStatus = 23,
|
||||||
NETMSG_NUM = 25
|
Count = 25
|
||||||
};
|
);
|
||||||
|
|
||||||
// supported cs's
|
// supported cs's
|
||||||
enum GameFlags : int {
|
CR_DECLARE_SCOPED_ENUM (GameFlags,
|
||||||
GAME_CSTRIKE16 = cr::bit (0), // counter-strike 1.6 and above
|
Modern = cr::bit (0), // counter-strike 1.6 and above
|
||||||
GAME_XASH_ENGINE = cr::bit (1), // counter-strike 1.6 under the xash engine (additional flag)
|
Xash3D = cr::bit (1), // counter-strike 1.6 under the xash engine (additional flag)
|
||||||
GAME_CZERO = cr::bit (2), // counter-strike: condition zero
|
ConditionZero = cr::bit (2), // counter-strike: condition zero
|
||||||
GAME_LEGACY = cr::bit (3), // counter-strike 1.3-1.5 with/without steam
|
Legacy = cr::bit (3), // counter-strike 1.3-1.5 with/without steam
|
||||||
GAME_MOBILITY = cr::bit (4), // additional flag that bot is running on android (additional flag)
|
Mobility = cr::bit (4), // additional flag that bot is running on android (additional flag)
|
||||||
GAME_OFFICIAL_CSBOT = cr::bit (5), // additional flag that indicates official cs bots are in game
|
CSBot = cr::bit (5), // additional flag that indicates official cs bots are in game
|
||||||
GAME_METAMOD = cr::bit (6), // game running under meta\mod
|
Metamod = cr::bit (6), // game running under meta\mod
|
||||||
GAME_CSDM = cr::bit (7), // csdm mod currently in use
|
CSDM = cr::bit (7), // csdm mod currently in use
|
||||||
GAME_CSDM_FFA = cr::bit (8), // csdm mod with ffa mode
|
FreeForAll = cr::bit (8), // csdm mod with ffa mode
|
||||||
GAME_REGAMEDLL = cr::bit (9), // server dll is a regamedll
|
ReGameDLL = cr::bit (9), // server dll is a regamedll
|
||||||
GAME_SUPPORT_SVC_PINGS = cr::bit (10), // on that game version we can fake bots pings
|
HasFakePings = cr::bit (10), // on that game version we can fake bots pings
|
||||||
GAME_SUPPORT_BOT_VOICE = cr::bit (11) // on that game version we can use chatter
|
HasBotVoice = cr::bit (11) // on that game version we can use chatter
|
||||||
};
|
);
|
||||||
|
|
||||||
|
|
||||||
// defines map type
|
// defines map type
|
||||||
enum MapFlags : int {
|
CR_DECLARE_SCOPED_ENUM (MapFlags,
|
||||||
MAP_AS = cr::bit (0),
|
Assassination = cr::bit (0),
|
||||||
MAP_CS = cr::bit (1),
|
HostageRescue = cr::bit (1),
|
||||||
MAP_DE = cr::bit (2),
|
Demolition = cr::bit (2),
|
||||||
MAP_ES = cr::bit (3),
|
Escape = cr::bit (3),
|
||||||
MAP_KA = cr::bit (4),
|
KnifeArena = cr::bit (4),
|
||||||
MAP_FY = cr::bit (5),
|
Fun = cr::bit (5),
|
||||||
|
HasDoors = cr::bit (10) // additional flags
|
||||||
// additional flags
|
);
|
||||||
MAP_HAS_DOORS = cr::bit (6)
|
|
||||||
};
|
|
||||||
|
|
||||||
// variable reg pair
|
// variable reg pair
|
||||||
struct VarPair {
|
struct VarPair {
|
||||||
VarType type;
|
Var type;
|
||||||
cvar_t reg;
|
cvar_t reg;
|
||||||
|
bool missing;
|
||||||
|
const char *regval;
|
||||||
class ConVar *self;
|
class ConVar *self;
|
||||||
|
|
||||||
bool regMissing;
|
|
||||||
const char *regVal;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// network message block
|
// network message block
|
||||||
|
|
@ -106,7 +102,7 @@ struct MessageBlock {
|
||||||
int bot;
|
int bot;
|
||||||
int state;
|
int state;
|
||||||
int msg;
|
int msg;
|
||||||
int regMsgs[NETMSG_NUM];
|
int regMsgs[NetMsg::Count];
|
||||||
};
|
};
|
||||||
|
|
||||||
// referentia vector info
|
// referentia vector info
|
||||||
|
|
@ -117,14 +113,14 @@ struct RefVector {
|
||||||
// entity prototype
|
// entity prototype
|
||||||
using EntityFunction = void (*) (entvars_t *);
|
using EntityFunction = void (*) (entvars_t *);
|
||||||
|
|
||||||
// compare language
|
// language hasher
|
||||||
struct LangComprarer {
|
struct HashLangString {
|
||||||
size_t operator () (const String &key) const {
|
uint32 operator () (const String &key) const {
|
||||||
char *str = const_cast <char *> (key.chars ());
|
auto str = reinterpret_cast <uint8 *> (const_cast <char *> (key.chars ()));
|
||||||
size_t hash = key.length ();
|
uint32 hash = 0;
|
||||||
|
|
||||||
while (*str++) {
|
while (*str++) {
|
||||||
if (!isalpha (*str)) {
|
if (!isalnum (*str)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
hash = ((*str << 5) + hash) + *str;
|
hash = ((*str << 5) + hash) + *str;
|
||||||
|
|
@ -136,8 +132,8 @@ struct LangComprarer {
|
||||||
// provides utility functions to not call original engine (less call-cost)
|
// provides utility functions to not call original engine (less call-cost)
|
||||||
class Game final : public Singleton <Game> {
|
class Game final : public Singleton <Game> {
|
||||||
private:
|
private:
|
||||||
int m_drawModels[DRAW_NUM];
|
int m_drawModels[DrawLine::Count];
|
||||||
int m_spawnCount[TEAM_UNASSIGNED];
|
int m_spawnCount[Team::Unassigned];
|
||||||
|
|
||||||
// bot client command
|
// bot client command
|
||||||
bool m_isBotCommand;
|
bool m_isBotCommand;
|
||||||
|
|
@ -147,9 +143,9 @@ private:
|
||||||
edict_t *m_localEntity;
|
edict_t *m_localEntity;
|
||||||
|
|
||||||
Array <VarPair> m_cvars;
|
Array <VarPair> m_cvars;
|
||||||
HashMap <String, String, LangComprarer> m_language;
|
Dictionary <String, String, HashLangString> m_language;
|
||||||
|
|
||||||
Library m_gameLib;
|
SharedLibrary m_gameLib;
|
||||||
MessageBlock m_msgBlock;
|
MessageBlock m_msgBlock;
|
||||||
bool m_precached;
|
bool m_precached;
|
||||||
|
|
||||||
|
|
@ -161,33 +157,18 @@ public:
|
||||||
RefVector vec;
|
RefVector vec;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Game (void);
|
Game ();
|
||||||
~Game (void);
|
~Game ();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// precaches internal stuff
|
// precaches internal stuff
|
||||||
void precache (void);
|
void precache ();
|
||||||
|
|
||||||
// initialize levels
|
// initialize levels
|
||||||
void levelInitialize (edict_t *ents, int max);
|
void levelInitialize (edict_t *ents, int max);
|
||||||
|
|
||||||
// prints data to servers console
|
|
||||||
void print (const char *fmt, ...);
|
|
||||||
|
|
||||||
// prints chat message to all players
|
|
||||||
void chatPrint (const char *fmt, ...);
|
|
||||||
|
|
||||||
// prints center message to all players
|
|
||||||
void centerPrint (const char *fmt, ...);
|
|
||||||
|
|
||||||
// prints center message to specified player
|
|
||||||
void centerPrint (edict_t *ent, const char *fmt, ...);
|
|
||||||
|
|
||||||
// prints message to client console
|
|
||||||
void clientPrint (edict_t *ent, const char *fmt, ...);
|
|
||||||
|
|
||||||
// display world line
|
// display world line
|
||||||
void drawLine (edict_t *ent, const Vector &start, const Vector &end, int width, int noise, int red, int green, int blue, int brightness, int speed, int life, DrawLineType type = DRAW_SIMPLE);
|
void drawLine (edict_t *ent, const Vector &start, const Vector &end, int width, int noise, const Color &color, int brightness, int speed, int life, DrawLine type = DrawLine::Simple);
|
||||||
|
|
||||||
// test line
|
// test line
|
||||||
void testLine (const Vector &start, const Vector &end, int ignoreFlags, edict_t *ignoreEntity, TraceResult *ptr);
|
void testLine (const Vector &start, const Vector &end, int ignoreFlags, edict_t *ignoreEntity, TraceResult *ptr);
|
||||||
|
|
@ -199,34 +180,31 @@ public:
|
||||||
float getWaveLen (const char *fileName);
|
float getWaveLen (const char *fileName);
|
||||||
|
|
||||||
// we are on dedicated server ?
|
// we are on dedicated server ?
|
||||||
bool isDedicated (void);
|
bool isDedicated ();
|
||||||
|
|
||||||
// get stripped down mod name
|
// get stripped down mod name
|
||||||
const char *getModName (void);
|
const char *getModName ();
|
||||||
|
|
||||||
// get the valid mapname
|
// get the valid mapname
|
||||||
const char *getMapName (void);
|
const char *getMapName ();
|
||||||
|
|
||||||
// get the "any" entity origin
|
// get the "any" entity origin
|
||||||
Vector getAbsPos (edict_t *ent);
|
Vector getAbsPos (edict_t *ent);
|
||||||
|
|
||||||
// send server command
|
|
||||||
void execCmd (const char *fmt, ...);
|
|
||||||
|
|
||||||
// registers a server command
|
// registers a server command
|
||||||
void registerCmd (const char *command, void func (void));
|
void registerCmd (const char *command, void func_ ());
|
||||||
|
|
||||||
// play's sound to client
|
// play's sound to client
|
||||||
void playSound (edict_t *ent, const char *sound);
|
void playSound (edict_t *ent, const char *sound);
|
||||||
|
|
||||||
// sends bot command
|
// sends bot command
|
||||||
void execBotCmd (edict_t *ent, const char *fmt, ...);
|
void prepareBotArgs (edict_t *ent, String str);
|
||||||
|
|
||||||
// adds cvar to registration stack
|
// adds cvar to registration stack
|
||||||
void pushVarToRegStack (const char *variable, const char *value, VarType varType, bool regMissing, const char *regVal, ConVar *self);
|
void addNewCvar (const char *variable, const char *value, Var varType, bool regMissing, const char *regVal, class ConVar *self);
|
||||||
|
|
||||||
// sends local registration stack for engine registration
|
// sends local registration stack for engine registration
|
||||||
void pushRegStackToEngine (bool gameVars = false);
|
void registerCvars (bool gameVars = false);
|
||||||
|
|
||||||
// translates bot message into needed language
|
// translates bot message into needed language
|
||||||
const char *translate (const char *input);
|
const char *translate (const char *input);
|
||||||
|
|
@ -235,19 +213,19 @@ public:
|
||||||
void processMessages (void *ptr);
|
void processMessages (void *ptr);
|
||||||
|
|
||||||
// checks whether softwared rendering is enabled
|
// checks whether softwared rendering is enabled
|
||||||
bool isSoftwareRenderer (void);
|
bool isSoftwareRenderer ();
|
||||||
|
|
||||||
// load the cs binary in non metamod mode
|
// load the cs binary in non metamod mode
|
||||||
bool loadCSBinary (void);
|
bool loadCSBinary ();
|
||||||
|
|
||||||
// do post-load stuff
|
// do post-load stuff
|
||||||
bool postload (void);
|
bool postload ();
|
||||||
|
|
||||||
// detects if csdm mod is in use
|
// detects if csdm mod is in use
|
||||||
void detectDeathmatch (void);
|
void detectDeathmatch ();
|
||||||
|
|
||||||
// executes stuff every 1 second
|
// executes stuff every 1 second
|
||||||
void slowFrame (void);
|
void slowFrame ();
|
||||||
|
|
||||||
// begin message handler
|
// begin message handler
|
||||||
void beginMessage (edict_t *ent, int dest, int type);
|
void beginMessage (edict_t *ent, int dest, int type);
|
||||||
|
|
@ -255,26 +233,23 @@ public:
|
||||||
// public inlines
|
// public inlines
|
||||||
public:
|
public:
|
||||||
// get the current time on server
|
// get the current time on server
|
||||||
float timebase (void) const {
|
float timebase () const {
|
||||||
return globals->time;
|
return globals->time;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get "maxplayers" limit on server
|
// get "maxplayers" limit on server
|
||||||
int maxClients (void) const {
|
int maxClients () const {
|
||||||
return globals->maxClients;
|
return globals->maxClients;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the fakeclient command interface
|
// get the fakeclient command interface
|
||||||
bool isBotCmd (void) const {
|
bool isBotCmd () const {
|
||||||
return m_isBotCommand;
|
return m_isBotCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets custom engine args for client command
|
// gets custom engine args for client command
|
||||||
const char *botArgs (void) const {
|
const char *botArgs () const {
|
||||||
static String args;
|
return strings.format (String::join (m_botArgs, " ", m_botArgs[0] == "say" || m_botArgs[0] == "say_team" ? 1 : 0).chars ());
|
||||||
args = String::join (m_botArgs, " ", m_botArgs[0] == "say" || m_botArgs[0] == "say_team" ? 1 : 0);
|
|
||||||
|
|
||||||
return args.chars ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets custom engine argv for client command
|
// gets custom engine argv for client command
|
||||||
|
|
@ -286,7 +261,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets custom engine argc for client command
|
// gets custom engine argc for client command
|
||||||
int botArgc (void) const {
|
int botArgc () const {
|
||||||
return m_botArgs.length ();
|
return m_botArgs.length ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -295,18 +270,28 @@ public:
|
||||||
return static_cast <edict_t *> (m_startEntity + index);
|
return static_cast <edict_t *> (m_startEntity + index);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// gets edict pointer out of entity index (player)
|
||||||
|
edict_t *playerOfIndex (const int index) {
|
||||||
|
return entityOfIndex (index) + 1;
|
||||||
|
};
|
||||||
|
|
||||||
// gets edict index out of it's pointer
|
// gets edict index out of it's pointer
|
||||||
int indexOfEntity (const edict_t *ent) {
|
int indexOfEntity (const edict_t *ent) {
|
||||||
return static_cast <int> (ent - m_startEntity);
|
return static_cast <int> (ent - m_startEntity);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// gets edict index of it's pointer (player)
|
||||||
|
int indexOfPlayer (const edict_t *ent) {
|
||||||
|
return indexOfEntity (ent) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
// verify entity isn't null
|
// verify entity isn't null
|
||||||
bool isNullEntity (const edict_t *ent) {
|
bool isNullEntity (const edict_t *ent) {
|
||||||
return !ent || !indexOfEntity (ent) || ent->free;
|
return !ent || !indexOfEntity (ent) || ent->free;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the wroldspawn entity
|
// get the wroldspawn entity
|
||||||
edict_t *getStartEntity (void) {
|
edict_t *getStartEntity () {
|
||||||
return m_startEntity;
|
return m_startEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -320,12 +305,17 @@ public:
|
||||||
|
|
||||||
// adds translation pair from config
|
// adds translation pair from config
|
||||||
void addTranslation (const String &original, const String &translated) {
|
void addTranslation (const String &original, const String &translated) {
|
||||||
m_language.put (original, translated);
|
m_language.push (original, translated);
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the translation table
|
||||||
|
void clearTranslation () {
|
||||||
|
m_language.clear ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// resets the message capture mechanism
|
// resets the message capture mechanism
|
||||||
void resetMessages (void) {
|
void resetMessages () {
|
||||||
m_msgBlock.msg = NETMSG_UNDEFINED;
|
m_msgBlock.msg = NetMsg::None;
|
||||||
m_msgBlock.state = 0;
|
m_msgBlock.state = 0;
|
||||||
m_msgBlock.bot = 0;
|
m_msgBlock.bot = 0;
|
||||||
};
|
};
|
||||||
|
|
@ -358,12 +348,12 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// sets the precache to uninitialize
|
// sets the precache to uninitialize
|
||||||
void setUnprecached (void) {
|
void setUnprecached () {
|
||||||
m_precached = false;
|
m_precached = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets the local entity (host edict)
|
// gets the local entity (host edict)
|
||||||
edict_t *getLocalEntity (void) {
|
edict_t *getLocalEntity () {
|
||||||
return m_localEntity;
|
return m_localEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -374,17 +364,12 @@ public:
|
||||||
|
|
||||||
// builds referential vector
|
// builds referential vector
|
||||||
void makeVectors (const Vector &in) {
|
void makeVectors (const Vector &in) {
|
||||||
in.makeVectors (&vec.forward, &vec.right, &vec.up);
|
in.buildVectors (&vec.forward, &vec.right, &vec.up);
|
||||||
}
|
|
||||||
|
|
||||||
// what kind of map we're running ?
|
|
||||||
bool isMap (const int map) const {
|
|
||||||
return (m_mapFlags & map) == map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// what kind of game engine / game dll / mod / tool we're running ?
|
// what kind of game engine / game dll / mod / tool we're running ?
|
||||||
bool is (const int type) const {
|
bool is (const int type) const {
|
||||||
return (m_gameFlags & type) == type;
|
return !!(m_gameFlags & type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// adds game flag
|
// adds game flag
|
||||||
|
|
@ -394,43 +379,79 @@ public:
|
||||||
|
|
||||||
// gets the map type
|
// gets the map type
|
||||||
bool mapIs (const int type) const {
|
bool mapIs (const int type) const {
|
||||||
return (m_mapFlags & type) == type;
|
return !!(m_mapFlags & type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get loaded gamelib
|
// get loaded gamelib
|
||||||
Library &getLib (void) {
|
const SharedLibrary &lib () {
|
||||||
return m_gameLib;
|
return m_gameLib;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// helper to sending the client message
|
||||||
|
void sendClientMessage (bool console, edict_t *ent, const char *message);
|
||||||
|
|
||||||
|
// send server command
|
||||||
|
template <typename ...Args> void serverCommand (const char *fmt, Args ...args) {
|
||||||
|
engfuncs.pfnServerCommand (strncat (strings.format (fmt, cr::forward <Args> (args)...), "\n", StringBuffer::StaticBufferSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// send a bot command
|
||||||
|
template <typename ...Args> void botCommand (edict_t *ent, const char *fmt, Args ...args) {
|
||||||
|
prepareBotArgs (ent, strings.format (fmt, cr::forward <Args> (args)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
// prints data to servers console
|
||||||
|
template <typename ...Args> void print (const char *fmt, Args ...args) {
|
||||||
|
engfuncs.pfnServerPrint (strncat (strings.format (translate (fmt), cr::forward <Args> (args)...), "\n", StringBuffer::StaticBufferSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// prints center message to specified player
|
||||||
|
template <typename ...Args> void clientPrint (edict_t *ent, const char *fmt, Args ...args) {
|
||||||
|
if (isNullEntity (ent)) {
|
||||||
|
print (fmt, cr::forward <Args> (args)...);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendClientMessage (true, ent, strncat (strings.format (translate (fmt), cr::forward <Args> (args)...), "\n", StringBuffer::StaticBufferSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// prints message to client console
|
||||||
|
template <typename ...Args> void centerPrint (edict_t *ent, const char *fmt, Args ...args) {
|
||||||
|
if (isNullEntity (ent)) {
|
||||||
|
print (fmt, cr::forward <Args> (args)...);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendClientMessage (false, ent, strncat (strings.format (translate (fmt), cr::forward <Args> (args)...), "\n", StringBuffer::StaticBufferSize));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// simplify access for console variables
|
// simplify access for console variables
|
||||||
class ConVar {
|
class ConVar {
|
||||||
public:
|
public:
|
||||||
cvar_t *m_eptr;
|
cvar_t *eptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ConVar (const char *name, const char *initval, VarType type = VT_NOSERVER, bool regMissing = false, const char *regVal = nullptr) : m_eptr (nullptr) {
|
ConVar (const char *name, const char *initval, Var type = Var::NoServer, bool regMissing = false, const char *regVal = nullptr) : eptr (nullptr) {
|
||||||
Game::ref ().pushVarToRegStack (name, initval, type, regMissing, regVal, this);
|
Game::get ().addNewCvar (name, initval, type, regMissing, regVal, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool boolean (void) const {
|
bool bool_ () const {
|
||||||
return m_eptr->value > 0.0f;
|
return eptr->value > 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
int integer (void) const {
|
int int_ () const {
|
||||||
return static_cast <int> (m_eptr->value);
|
return static_cast <int> (eptr->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
float flt (void) const {
|
float float_ () const {
|
||||||
return m_eptr->value;
|
return eptr->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *str (void) const {
|
const char *str () const {
|
||||||
return m_eptr->string;
|
return eptr->string;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set (float val) {
|
void set (float val) {
|
||||||
engfuncs.pfnCVarSetFloat (m_eptr->name, val);
|
engfuncs.pfnCVarSetFloat (eptr->name, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set (int val) {
|
void set (int val) {
|
||||||
|
|
@ -438,7 +459,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void set (const char *val) {
|
void set (const char *val) {
|
||||||
engfuncs.pfnCvar_DirectSet (m_eptr, const_cast <char *> (val));
|
engfuncs.pfnCvar_DirectSet (eptr, const_cast <char *> (val));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -447,26 +468,26 @@ private:
|
||||||
bool m_autoDestruct { false };
|
bool m_autoDestruct { false };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MessageWriter (void) = default;
|
MessageWriter () = default;
|
||||||
|
|
||||||
MessageWriter (int dest, int type, const Vector &pos = Vector::null (), edict_t *to = nullptr) {
|
MessageWriter (int dest, int type, const Vector &pos = nullvec, edict_t *to = nullptr) {
|
||||||
start (dest, type, pos, to);
|
start (dest, type, pos, to);
|
||||||
m_autoDestruct = true;
|
m_autoDestruct = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~MessageWriter (void) {
|
~MessageWriter () {
|
||||||
if (m_autoDestruct) {
|
if (m_autoDestruct) {
|
||||||
end ();
|
end ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MessageWriter &start (int dest, int type, const Vector &pos = Vector::null (), edict_t *to = nullptr) {
|
MessageWriter &start (int dest, int type, const Vector &pos = nullvec, edict_t *to = nullptr) {
|
||||||
engfuncs.pfnMessageBegin (dest, type, pos, to);
|
engfuncs.pfnMessageBegin (dest, type, pos, to);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void end (void) {
|
void end () {
|
||||||
engfuncs.pfnMessageEnd ();
|
engfuncs.pfnMessageEnd ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -475,6 +496,11 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MessageWriter &writeLong (int val) {
|
||||||
|
engfuncs.pfnWriteLong (val);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
MessageWriter &writeChar (int val) {
|
MessageWriter &writeChar (int val) {
|
||||||
engfuncs.pfnWriteChar (val);
|
engfuncs.pfnWriteChar (val);
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -497,11 +523,11 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static inline uint16 fu16 (float value, float scale) {
|
static inline uint16 fu16 (float value, float scale) {
|
||||||
return cr::clamp <uint16> (static_cast <uint16> (value * scale), 0, 0xffff);
|
return cr::clamp <uint16> (static_cast <uint16> (value * cr::bit (static_cast <short> (scale))), 0, 0xffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline short fs16 (float value, float scale) {
|
static inline short fs16 (float value, float scale) {
|
||||||
return cr::clamp <short> (static_cast <short> (value * scale), -32767, 32767);
|
return cr::clamp <short> (static_cast <short> (value * cr::bit (static_cast <short> (scale))), -32767, 32767);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -511,28 +537,28 @@ private:
|
||||||
int m_lightstyleValue[MAX_LIGHTSTYLEVALUE];
|
int m_lightstyleValue[MAX_LIGHTSTYLEVALUE];
|
||||||
bool m_doAnimation = false;
|
bool m_doAnimation = false;
|
||||||
|
|
||||||
SimpleColor m_point;
|
Color m_point;
|
||||||
model_t *m_worldModel = nullptr;
|
model_t *m_worldModel = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LightMeasure (void) {
|
LightMeasure () {
|
||||||
initializeLightstyles ();
|
initializeLightstyles ();
|
||||||
m_point.reset ();
|
m_point.reset ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void initializeLightstyles (void);
|
void initializeLightstyles ();
|
||||||
void animateLight (void);
|
void animateLight ();
|
||||||
void updateLight (int style, char *value);
|
void updateLight (int style, char *value);
|
||||||
|
|
||||||
float getLightLevel (const Vector &point);
|
float getLightLevel (const Vector &point);
|
||||||
float getSkyColor (void);
|
float getSkyColor ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename S, typename M> bool recursiveLightPoint (const M *node, const Vector &start, const Vector &end);
|
template <typename S, typename M> bool recursiveLightPoint (const M *node, const Vector &start, const Vector &end);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void resetWorldModel (void) {
|
void resetWorldModel () {
|
||||||
m_worldModel = nullptr;
|
m_worldModel = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,25 @@ typedef struct {
|
||||||
int iHitgroup; // 0 == generic, non zero is specific body part
|
int iHitgroup; // 0 == generic, non zero is specific body part
|
||||||
} TraceResult;
|
} TraceResult;
|
||||||
|
|
||||||
|
typedef struct usercmd_s {
|
||||||
|
short lerp_msec; // Interpolation time on client
|
||||||
|
byte msec; // Duration in ms of command
|
||||||
|
vec3_t viewangles; // Command view angles.
|
||||||
|
|
||||||
|
// intended velocities
|
||||||
|
float forwardmove; // Forward velocity.
|
||||||
|
float sidemove; // Sideways velocity.
|
||||||
|
float upmove; // Upward velocity.
|
||||||
|
byte lightlevel; // Light level at spot where we are standing.
|
||||||
|
unsigned short buttons; // Attack buttons
|
||||||
|
byte impulse; // Impulse command issued.
|
||||||
|
byte weaponselect; // Current weapon id
|
||||||
|
|
||||||
|
// Experimental player impact stuff.
|
||||||
|
int impact_index;
|
||||||
|
vec3_t impact_position;
|
||||||
|
} usercmd_t;
|
||||||
|
|
||||||
typedef uint32 CRC32_t;
|
typedef uint32 CRC32_t;
|
||||||
|
|
||||||
// Engine hands this to DLLs for functionality callbacks
|
// Engine hands this to DLLs for functionality callbacks
|
||||||
|
|
@ -111,7 +130,7 @@ typedef struct enginefuncs_s {
|
||||||
edict_t *(*pfnEntitiesInPVS) (edict_t *pplayer);
|
edict_t *(*pfnEntitiesInPVS) (edict_t *pplayer);
|
||||||
void (*pfnMakeVectors) (const float *rgflVector);
|
void (*pfnMakeVectors) (const float *rgflVector);
|
||||||
void (*pfnAngleVectors) (const float *rgflVector, float *forward, float *right, float *up);
|
void (*pfnAngleVectors) (const float *rgflVector, float *forward, float *right, float *up);
|
||||||
edict_t *(*pfnCreateEntity) (void);
|
edict_t *(*pfnCreateEntity) ();
|
||||||
void (*pfnRemoveEntity) (edict_t *e);
|
void (*pfnRemoveEntity) (edict_t *e);
|
||||||
edict_t *(*pfnCreateNamedEntity) (int className);
|
edict_t *(*pfnCreateNamedEntity) (int className);
|
||||||
void (*pfnMakeStatic) (edict_t *ent);
|
void (*pfnMakeStatic) (edict_t *ent);
|
||||||
|
|
@ -130,14 +149,14 @@ typedef struct enginefuncs_s {
|
||||||
void (*pfnTraceSphere) (const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr);
|
void (*pfnTraceSphere) (const float *v1, const float *v2, int fNoMonsters, float radius, edict_t *pentToSkip, TraceResult *ptr);
|
||||||
void (*pfnGetAimVector) (edict_t *ent, float speed, float *rgflReturn);
|
void (*pfnGetAimVector) (edict_t *ent, float speed, float *rgflReturn);
|
||||||
void (*pfnServerCommand) (char *str);
|
void (*pfnServerCommand) (char *str);
|
||||||
void (*pfnServerExecute) (void);
|
void (*pfnServerExecute) ();
|
||||||
void (*pfnClientCommand) (edict_t *ent, char const *szFmt, ...);
|
void (*pfnClientCommand) (edict_t *ent, char const *szFmt, ...);
|
||||||
void (*pfnParticleEffect) (const float *org, const float *dir, float color, float count);
|
void (*pfnParticleEffect) (const float *org, const float *dir, float color, float count);
|
||||||
void (*pfnLightStyle) (int style, char *val);
|
void (*pfnLightStyle) (int style, char *val);
|
||||||
int (*pfnDecalIndex) (const char *name);
|
int (*pfnDecalIndex) (const char *name);
|
||||||
int (*pfnPointContents) (const float *rgflVector);
|
int (*pfnPointContents) (const float *rgflVector);
|
||||||
void (*pfnMessageBegin) (int msg_dest, int msg_type, const float *pOrigin, edict_t *ed);
|
void (*pfnMessageBegin) (int msg_dest, int msg_type, const float *pOrigin, edict_t *ed);
|
||||||
void (*pfnMessageEnd) (void);
|
void (*pfnMessageEnd) ();
|
||||||
void (*pfnWriteByte) (int value);
|
void (*pfnWriteByte) (int value);
|
||||||
void (*pfnWriteChar) (int value);
|
void (*pfnWriteChar) (int value);
|
||||||
void (*pfnWriteShort) (int value);
|
void (*pfnWriteShort) (int value);
|
||||||
|
|
@ -151,7 +170,7 @@ typedef struct enginefuncs_s {
|
||||||
const char *(*pfnCVarGetString) (const char *szVarName);
|
const char *(*pfnCVarGetString) (const char *szVarName);
|
||||||
void (*pfnCVarSetFloat) (const char *szVarName, float flValue);
|
void (*pfnCVarSetFloat) (const char *szVarName, float flValue);
|
||||||
void (*pfnCVarSetString) (const char *szVarName, const char *szValue);
|
void (*pfnCVarSetString) (const char *szVarName, const char *szValue);
|
||||||
void (*pfnAlertMessage) (ALERT_TYPE atype, char *szFmt, ...);
|
void (*pfnAlertMessage) (ALERT_TYPE atype, const char *szFmt, ...);
|
||||||
void (*pfnEngineFprintf) (void *pfile, char *szFmt, ...);
|
void (*pfnEngineFprintf) (void *pfile, char *szFmt, ...);
|
||||||
void *(*pfnPvAllocEntPrivateData) (edict_t *ent, int32 cb);
|
void *(*pfnPvAllocEntPrivateData) (edict_t *ent, int32 cb);
|
||||||
void *(*pfnPvEntPrivateData) (edict_t *ent);
|
void *(*pfnPvEntPrivateData) (edict_t *ent);
|
||||||
|
|
@ -172,9 +191,9 @@ typedef struct enginefuncs_s {
|
||||||
const char *(*pfnNameForFunction) (uint32 function);
|
const char *(*pfnNameForFunction) (uint32 function);
|
||||||
void (*pfnClientPrintf) (edict_t *ent, PRINT_TYPE ptype, const char *szMsg); // JOHN: engine callbacks so game DLL can print messages to individual clients
|
void (*pfnClientPrintf) (edict_t *ent, PRINT_TYPE ptype, const char *szMsg); // JOHN: engine callbacks so game DLL can print messages to individual clients
|
||||||
void (*pfnServerPrint) (const char *szMsg);
|
void (*pfnServerPrint) (const char *szMsg);
|
||||||
const char *(*pfnCmd_Args) (void); // these 3 added
|
const char *(*pfnCmd_Args) (); // these 3 added
|
||||||
const char *(*pfnCmd_Argv) (int argc); // so game DLL can easily
|
const char *(*pfnCmd_Argv) (int argc); // so game DLL can easily
|
||||||
int (*pfnCmd_Argc) (void); // access client 'cmd' strings
|
int (*pfnCmd_Argc) (); // access client 'cmd' strings
|
||||||
void (*pfnGetAttachment) (const edict_t *ent, int iAttachment, float *rgflOrigin, float *rgflAngles);
|
void (*pfnGetAttachment) (const edict_t *ent, int iAttachment, float *rgflOrigin, float *rgflAngles);
|
||||||
void (*pfnCRC32_Init) (CRC32_t *pulCRC);
|
void (*pfnCRC32_Init) (CRC32_t *pulCRC);
|
||||||
void (*pfnCRC32_ProcessBuffer) (CRC32_t *pulCRC, void *p, int len);
|
void (*pfnCRC32_ProcessBuffer) (CRC32_t *pulCRC, void *p, int len);
|
||||||
|
|
@ -183,7 +202,7 @@ typedef struct enginefuncs_s {
|
||||||
int32 (*pfnRandomLong) (int32 lLow, int32 lHigh);
|
int32 (*pfnRandomLong) (int32 lLow, int32 lHigh);
|
||||||
float (*pfnRandomFloat) (float flLow, float flHigh);
|
float (*pfnRandomFloat) (float flLow, float flHigh);
|
||||||
void (*pfnSetView) (const edict_t *client, const edict_t *pViewent);
|
void (*pfnSetView) (const edict_t *client, const edict_t *pViewent);
|
||||||
float (*pfnTime) (void);
|
float (*pfnTime) ();
|
||||||
void (*pfnCrosshairAngle) (const edict_t *client, float pitch, float yaw);
|
void (*pfnCrosshairAngle) (const edict_t *client, float pitch, float yaw);
|
||||||
uint8 *(*pfnLoadFileForMe) (char const *szFilename, int *pLength);
|
uint8 *(*pfnLoadFileForMe) (char const *szFilename, int *pLength);
|
||||||
void (*pfnFreeFile) (void *buffer);
|
void (*pfnFreeFile) (void *buffer);
|
||||||
|
|
@ -195,7 +214,7 @@ typedef struct enginefuncs_s {
|
||||||
void (*pfnSetClientMaxspeed) (const edict_t *ent, float fNewMaxspeed);
|
void (*pfnSetClientMaxspeed) (const edict_t *ent, float fNewMaxspeed);
|
||||||
edict_t *(*pfnCreateFakeClient) (const char *netname); // returns nullptr if fake client can't be created
|
edict_t *(*pfnCreateFakeClient) (const char *netname); // returns nullptr if fake client can't be created
|
||||||
void (*pfnRunPlayerMove) (edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, uint16 buttons, uint8 impulse, uint8 msec);
|
void (*pfnRunPlayerMove) (edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, uint16 buttons, uint8 impulse, uint8 msec);
|
||||||
int (*pfnNumberOfEntities) (void);
|
int (*pfnNumberOfEntities) ();
|
||||||
char *(*pfnGetInfoKeyBuffer) (edict_t *e); // passing in nullptr gets the serverinfo
|
char *(*pfnGetInfoKeyBuffer) (edict_t *e); // passing in nullptr gets the serverinfo
|
||||||
char *(*pfnInfoKeyValue) (char *infobuffer, char const *key);
|
char *(*pfnInfoKeyValue) (char *infobuffer, char const *key);
|
||||||
void (*pfnSetKeyValue) (char *infobuffer, char *key, char *value);
|
void (*pfnSetKeyValue) (char *infobuffer, char *key, char *value);
|
||||||
|
|
@ -205,7 +224,7 @@ typedef struct enginefuncs_s {
|
||||||
int (*pfnPrecacheGeneric) (char *s);
|
int (*pfnPrecacheGeneric) (char *s);
|
||||||
int (*pfnGetPlayerUserId) (edict_t *e); // returns the server assigned userid for this player. useful for logging frags, etc. returns -1 if the edict couldn't be found in the list of clients
|
int (*pfnGetPlayerUserId) (edict_t *e); // returns the server assigned userid for this player. useful for logging frags, etc. returns -1 if the edict couldn't be found in the list of clients
|
||||||
void (*pfnBuildSoundMsg) (edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed);
|
void (*pfnBuildSoundMsg) (edict_t *entity, int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch, int msg_dest, int msg_type, const float *pOrigin, edict_t *ed);
|
||||||
int (*pfnIsDedicatedServer) (void); // is this a dedicated server?
|
int (*pfnIsDedicatedServer) (); // is this a dedicated server?
|
||||||
cvar_t *(*pfnCVarGetPointer) (const char *szVarName);
|
cvar_t *(*pfnCVarGetPointer) (const char *szVarName);
|
||||||
unsigned int (*pfnGetPlayerWONId) (edict_t *e); // returns the server assigned WONid for this player. useful for logging frags, etc. returns -1 if the edict couldn't be found in the list of clients
|
unsigned int (*pfnGetPlayerWONId) (edict_t *e); // returns the server assigned WONid for this player. useful for logging frags, etc. returns -1 if the edict couldn't be found in the list of clients
|
||||||
|
|
||||||
|
|
@ -221,7 +240,7 @@ typedef struct enginefuncs_s {
|
||||||
void (*pfnDeltaSetField) (struct delta_s *pFields, const char *fieldname);
|
void (*pfnDeltaSetField) (struct delta_s *pFields, const char *fieldname);
|
||||||
void (*pfnDeltaUnsetField) (struct delta_s *pFields, const char *fieldname);
|
void (*pfnDeltaUnsetField) (struct delta_s *pFields, const char *fieldname);
|
||||||
void (*pfnDeltaAddEncoder) (char *name, void (*conditionalencode) (struct delta_s *pFields, const uint8 *from, const uint8 *to));
|
void (*pfnDeltaAddEncoder) (char *name, void (*conditionalencode) (struct delta_s *pFields, const uint8 *from, const uint8 *to));
|
||||||
int (*pfnGetCurrentPlayer) (void);
|
int (*pfnGetCurrentPlayer) ();
|
||||||
int (*pfnCanSkipPlayer) (const edict_t *player);
|
int (*pfnCanSkipPlayer) (const edict_t *player);
|
||||||
int (*pfnDeltaFindField) (struct delta_s *pFields, const char *fieldname);
|
int (*pfnDeltaFindField) (struct delta_s *pFields, const char *fieldname);
|
||||||
void (*pfnDeltaSetFieldByIndex) (struct delta_s *pFields, int fieldNumber);
|
void (*pfnDeltaSetFieldByIndex) (struct delta_s *pFields, int fieldNumber);
|
||||||
|
|
@ -231,7 +250,7 @@ typedef struct enginefuncs_s {
|
||||||
void (*pfnCvar_DirectSet) (struct cvar_t *var, char *value);
|
void (*pfnCvar_DirectSet) (struct cvar_t *var, char *value);
|
||||||
void (*pfnForceUnmodified) (FORCE_TYPE type, float *mins, float *maxs, const char *szFilename);
|
void (*pfnForceUnmodified) (FORCE_TYPE type, float *mins, float *maxs, const char *szFilename);
|
||||||
void (*pfnGetPlayerStats) (const edict_t *client, int *ping, int *packet_loss);
|
void (*pfnGetPlayerStats) (const edict_t *client, int *ping, int *packet_loss);
|
||||||
void (*pfnAddServerCommand) (char *cmd_name, void (*function) (void));
|
void (*pfnAddServerCommand) (char *cmd_name, void (*function) ());
|
||||||
|
|
||||||
int (*pfnVoice_GetClientListening) (int iReceiver, int iSender);
|
int (*pfnVoice_GetClientListening) (int iReceiver, int iSender);
|
||||||
int (*pfnVoice_SetClientListening) (int iReceiver, int iSender, int bListen);
|
int (*pfnVoice_SetClientListening) (int iReceiver, int iSender, int bListen);
|
||||||
|
|
@ -244,18 +263,20 @@ typedef struct enginefuncs_s {
|
||||||
int (*pfnGetFileSize) (char *szFilename);
|
int (*pfnGetFileSize) (char *szFilename);
|
||||||
unsigned int (*pfnGetApproxWavePlayLen) (const char *filepath);
|
unsigned int (*pfnGetApproxWavePlayLen) (const char *filepath);
|
||||||
|
|
||||||
int (*pfnIsCareerMatch) (void);
|
int (*pfnIsCareerMatch) ();
|
||||||
int (*pfnGetLocalizedStringLength) (const char *label);
|
int (*pfnGetLocalizedStringLength) (const char *label);
|
||||||
void (*pfnRegisterTutorMessageShown) (int mid);
|
void (*pfnRegisterTutorMessageShown) (int mid);
|
||||||
int (*pfnGetTimesTutorMessageShown) (int mid);
|
int (*pfnGetTimesTutorMessageShown) (int mid);
|
||||||
void (*pfnProcessTutorMessageDecayBuffer) (int *buffer, int bufferLength);
|
void (*pfnProcessTutorMessageDecayBuffer) (int *buffer, int bufferLength);
|
||||||
void (*pfnConstructTutorMessageDecayBuffer) (int *buffer, int bufferLength);
|
void (*pfnConstructTutorMessageDecayBuffer) (int *buffer, int bufferLength);
|
||||||
void (*pfnResetTutorMessageDecayData) (void);
|
void (*pfnResetTutorMessageDecayData) ();
|
||||||
|
|
||||||
void (*pfnQueryClientCVarValue) (const edict_t *player, const char *cvarName);
|
void (*pfnQueryClientCVarValue) (const edict_t *player, const char *cvarName);
|
||||||
void (*pfnQueryClientCVarValue2) (const edict_t *player, const char *cvarName, int requestID);
|
void (*pfnQueryClientCVarValue2) (const edict_t *player, const char *cvarName, int requestID);
|
||||||
int (*pfnCheckParm) (const char *pchCmdLineToken, char **ppnext);
|
int (*pfnCheckParm) (const char *pchCmdLineToken, char **ppnext);
|
||||||
|
#ifdef EIFACE_2019
|
||||||
|
edict_t *(*pfnPEntityOfEntIndexAllEntities) (int iEntIndex);
|
||||||
|
#endif
|
||||||
} enginefuncs_t;
|
} enginefuncs_t;
|
||||||
|
|
||||||
// Passed to pfnKeyValue
|
// Passed to pfnKeyValue
|
||||||
|
|
@ -270,7 +291,7 @@ typedef struct customization_s customization_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// Initialize/shutdown the game (one-time call after loading of game .dll )
|
// Initialize/shutdown the game (one-time call after loading of game .dll )
|
||||||
void (*pfnGameInit) (void);
|
void (*pfnGameInit) ();
|
||||||
int (*pfnSpawn) (edict_t *pent);
|
int (*pfnSpawn) (edict_t *pent);
|
||||||
void (*pfnThink) (edict_t *pent);
|
void (*pfnThink) (edict_t *pent);
|
||||||
void (*pfnUse) (edict_t *pentUsed, edict_t *pentOther);
|
void (*pfnUse) (edict_t *pentUsed, edict_t *pentOther);
|
||||||
|
|
@ -286,7 +307,7 @@ typedef struct {
|
||||||
|
|
||||||
void (*pfnSaveGlobalState) (SAVERESTOREDATA *);
|
void (*pfnSaveGlobalState) (SAVERESTOREDATA *);
|
||||||
void (*pfnRestoreGlobalState) (SAVERESTOREDATA *);
|
void (*pfnRestoreGlobalState) (SAVERESTOREDATA *);
|
||||||
void (*pfnResetGlobalState) (void);
|
void (*pfnResetGlobalState) ();
|
||||||
|
|
||||||
int (*pfnClientConnect) (edict_t *ent, const char *pszName, const char *pszAddress, char szRejectReason[128]);
|
int (*pfnClientConnect) (edict_t *ent, const char *pszName, const char *pszAddress, char szRejectReason[128]);
|
||||||
|
|
||||||
|
|
@ -297,17 +318,17 @@ typedef struct {
|
||||||
void (*pfnClientUserInfoChanged) (edict_t *ent, char *infobuffer);
|
void (*pfnClientUserInfoChanged) (edict_t *ent, char *infobuffer);
|
||||||
|
|
||||||
void (*pfnServerActivate) (edict_t *edictList, int edictCount, int clientMax);
|
void (*pfnServerActivate) (edict_t *edictList, int edictCount, int clientMax);
|
||||||
void (*pfnServerDeactivate) (void);
|
void (*pfnServerDeactivate) ();
|
||||||
|
|
||||||
void (*pfnPlayerPreThink) (edict_t *ent);
|
void (*pfnPlayerPreThink) (edict_t *ent);
|
||||||
void (*pfnPlayerPostThink) (edict_t *ent);
|
void (*pfnPlayerPostThink) (edict_t *ent);
|
||||||
|
|
||||||
void (*pfnStartFrame) (void);
|
void (*pfnStartFrame) ();
|
||||||
void (*pfnParmsNewLevel) (void);
|
void (*pfnParmsNewLevel) ();
|
||||||
void (*pfnParmsChangeLevel) (void);
|
void (*pfnParmsChangeLevel) ();
|
||||||
|
|
||||||
// Returns string describing current .dll. E.g., TeamFotrress 2, Half-Life
|
// Returns string describing current .dll. E.g., TeamFotrress 2, Half-Life
|
||||||
const char *(*pfnGetGameDescription) (void);
|
const char *(*pfnGetGameDescription) ();
|
||||||
|
|
||||||
// Notify dll about a player customization.
|
// Notify dll about a player customization.
|
||||||
void (*pfnPlayerCustomization) (edict_t *ent, struct customization_s *pCustom);
|
void (*pfnPlayerCustomization) (edict_t *ent, struct customization_s *pCustom);
|
||||||
|
|
@ -327,10 +348,10 @@ typedef struct {
|
||||||
void (*pfnUpdateClientData) (const struct edict_s *ent, int sendweapons, struct clientdata_s *cd);
|
void (*pfnUpdateClientData) (const struct edict_s *ent, int sendweapons, struct clientdata_s *cd);
|
||||||
int (*pfnAddToFullPack) (struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, uint8 *pSet);
|
int (*pfnAddToFullPack) (struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, uint8 *pSet);
|
||||||
void (*pfnCreateBaseline) (int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, float *player_mins, float *player_maxs);
|
void (*pfnCreateBaseline) (int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, float *player_mins, float *player_maxs);
|
||||||
void (*pfnRegisterEncoders) (void);
|
void (*pfnRegisterEncoders) ();
|
||||||
int (*pfnGetWeaponData) (struct edict_s *player, struct weapon_data_s *info);
|
int (*pfnGetWeaponData) (struct edict_s *player, struct weapon_data_s *info);
|
||||||
|
|
||||||
void (*pfnCmdStart) (const edict_t *player, const struct c *cmd, unsigned int random_seed);
|
void (*pfnCmdStart) (const edict_t *player, usercmd_t *cmd, unsigned int random_seed);
|
||||||
void (*pfnCmdEnd) (const edict_t *player);
|
void (*pfnCmdEnd) (const edict_t *player);
|
||||||
|
|
||||||
// Return 1 if the packet is valid. Set response_buffer_size if you want to send a response packet. Incoming, it holds the max
|
// Return 1 if the packet is valid. Set response_buffer_size if you want to send a response packet. Incoming, it holds the max
|
||||||
|
|
@ -341,7 +362,7 @@ typedef struct {
|
||||||
int (*pfnGetHullBounds) (int hullnumber, float *mins, float *maxs);
|
int (*pfnGetHullBounds) (int hullnumber, float *mins, float *maxs);
|
||||||
|
|
||||||
// Create baselines for certain "unplaced" items.
|
// Create baselines for certain "unplaced" items.
|
||||||
void (*pfnCreateInstancedBaselines) (void);
|
void (*pfnCreateInstancedBaselines) ();
|
||||||
|
|
||||||
// One of the pfnForceUnmodified files failed the consistency check for the specified player
|
// One of the pfnForceUnmodified files failed the consistency check for the specified player
|
||||||
// Return 0 to allow the client to continue, 1 to force immediate disconnection ( with an optional disconnect message of up to 256 characters )
|
// Return 0 to allow the client to continue, 1 to force immediate disconnection ( with an optional disconnect message of up to 256 characters )
|
||||||
|
|
@ -351,7 +372,7 @@ typedef struct {
|
||||||
// the sv_unlag cvar.
|
// the sv_unlag cvar.
|
||||||
// Most games right now should return 0, until client-side weapon prediction code is written
|
// Most games right now should return 0, until client-side weapon prediction code is written
|
||||||
// and tested for them.
|
// and tested for them.
|
||||||
int (*pfnAllowLagCompensation) (void);
|
int (*pfnAllowLagCompensation) ();
|
||||||
} gamefuncs_t;
|
} gamefuncs_t;
|
||||||
|
|
||||||
// Current version.
|
// Current version.
|
||||||
|
|
@ -361,7 +382,7 @@ typedef struct {
|
||||||
// Called right before the object's memory is freed.
|
// Called right before the object's memory is freed.
|
||||||
// Calls its destructor.
|
// Calls its destructor.
|
||||||
void (*pfnOnFreeEntPrivateData) (edict_t *pEnt);
|
void (*pfnOnFreeEntPrivateData) (edict_t *pEnt);
|
||||||
void (*pfnGameShutdown) (void);
|
void (*pfnGameShutdown) ();
|
||||||
int (*pfnShouldCollide) (edict_t *pentTouched, edict_t *pentOther);
|
int (*pfnShouldCollide) (edict_t *pentTouched, edict_t *pentOther);
|
||||||
|
|
||||||
void (*pfnCvarValue) (const edict_t *pEnt, const char *value);
|
void (*pfnCvarValue) (const edict_t *pEnt, const char *value);
|
||||||
|
|
|
||||||
|
|
@ -54,9 +54,9 @@ typedef int func_t; //
|
||||||
typedef int string_t; // from engine's pr_comp.h;
|
typedef int string_t; // from engine's pr_comp.h;
|
||||||
typedef float vec_t; // needed before including progdefs.h
|
typedef float vec_t; // needed before including progdefs.h
|
||||||
|
|
||||||
#include "corelib.h"
|
#include <crlib/cr-vector.h>
|
||||||
|
|
||||||
typedef cr::classes::Vector vec3_t;
|
typedef cr::Vector vec3_t;
|
||||||
using namespace cr::types;
|
using namespace cr::types;
|
||||||
|
|
||||||
#include "const.h"
|
#include "const.h"
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ extern gamefuncs_t dllapi;
|
||||||
#define STRING(offset) (const char *)(globals->pStringBase + (int)offset)
|
#define STRING(offset) (const char *)(globals->pStringBase + (int)offset)
|
||||||
|
|
||||||
// form fwgs-hlsdk
|
// form fwgs-hlsdk
|
||||||
|
#if defined (CR_ARCH_X64)
|
||||||
static inline int MAKE_STRING (const char *val) {
|
static inline int MAKE_STRING (const char *val) {
|
||||||
long long ptrdiff = val - STRING (0);
|
long long ptrdiff = val - STRING (0);
|
||||||
|
|
||||||
|
|
@ -32,6 +33,9 @@ static inline int MAKE_STRING (const char *val) {
|
||||||
}
|
}
|
||||||
return static_cast <int> (ptrdiff);
|
return static_cast <int> (ptrdiff);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
#define MAKE_STRING(str) ((uint64)(str) - (uint64)(STRING(0)))
|
||||||
|
#endif
|
||||||
|
|
||||||
#define ENGINE_STR(str) (const_cast <char *> (STRING (engfuncs.pfnAllocString (str))))
|
#define ENGINE_STR(str) (const_cast <char *> (STRING (engfuncs.pfnAllocString (str))))
|
||||||
|
|
||||||
|
|
@ -93,17 +97,17 @@ typedef struct hudtextparms_s {
|
||||||
#define PUSH_BLOCK_ONLY_X 1
|
#define PUSH_BLOCK_ONLY_X 1
|
||||||
#define PUSH_BLOCK_ONLY_Y 2
|
#define PUSH_BLOCK_ONLY_Y 2
|
||||||
|
|
||||||
#define VEC_HULL_MIN Vector (-16, -16, -36)
|
#define VEC_HULL_MIN Vector(-16, -16, -36)
|
||||||
#define VEC_HULL_MAX Vector (16, 16, 36)
|
#define VEC_HULL_MAX Vector(16, 16, 36)
|
||||||
#define VEC_HUMAN_HULL_MIN Vector (-16, -16, 0)
|
#define VEC_HUMAN_HULL_MIN Vector(-16, -16, 0)
|
||||||
#define VEC_HUMAN_HULL_MAX Vector (16, 16, 72)
|
#define VEC_HUMAN_HULL_MAX Vector(16, 16, 72)
|
||||||
#define VEC_HUMAN_HULL_DUCK Vector (16, 16, 36)
|
#define VEC_HUMAN_HULL_DUCK Vector(16, 16, 36)
|
||||||
|
|
||||||
#define VEC_VIEW Vector (0, 0, 28)
|
#define VEC_VIEW Vector(0, 0, 28)
|
||||||
|
|
||||||
#define VEC_DUCK_HULL_MIN Vector (-16, -16, -18)
|
#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18)
|
||||||
#define VEC_DUCK_HULL_MAX Vector (16, 16, 18)
|
#define VEC_DUCK_HULL_MAX Vector(16, 16, 18)
|
||||||
#define VEC_DUCK_VIEW Vector (0, 0, 12)
|
#define VEC_DUCK_VIEW Vector(0, 0, 12)
|
||||||
|
|
||||||
#define SVC_TEMPENTITY 23
|
#define SVC_TEMPENTITY 23
|
||||||
#define SVC_CENTERPRINT 26
|
#define SVC_CENTERPRINT 26
|
||||||
|
|
|
||||||
|
|
@ -1,97 +0,0 @@
|
||||||
//
|
|
||||||
// Yet Another POD-Bot, based on PODBot by Markus Klinge ("CountFloyd").
|
|
||||||
// Copyright (c) YaPB Development Team.
|
|
||||||
//
|
|
||||||
// This software is licensed under the BSD-style license.
|
|
||||||
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
|
|
||||||
// https://yapb.ru/license
|
|
||||||
//
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
// detects the build platform
|
|
||||||
#if defined(__linux__)
|
|
||||||
#define PLATFORM_LINUX
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
#define PLATFORM_OSX
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
#define PLATFORM_WIN32
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// by default sse has everyone
|
|
||||||
#define PLATFORM_HAS_SSE2
|
|
||||||
|
|
||||||
// detects the compiler
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#define CXX_MSVC
|
|
||||||
#elif defined(__clang__)
|
|
||||||
#define CXX_CLANG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// configure export macros
|
|
||||||
#if defined(PLATFORM_WIN32)
|
|
||||||
#define SHARED_LIBRARAY_EXPORT extern "C" __declspec (dllexport)
|
|
||||||
#elif defined(PLATFORM_LINUX) || defined(PLATFORM_OSX)
|
|
||||||
#define SHARED_LIBRARAY_EXPORT extern "C" __attribute__ ((visibility ("default")))
|
|
||||||
#else
|
|
||||||
#error "Can't configure export macros. Compiler unrecognized."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// operating system specific macros, functions and typedefs
|
|
||||||
#ifdef PLATFORM_WIN32
|
|
||||||
|
|
||||||
#include <direct.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#define STD_CALL __stdcall
|
|
||||||
|
|
||||||
#define DLL_ENTRYPOINT int STD_CALL DllMain (HINSTANCE, DWORD dwReason, LPVOID)
|
|
||||||
#define DLL_DETACHING (dwReason == DLL_PROCESS_DETACH)
|
|
||||||
#define DLL_RETENTRY return TRUE
|
|
||||||
|
|
||||||
#if defined(CXX_MSVC) && !defined (_M_X64)
|
|
||||||
#define DLL_GIVEFNPTRSTODLL extern "C" void STD_CALL
|
|
||||||
#elif defined(CXX_CLANG) || defined (_M_X64)
|
|
||||||
#define DLL_GIVEFNPTRSTODLL SHARED_LIBRARAY_EXPORT void STD_CALL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// specify export parameter
|
|
||||||
#if defined(CXX_MSVC) || defined (CXX_CLANG)
|
|
||||||
#if !defined (_M_X64)
|
|
||||||
#pragma comment(linker, "/EXPORT:GiveFnptrsToDll=_GiveFnptrsToDll@8,@1")
|
|
||||||
#endif
|
|
||||||
#pragma comment(linker, "/SECTION:.data,RW")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#elif defined(PLATFORM_LINUX) || defined(PLATFORM_OSX)
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#define DLL_ENTRYPOINT __attribute__ ((destructor)) void _fini (void)
|
|
||||||
#define DLL_DETACHING TRUE
|
|
||||||
#define DLL_RETENTRY return
|
|
||||||
#define DLL_GIVEFNPTRSTODLL extern "C" void __attribute__ ((visibility ("default")))
|
|
||||||
|
|
||||||
#define STD_CALL /* */
|
|
||||||
|
|
||||||
// android is a linux with a special cases
|
|
||||||
// @todo: sse should be working ok on x86 android?
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
#define PLATFORM_ANDROID
|
|
||||||
|
|
||||||
#if defined (__arm__) || defined (__aarch64__ )
|
|
||||||
#undef PLATFORM_HAS_SSE2
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#error "Platform unrecognized."
|
|
||||||
#endif
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
// general product information
|
// general product information
|
||||||
#define PRODUCT_NAME "Yet Another POD-Bot"
|
#define PRODUCT_NAME "Yet Another POD-Bot"
|
||||||
#define PRODUCT_SHORT_NAME "YaPB"
|
#define PRODUCT_SHORT_NAME "YaPB"
|
||||||
#define PRODUCT_VERSION "2.91"
|
#define PRODUCT_VERSION "2.92"
|
||||||
#define PRODUCT_AUTHOR "YaPB Dev Team"
|
#define PRODUCT_AUTHOR "YaPB Dev Team"
|
||||||
#define PRODUCT_URL "https://yapb.ru/"
|
#define PRODUCT_URL "https://yapb.ru/"
|
||||||
#define PRODUCT_EMAIL "d@entix.io"
|
#define PRODUCT_EMAIL "d@entix.io"
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
#define PRODUCT_GIT_HASH "unspecified_hash"
|
#define PRODUCT_GIT_HASH "unspecified_hash"
|
||||||
#define PRODUCT_GIT_COMMIT_AUTHOR "unspecified_author"
|
#define PRODUCT_GIT_COMMIT_AUTHOR "unspecified_author"
|
||||||
#define PRODUCT_GIT_COMMIT_ID 0000
|
#define PRODUCT_GIT_COMMIT_ID 0000
|
||||||
#define PRODUCT_VERSION_DWORD_INTERNAL 2, 91
|
#define PRODUCT_VERSION_DWORD_INTERNAL 2, 92
|
||||||
#define PRODUCT_VERSION_DWORD PRODUCT_VERSION_DWORD_INTERNAL, PRODUCT_GIT_COMMIT_ID
|
#define PRODUCT_VERSION_DWORD PRODUCT_VERSION_DWORD_INTERNAL, PRODUCT_GIT_COMMIT_ID
|
||||||
#define PRODUCT_SUPPORT_VERSION "Beta 6.6 - Condition Zero"
|
#define PRODUCT_SUPPORT_VERSION "Beta 6.6 - Condition Zero"
|
||||||
#define PRODUCT_COMMENTS "http://github.com/jeefo/yapb/"
|
#define PRODUCT_COMMENTS "http://github.com/jeefo/yapb/"
|
||||||
|
|
|
||||||
2008
include/yapb.h
2008
include/yapb.h
File diff suppressed because it is too large
Load diff
|
|
@ -11,18 +11,19 @@ PROJECT = yapb
|
||||||
SOURCES = ../source
|
SOURCES = ../source
|
||||||
OBJECTS = $(wildcard $(SOURCES)/*.cpp)
|
OBJECTS = $(wildcard $(SOURCES)/*.cpp)
|
||||||
|
|
||||||
COMPILER_FLAGS = -mtune=generic -std=c++11 -m32 -Wall -Wextra -Werror -fno-exceptions -fno-rtti -DPOSIX
|
COMPILER_FLAGS = -std=c++11 -m32 -Wall -Wextra -Werror -fno-exceptions -fno-rtti
|
||||||
LINKER_FLAGS = -m32
|
LINKER_FLAGS = -m32 -ldl
|
||||||
|
|
||||||
ifeq "$(DEBUG)" "true"
|
ifeq "$(DEBUG)" "true"
|
||||||
COMPILER_FLAGS += -D_DEBUG -DDEBUG -g3
|
COMPILER_FLAGS += -g3 -DCR_DEBUG
|
||||||
BINARY_DIR = debug
|
BINARY_DIR = debug
|
||||||
else
|
else
|
||||||
COMPILER_FLAGS += -DNDEBUG -pipe -O3 -msse2 -funroll-loops -fomit-frame-pointer -fno-stack-protector -fvisibility=hidden -fvisibility-inlines-hidden -nostdinc++
|
COMPILER_FLAGS += -pipe -O3 -march=core2 -msse2 -mfpmath=sse -ffast-math -fno-builtin -fno-threadsafe-statics -funroll-loops -fomit-frame-pointer -fno-stack-protector -fvisibility=hidden -fvisibility-inlines-hidden
|
||||||
BINARY_DIR = release
|
BINARY_DIR = release
|
||||||
|
LINKER_FLAGS += -static-libgcc
|
||||||
endif
|
endif
|
||||||
|
|
||||||
INCLUDE = -I../include -I../include/engine
|
INCLUDE = -I../include
|
||||||
COMPILER = $(CC)
|
COMPILER = $(CC)
|
||||||
|
|
||||||
ifeq "$(shell uname -s)" "Darwin"
|
ifeq "$(shell uname -s)" "Darwin"
|
||||||
|
|
@ -31,11 +32,10 @@ endif
|
||||||
|
|
||||||
ifeq "$(OSX)" "true"
|
ifeq "$(OSX)" "true"
|
||||||
LIBRARY_EXT = dylib
|
LIBRARY_EXT = dylib
|
||||||
COMPILER_FLAGS += -DOSX -D_OSX -mmacosx-version-min=10.9
|
COMPILER_FLAGS += -mmacosx-version-min=10.9
|
||||||
LINKER_FLAGS += -dynamiclib -lstdc++ -mmacosx-version-min=10.9 -arch i386
|
LINKER_FLAGS += -dynamiclib -lstdc++ -mmacosx-version-min=10.9 -arch i386
|
||||||
else
|
else
|
||||||
LIBRARY_EXT = so
|
LIBRARY_EXT = so
|
||||||
COMPILER_FLAGS += -DLINUX -D_LINUX
|
|
||||||
LINKER_FLAGS += -shared
|
LINKER_FLAGS += -shared
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
@ -45,16 +45,26 @@ ifeq ($(findstring clang,$(COMPILER)),clang)
|
||||||
ifeq "$(OSX)" "false"
|
ifeq "$(OSX)" "false"
|
||||||
LINKER_FLAGS += -lgcc_eh
|
LINKER_FLAGS += -lgcc_eh
|
||||||
else
|
else
|
||||||
LINKER_FLAGS += -nostdlib++ -Wunused-command-line-argument
|
ifeq "$(DEBUG)" "true"
|
||||||
|
LINKER_FLAGS += -lstdc++
|
||||||
|
else
|
||||||
|
LINKER_FLAGS += -nostdlib++ -Wunused-command-line-argument -fuse-ld=lld -Wl,-z,notext --no-undefined
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
else ifeq ($(findstring gcc,$(COMPILER)),gcc)
|
else ifeq ($(findstring gcc,$(COMPILER)),gcc)
|
||||||
ifneq "$(OSX)" "false"
|
ifneq "$(OSX)" "false"
|
||||||
LINKER_FLAGS += -static-libgcc
|
ifneq "$(DEBUG)" "true"
|
||||||
COMPILER_FLAGS += -funroll-all-loops -Wno-implicit-fallthrough
|
LINKER_FLAGS += -Wl,--no-undefined -flto=thin
|
||||||
|
COMPILER_FLAGS += -funroll-all-loops -flto=thin
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
else ifeq ($(findstring icc,$(COMPILER)),icc)
|
else ifeq ($(findstring icc,$(COMPILER)),icc)
|
||||||
COMPILER_FLAGS += -funroll-all-loops -no-prec-div -no-inline-min-size -no-inline-max-size -wd11076 -wd11074
|
LINKER_FLAGS += -static-intel -no-intel-extensions
|
||||||
LINKER_FLAGS += -cxxlib-nostd -static-intel -no-intel-extensions
|
|
||||||
|
ifneq "$(DEBUG)" "true"
|
||||||
|
COMPILER_FLAGS += -funroll-all-loops -ipo -wd11076 -wd11074
|
||||||
|
LINKER_FLAGS += -cxxlib-nostd -Wl,--no-undefined,-z,notext,--gc-sections -ipo
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
OBJECTS_BIN := $(OBJECTS:%.cpp=$(BINARY_DIR)/%.o)
|
OBJECTS_BIN := $(OBJECTS:%.cpp=$(BINARY_DIR)/%.o)
|
||||||
|
|
@ -78,6 +88,7 @@ debug:
|
||||||
all:
|
all:
|
||||||
$(MAKE) compile DEBUG=true
|
$(MAKE) compile DEBUG=true
|
||||||
$(MAKE) compile DEBUG=false
|
$(MAKE) compile DEBUG=false
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf release/*.o
|
rm -rf release/*.o
|
||||||
rm -rf release/$(BINARY_OUTPUT)
|
rm -rf release/$(BINARY_OUTPUT)
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,29 @@
|
||||||
</ProjectConfiguration>
|
</ProjectConfiguration>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\include\compress.h" />
|
<ClInclude Include="..\include\crlib\cr-alloc.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-array.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-basic.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-binheap.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-color.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-complete.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-dict.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-files.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-http.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-lambda.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-library.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-logger.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-math.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-movable.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-platform.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-random.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-string.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-twin.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-ulz.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-uniqueptr.h" />
|
||||||
|
<ClInclude Include="..\include\crlib\cr-vector.h" />
|
||||||
<ClInclude Include="..\include\engine\model.h" />
|
<ClInclude Include="..\include\engine\model.h" />
|
||||||
<ClInclude Include="..\include\yapb.h" />
|
<ClInclude Include="..\include\yapb.h" />
|
||||||
<ClInclude Include="..\include\corelib.h" />
|
|
||||||
<ClInclude Include="..\include\engine.h" />
|
<ClInclude Include="..\include\engine.h" />
|
||||||
<ClInclude Include="..\include\engine\const.h" />
|
<ClInclude Include="..\include\engine\const.h" />
|
||||||
<ClInclude Include="..\include\engine\eiface.h" />
|
<ClInclude Include="..\include\engine\eiface.h" />
|
||||||
|
|
@ -22,7 +41,6 @@
|
||||||
<ClInclude Include="..\include\engine\meta_api.h" />
|
<ClInclude Include="..\include\engine\meta_api.h" />
|
||||||
<ClInclude Include="..\include\engine\progdefs.h" />
|
<ClInclude Include="..\include\engine\progdefs.h" />
|
||||||
<ClInclude Include="..\include\engine\util.h" />
|
<ClInclude Include="..\include\engine\util.h" />
|
||||||
<ClInclude Include="..\include\platform.h" />
|
|
||||||
<ClInclude Include="..\include\resource.h" />
|
<ClInclude Include="..\include\resource.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
@ -35,12 +53,13 @@
|
||||||
<ClCompile Include="..\source\interface.cpp" />
|
<ClCompile Include="..\source\interface.cpp" />
|
||||||
<ClCompile Include="..\source\navigate.cpp" />
|
<ClCompile Include="..\source\navigate.cpp" />
|
||||||
<ClCompile Include="..\source\support.cpp" />
|
<ClCompile Include="..\source\support.cpp" />
|
||||||
<ClCompile Include="..\source\waypoint.cpp" />
|
<ClCompile Include="..\source\graph.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="yapb.rc" />
|
<ResourceCompile Include="yapb.rc" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<None Include="..\source\Android.mk" />
|
||||||
<None Include="makefile" />
|
<None Include="makefile" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup Label="Globals">
|
<PropertyGroup Label="Globals">
|
||||||
|
|
@ -108,7 +127,7 @@
|
||||||
</Midl>
|
</Midl>
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>..\include\engine;..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
<PrecompiledHeader />
|
<PrecompiledHeader />
|
||||||
|
|
@ -181,7 +200,7 @@
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||||
<EnableFiberSafeOptimizations>false</EnableFiberSafeOptimizations>
|
<EnableFiberSafeOptimizations>false</EnableFiberSafeOptimizations>
|
||||||
<AdditionalIncludeDirectories>..\mmgr;..\include\engine;..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>NDEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>NDEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ExceptionHandling>false</ExceptionHandling>
|
<ExceptionHandling>false</ExceptionHandling>
|
||||||
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,11 @@
|
||||||
<Filter Include="include\engine">
|
<Filter Include="include\engine">
|
||||||
<UniqueIdentifier>{f98ff5ec-055a-46cd-b5b1-462ef4c1c73e}</UniqueIdentifier>
|
<UniqueIdentifier>{f98ff5ec-055a-46cd-b5b1-462ef4c1c73e}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="include\crlib">
|
||||||
|
<UniqueIdentifier>{76a583d1-8f55-451b-8516-2f7cce4d1875}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\include\compress.h">
|
|
||||||
<Filter>include</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\include\corelib.h">
|
|
||||||
<Filter>include</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\include\resource.h">
|
<ClInclude Include="..\include\resource.h">
|
||||||
<Filter>include</Filter>
|
<Filter>include</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
@ -42,9 +39,6 @@
|
||||||
<ClInclude Include="..\include\engine\util.h">
|
<ClInclude Include="..\include\engine\util.h">
|
||||||
<Filter>include\engine</Filter>
|
<Filter>include\engine</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\include\platform.h">
|
|
||||||
<Filter>include</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\include\engine.h">
|
<ClInclude Include="..\include\engine.h">
|
||||||
<Filter>include</Filter>
|
<Filter>include</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
@ -54,6 +48,69 @@
|
||||||
<ClInclude Include="..\include\engine\model.h">
|
<ClInclude Include="..\include\engine\model.h">
|
||||||
<Filter>include\engine</Filter>
|
<Filter>include\engine</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-alloc.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-array.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-basic.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-binheap.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-complete.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-dict.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-files.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-http.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-lambda.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-library.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-logger.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-math.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-movable.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-platform.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-random.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-string.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-twin.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-ulz.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-uniqueptr.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-vector.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\include\crlib\cr-color.h">
|
||||||
|
<Filter>include\crlib</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\source\chatlib.cpp">
|
<ClCompile Include="..\source\chatlib.cpp">
|
||||||
|
|
@ -68,9 +125,6 @@
|
||||||
<ClCompile Include="..\source\support.cpp">
|
<ClCompile Include="..\source\support.cpp">
|
||||||
<Filter>source</Filter>
|
<Filter>source</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\source\waypoint.cpp">
|
|
||||||
<Filter>source</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\source\manager.cpp">
|
<ClCompile Include="..\source\manager.cpp">
|
||||||
<Filter>source</Filter>
|
<Filter>source</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|
@ -80,10 +134,13 @@
|
||||||
<ClCompile Include="..\source\engine.cpp">
|
<ClCompile Include="..\source\engine.cpp">
|
||||||
<Filter>source</Filter>
|
<Filter>source</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\source\control.cpp">
|
||||||
|
<Filter>source</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\source\basecode.cpp">
|
<ClCompile Include="..\source\basecode.cpp">
|
||||||
<Filter>source</Filter>
|
<Filter>source</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\source\control.cpp">
|
<ClCompile Include="..\source\graph.cpp">
|
||||||
<Filter>source</Filter>
|
<Filter>source</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
@ -96,5 +153,8 @@
|
||||||
<None Include="makefile">
|
<None Include="makefile">
|
||||||
<Filter>project</Filter>
|
<Filter>project</Filter>
|
||||||
</None>
|
</None>
|
||||||
|
<None Include="..\source\Android.mk">
|
||||||
|
<Filter>project</Filter>
|
||||||
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
LOCAL_PATH := $(call my-dir)
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
include $(CLEAR_VARS)
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
include $(XASH3D_CONFIG)
|
include $(XASH3D_CONFIG)
|
||||||
|
|
||||||
LOCAL_MODULE := yapb
|
LOCAL_MODULE := yapb
|
||||||
|
|
@ -25,9 +24,10 @@ LOCAL_SRC_FILES := \
|
||||||
interface.cpp \
|
interface.cpp \
|
||||||
navigate.cpp \
|
navigate.cpp \
|
||||||
support.cpp \
|
support.cpp \
|
||||||
waypoint.cpp \
|
graph.cpp \
|
||||||
|
|
||||||
LOCAL_CFLAGS += -O2 -std=c++11 -DLINUX -D_LINUX -DPOSIX -pipe -fno-strict-aliasing -Wall -Werror
|
LOCAL_CFLAGS += -O3 -std=c++11 -DLINUX -D_LINUX -DPOSIX -pipe -fno-strict-aliasing -Wall -Werror -Wno-array-bounds
|
||||||
LOCAL_CPPFLAGS += -fno-exceptions -fno-rtti
|
LOCAL_CPPFLAGS += -fno-exceptions -fno-rtti
|
||||||
|
LOCAL_LDLIBS := -llog
|
||||||
|
|
||||||
include $(BUILD_SHARED_LIBRARY)
|
include $(BUILD_SHARED_LIBRARY)
|
||||||
|
|
|
||||||
2510
source/basecode.cpp
2510
source/basecode.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -19,11 +19,11 @@ void BotUtils::stripTags (String &line) {
|
||||||
for (const auto &tag : m_tags) {
|
for (const auto &tag : m_tags) {
|
||||||
const size_t start = line.find (tag.first, 0);
|
const size_t start = line.find (tag.first, 0);
|
||||||
|
|
||||||
if (start != String::INVALID_INDEX) {
|
if (start != String::kInvalidIndex) {
|
||||||
const size_t end = line.find (tag.second, start);
|
const size_t end = line.find (tag.second, start);
|
||||||
const size_t diff = end - start;
|
const size_t diff = end - start;
|
||||||
|
|
||||||
if (end != String::INVALID_INDEX && end > start && diff < 32 && diff > 4) {
|
if (end != String::kInvalidIndex && end > start && diff < 32 && diff > 4) {
|
||||||
line.erase (start, diff + tag.second.length ());
|
line.erase (start, diff + tag.second.length ());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -37,7 +37,7 @@ void BotUtils::humanizePlayerName (String &playerName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// drop tag marks, 80 percent of time
|
// drop tag marks, 80 percent of time
|
||||||
if (rng.chance (80)) {
|
if (rg.chance (80)) {
|
||||||
stripTags (playerName);
|
stripTags (playerName);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -45,14 +45,14 @@ void BotUtils::humanizePlayerName (String &playerName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// sometimes switch name to lower characters, only valid for the english languge
|
// sometimes switch name to lower characters, only valid for the english languge
|
||||||
if (rng.chance (15) && strcmp (yb_language.str (), "en") == 0) {
|
if (rg.chance (8) && strcmp (yb_language.str (), "en") == 0) {
|
||||||
playerName.lowercase ();
|
playerName.lowercase ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotUtils::addChatErrors (String &line) {
|
void BotUtils::addChatErrors (String &line) {
|
||||||
// sometimes switch name to lower characters, only valid for the english languge
|
// sometimes switch name to lower characters, only valid for the english languge
|
||||||
if (rng.chance (15) && strcmp (yb_language.str (), "en") == 0) {
|
if (rg.chance (8) && strcmp (yb_language.str (), "en") == 0) {
|
||||||
line.lowercase ();
|
line.lowercase ();
|
||||||
}
|
}
|
||||||
auto length = line.length ();
|
auto length = line.length ();
|
||||||
|
|
@ -61,13 +61,13 @@ void BotUtils::addChatErrors (String &line) {
|
||||||
size_t percentile = line.length () / 2;
|
size_t percentile = line.length () / 2;
|
||||||
|
|
||||||
// "length / 2" percent of time drop a character
|
// "length / 2" percent of time drop a character
|
||||||
if (rng.chance (percentile)) {
|
if (rg.chance (percentile)) {
|
||||||
line.erase (rng.getInt (length / 8, length - length / 8));
|
line.erase (rg.int_ (length / 8, length - length / 8), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// "length" / 4 precent of time swap character
|
// "length" / 4 precent of time swap character
|
||||||
if (rng.chance (percentile / 2)) {
|
if (rg.chance (percentile / 2)) {
|
||||||
size_t pos = rng.getInt (length / 8, 3 * length / 8); // choose random position in string
|
size_t pos = rg.int_ (length / 8, 3 * length / 8); // choose random position in string
|
||||||
cr::swap (line[pos], line[pos + 1]);
|
cr::swap (line[pos], line[pos + 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -76,7 +76,7 @@ void BotUtils::addChatErrors (String &line) {
|
||||||
bool BotUtils::checkKeywords (const String &line, String &reply) {
|
bool BotUtils::checkKeywords (const String &line, String &reply) {
|
||||||
// this function checks is string contain keyword, and generates reply to it
|
// this function checks is string contain keyword, and generates reply to it
|
||||||
|
|
||||||
if (!yb_chat.boolean () || line.empty ()) {
|
if (!yb_chat.bool_ () || line.empty ()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -84,7 +84,7 @@ bool BotUtils::checkKeywords (const String &line, String &reply) {
|
||||||
for (const auto &keyword : factory.keywords) {
|
for (const auto &keyword : factory.keywords) {
|
||||||
|
|
||||||
// check is keyword has occurred in message
|
// check is keyword has occurred in message
|
||||||
if (line.find (keyword, 0) != String::INVALID_INDEX) {
|
if (line.find (keyword) != String::kInvalidIndex) {
|
||||||
StringArray &usedReplies = factory.usedReplies;
|
StringArray &usedReplies = factory.usedReplies;
|
||||||
|
|
||||||
if (usedReplies.length () >= factory.replies.length () / 4) {
|
if (usedReplies.length () >= factory.replies.length () / 4) {
|
||||||
|
|
@ -113,11 +113,9 @@ bool BotUtils::checkKeywords (const String &line, String &reply) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto &chat = conf.getChat ();
|
|
||||||
|
|
||||||
// didn't find a keyword? 70% of the time use some universal reply
|
// didn't find a keyword? 70% of the time use some universal reply
|
||||||
if (rng.chance (70) && !chat[CHAT_NOKW].empty ()) {
|
if (rg.chance (70) && conf.hasChatBank (Chat::NoKeyword)) {
|
||||||
reply.assign (chat[CHAT_NOKW].random ());
|
reply.assign (conf.pickRandomFromChatBank (Chat::NoKeyword));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -126,47 +124,49 @@ bool BotUtils::checkKeywords (const String &line, String &reply) {
|
||||||
void Bot::prepareChatMessage (const String &message) {
|
void Bot::prepareChatMessage (const String &message) {
|
||||||
// this function parses messages from the botchat, replaces keywords and converts names into a more human style
|
// this function parses messages from the botchat, replaces keywords and converts names into a more human style
|
||||||
|
|
||||||
if (!yb_chat.boolean () || message.empty ()) {
|
if (!yb_chat.bool_ () || message.empty ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_chatBuffer = message;
|
m_chatBuffer.assign (message.chars ());
|
||||||
|
|
||||||
// must be called before return or on the end
|
// must be called before return or on the end
|
||||||
auto finishPreparation = [&] (void) {
|
auto finishPreparation = [&] () {
|
||||||
if (!m_chatBuffer.empty ()) {
|
if (!m_chatBuffer.empty ()) {
|
||||||
util.addChatErrors (m_chatBuffer);
|
util.addChatErrors (m_chatBuffer);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// need to check if we're have special symbols
|
// need to check if we're have special symbols
|
||||||
size_t pos = message.find ('%', 0);
|
size_t pos = message.find ('%');
|
||||||
|
|
||||||
// nothing found, bail out
|
// nothing found, bail out
|
||||||
if (pos == String::INVALID_INDEX || pos >= message.length ()) {
|
if (pos == String::kInvalidIndex || pos >= message.length ()) {
|
||||||
finishPreparation ();
|
finishPreparation ();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the humanized name out of client
|
// get the humanized name out of client
|
||||||
auto humanizedName = [] (const Client &client) -> String {
|
auto humanizedName = [] (int index) -> String {
|
||||||
if (!util.isPlayer (client.ent)) {
|
auto ent = game.playerOfIndex (index);
|
||||||
return cr::move (String ("unknown"));
|
|
||||||
|
if (!util.isPlayer (ent)) {
|
||||||
|
return "unknown";
|
||||||
}
|
}
|
||||||
String playerName = STRING (client.ent->v.netname);
|
String playerName = STRING (ent->v.netname);
|
||||||
util.humanizePlayerName (playerName);
|
util.humanizePlayerName (playerName);
|
||||||
|
|
||||||
return cr::move (playerName);
|
return playerName;
|
||||||
};
|
};
|
||||||
|
|
||||||
// find highfrag player
|
// find highfrag player
|
||||||
auto getHighfragPlayer = [&] (void) -> String {
|
auto getHighfragPlayer = [&] () -> String {
|
||||||
int highestFrags = -1;
|
int highestFrags = -1;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
for (int i = 0; i < game.maxClients (); i++) {
|
for (int i = 0; i < game.maxClients (); ++i) {
|
||||||
const Client &client = util.getClient (i);
|
const Client &client = util.getClient (i);
|
||||||
|
|
||||||
if (!(client.flags & CF_USED) || client.ent == ent ()) {
|
if (!(client.flags & ClientFlags::Used) || client.ent == ent ()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int frags = static_cast <int> (client.ent->v.frags);
|
int frags = static_cast <int> (client.ent->v.frags);
|
||||||
|
|
@ -176,147 +176,116 @@ void Bot::prepareChatMessage (const String &message) {
|
||||||
index = i;
|
index = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return humanizedName (util.getClient (index));
|
return humanizedName (index);
|
||||||
};
|
};
|
||||||
|
|
||||||
// get roundtime
|
// get roundtime
|
||||||
auto getRoundTime = [] (void) -> String {
|
auto getRoundTime = [] () -> String {
|
||||||
auto roundTimeSecs = static_cast <int> (bots.getRoundEndTime () - game.timebase ());
|
auto roundTimeSecs = static_cast <int> (bots.getRoundEndTime () - game.timebase ());
|
||||||
|
|
||||||
String roundTime;
|
String roundTime;
|
||||||
roundTime.assign ("%02d:%02d", cr::clamp (roundTimeSecs / 60, 0, 59), cr::clamp (cr::abs (roundTimeSecs % 60), 0, 59));
|
roundTime.assignf ("%02d:%02d", cr::clamp (roundTimeSecs / 60, 0, 59), cr::clamp (cr::abs (roundTimeSecs % 60), 0, 59));
|
||||||
|
|
||||||
return cr::move (roundTime);
|
return roundTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
// get bot's victim
|
// get bot's victim
|
||||||
auto getMyVictim = [&] (void) -> String {
|
auto getMyVictim = [&] () -> String {;
|
||||||
for (const Client &client : util.getClients ()) {
|
return humanizedName (game.indexOfPlayer (m_lastVictim));
|
||||||
if (client.ent == m_lastVictim) {
|
|
||||||
return humanizedName (client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cr::move (String ("unknown"));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// get the game name alias
|
// get the game name alias
|
||||||
auto getGameName = [] (void) -> String {
|
auto getGameName = [] () -> String {
|
||||||
String gameName;
|
String gameName;
|
||||||
|
|
||||||
if (game.is (GAME_CZERO)) {
|
if (game.is (GameFlags::ConditionZero)) {
|
||||||
if (rng.chance (30)) {
|
if (rg.chance (30)) {
|
||||||
gameName = "CZ";
|
gameName = "CZ";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gameName = "Condition Zero";
|
gameName = "Condition Zero";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (game.is (GAME_CSTRIKE16) || game.is (GAME_LEGACY)) {
|
else if (game.is (GameFlags::Modern) || game.is (GameFlags::Legacy)) {
|
||||||
if (rng.chance (30)) {
|
if (rg.chance (30)) {
|
||||||
gameName = "CS";
|
gameName = "CS";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gameName = "Counter-Strike";
|
gameName = "Counter-Strike";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return cr::move (gameName);
|
return gameName;
|
||||||
};
|
};
|
||||||
|
|
||||||
// get enemy or teammate alive
|
// get enemy or teammate alive
|
||||||
auto getPlayerAlive = [&] (bool needsEnemy) -> String {
|
auto getPlayerAlive = [&] (bool needsEnemy) -> String {
|
||||||
int index;
|
for (const auto &client : util.getClients ()) {
|
||||||
|
if (!(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive) || client.ent == ent ()) {
|
||||||
for (index = 0; index < game.maxClients (); index++) {
|
|
||||||
const Client &client = util.getClient (index);
|
|
||||||
|
|
||||||
if (!(client.flags & CF_USED) || !(client.flags & CF_ALIVE) || client.ent == ent ()) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((needsEnemy && m_team == client.team) || (!needsEnemy && m_team != client.team)) {
|
if (needsEnemy && m_team != client.team) {
|
||||||
continue;
|
return humanizedName (game.indexOfPlayer (client.ent));
|
||||||
|
}
|
||||||
|
else if (!needsEnemy && m_team == client.team) {
|
||||||
|
return humanizedName (game.indexOfPlayer (client.ent));
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
return "UnknowPA";
|
||||||
|
};
|
||||||
|
size_t replaceCounter = 0;
|
||||||
|
|
||||||
if (index < game.maxClients ()) {
|
while (replaceCounter < 6 && (pos = m_chatBuffer.find ('%')) != String::kInvalidIndex) {
|
||||||
if (!needsEnemy && util.isPlayer (pev->dmg_inflictor) && m_team == game.getTeam (pev->dmg_inflictor)) {
|
// found one, let's do replace
|
||||||
return humanizedName (util.getClient (game.indexOfEntity (pev->dmg_inflictor) - 1));
|
switch (message[pos + 1]) {
|
||||||
|
|
||||||
|
// the highest frag player
|
||||||
|
case 'f':
|
||||||
|
m_chatBuffer.replace ("%f", getHighfragPlayer ());
|
||||||
|
break;
|
||||||
|
|
||||||
|
// current map name
|
||||||
|
case 'm':
|
||||||
|
m_chatBuffer.replace ("%m", game.getMapName ());
|
||||||
|
break;
|
||||||
|
|
||||||
|
// round time
|
||||||
|
case 'r':
|
||||||
|
m_chatBuffer.replace ("%r", getRoundTime ());
|
||||||
|
break;
|
||||||
|
|
||||||
|
// chat reply
|
||||||
|
case 's':
|
||||||
|
if (m_sayTextBuffer.entityIndex != -1) {
|
||||||
|
m_chatBuffer.replace ("%s", humanizedName (m_sayTextBuffer.entityIndex));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return humanizedName (util.getClient (index));
|
m_chatBuffer.replace ("%s", getHighfragPlayer ());
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
else {
|
|
||||||
for (index = 0; index < game.maxClients (); index++) {
|
|
||||||
const Client &client = util.getClient (index);
|
|
||||||
|
|
||||||
if (!(client.flags & CF_USED) || client.team != m_team || client.ent == ent ()) {
|
// last bot victim
|
||||||
continue;
|
case 'v':
|
||||||
}
|
m_chatBuffer.replace ("%v", getMyVictim ());
|
||||||
|
break;
|
||||||
|
|
||||||
if ((needsEnemy && m_team != client.team) || (!needsEnemy && m_team == client.team)) {
|
// game name
|
||||||
continue;
|
case 'd':
|
||||||
}
|
m_chatBuffer.replace ("%d", getGameName ());
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (index < game.maxClients ()) {
|
// teammate alive
|
||||||
return humanizedName (util.getClient (index));
|
case 't':
|
||||||
}
|
m_chatBuffer.replace ("%t", getPlayerAlive (false));
|
||||||
}
|
break;
|
||||||
return cr::move (String ("unknown"));
|
|
||||||
};
|
|
||||||
|
|
||||||
// found one, let's do replace
|
// enemy alive
|
||||||
switch (message[pos + 1]) {
|
case 'e':
|
||||||
|
m_chatBuffer.replace ("%e", getPlayerAlive (true));
|
||||||
// the highest frag player
|
break;
|
||||||
case 'f':
|
};
|
||||||
m_chatBuffer.replace ("%f", getHighfragPlayer ());
|
replaceCounter++;
|
||||||
break;
|
}
|
||||||
|
|
||||||
// current map name
|
|
||||||
case 'm':
|
|
||||||
m_chatBuffer.replace ("%m", game.getMapName ());
|
|
||||||
break;
|
|
||||||
|
|
||||||
// round time
|
|
||||||
case 'r':
|
|
||||||
m_chatBuffer.replace ("%r", getRoundTime ());
|
|
||||||
break;
|
|
||||||
|
|
||||||
// chat reply
|
|
||||||
case 's':
|
|
||||||
if (m_sayTextBuffer.entityIndex != -1) {
|
|
||||||
m_chatBuffer.replace ("%s", humanizedName (util.getClient (m_sayTextBuffer.entityIndex)));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_chatBuffer.replace ("%s", getHighfragPlayer ());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// last bot victim
|
|
||||||
case 'v':
|
|
||||||
m_chatBuffer.replace ("%v", getMyVictim ());
|
|
||||||
break;
|
|
||||||
|
|
||||||
// game name
|
|
||||||
case 'd':
|
|
||||||
m_chatBuffer.replace ("%d", getGameName ());
|
|
||||||
break;
|
|
||||||
|
|
||||||
// teammate alive
|
|
||||||
case 't':
|
|
||||||
m_chatBuffer.replace ("%t", getPlayerAlive (false));
|
|
||||||
break;
|
|
||||||
|
|
||||||
// enemy alive
|
|
||||||
case 'e':
|
|
||||||
m_chatBuffer.replace ("%e", getPlayerAlive (true));
|
|
||||||
break;
|
|
||||||
|
|
||||||
};
|
|
||||||
finishPreparation ();
|
finishPreparation ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -327,18 +296,17 @@ bool Bot::checkChatKeywords (String &reply) {
|
||||||
return util.checkKeywords (message.uppercase (), reply);
|
return util.checkKeywords (message.uppercase (), reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bot::isReplyingToChat (void) {
|
bool Bot::isReplyingToChat () {
|
||||||
// this function sends reply to a player
|
// this function sends reply to a player
|
||||||
|
|
||||||
if (m_sayTextBuffer.entityIndex != -1 && !m_sayTextBuffer.sayText.empty ()) {
|
if (m_sayTextBuffer.entityIndex != -1 && !m_sayTextBuffer.sayText.empty ()) {
|
||||||
|
|
||||||
// check is time to chat is good
|
// check is time to chat is good
|
||||||
if (m_sayTextBuffer.timeNextChat < game.timebase ()) {
|
if (m_sayTextBuffer.timeNextChat < game.timebase () + rg.float_ (m_sayTextBuffer.chatDelay / 2, m_sayTextBuffer.chatDelay)) {
|
||||||
String replyText;
|
String replyText;
|
||||||
|
|
||||||
if (rng.chance (m_sayTextBuffer.chatProbability + rng.getInt (25, 45)) && checkChatKeywords (replyText)) {
|
if (rg.chance (m_sayTextBuffer.chatProbability + rg.int_ (20, 50)) && checkChatKeywords (replyText)) {
|
||||||
prepareChatMessage (replyText);
|
prepareChatMessage (replyText);
|
||||||
pushMsgQueue (GAME_MSG_SAY_CMD);
|
pushMsgQueue (BotMsg::Say);
|
||||||
|
|
||||||
m_sayTextBuffer.entityIndex = -1;
|
m_sayTextBuffer.entityIndex = -1;
|
||||||
m_sayTextBuffer.timeNextChat = game.timebase () + m_sayTextBuffer.chatDelay;
|
m_sayTextBuffer.timeNextChat = game.timebase () + m_sayTextBuffer.chatDelay;
|
||||||
|
|
@ -353,19 +321,17 @@ bool Bot::isReplyingToChat (void) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::checkForChat (void) {
|
void Bot::checkForChat () {
|
||||||
|
|
||||||
// say a text every now and then
|
// say a text every now and then
|
||||||
if (rng.chance (35) || m_notKilled || !yb_chat.boolean ()) {
|
if (rg.chance (30) || m_notKilled || !yb_chat.bool_ ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bot chatting turned on?
|
// bot chatting turned on?
|
||||||
if (m_lastChatTime + 10.0 < game.timebase () && bots.getLastChatTimestamp () + 5.0f < game.timebase () && !isReplyingToChat ()) {
|
if (m_lastChatTime + rg.float_ (6.0f, 10.0f) < game.timebase () && bots.getLastChatTimestamp () + rg.float_ (2.5f, 5.0f) < game.timebase () && !isReplyingToChat ()) {
|
||||||
auto &chat = conf.getChat ();
|
if (conf.hasChatBank (Chat::Dead)) {
|
||||||
|
const auto &phrase = conf.pickRandomFromChatBank (Chat::Dead);
|
||||||
if (!chat[CHAT_DEAD].empty ()) {
|
|
||||||
const String &phrase = chat[CHAT_DEAD].random ();
|
|
||||||
bool sayBufferExists = false;
|
bool sayBufferExists = false;
|
||||||
|
|
||||||
// search for last messages, sayed
|
// search for last messages, sayed
|
||||||
|
|
@ -375,9 +341,10 @@ void Bot::checkForChat (void) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sayBufferExists) {
|
if (!sayBufferExists) {
|
||||||
prepareChatMessage (phrase);
|
prepareChatMessage (phrase);
|
||||||
pushMsgQueue (GAME_MSG_SAY_CMD);
|
pushMsgQueue (BotMsg::Say);
|
||||||
|
|
||||||
m_lastChatTime = game.timebase ();
|
m_lastChatTime = game.timebase ();
|
||||||
bots.setLastChatTimestamp (game.timebase ());
|
bots.setLastChatTimestamp (game.timebase ());
|
||||||
|
|
@ -388,7 +355,7 @@ void Bot::checkForChat (void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear the used line buffer every now and then
|
// clear the used line buffer every now and then
|
||||||
if (static_cast <int> (m_sayTextBuffer.lastUsedSentences.length ()) > rng.getInt (4, 6)) {
|
if (static_cast <int> (m_sayTextBuffer.lastUsedSentences.length ()) > rg.int_ (4, 6)) {
|
||||||
m_sayTextBuffer.lastUsedSentences.clear ();
|
m_sayTextBuffer.lastUsedSentences.clear ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -397,17 +364,17 @@ void Bot::checkForChat (void) {
|
||||||
void Bot::say (const char *text) {
|
void Bot::say (const char *text) {
|
||||||
// this function prints saytext message to all players
|
// this function prints saytext message to all players
|
||||||
|
|
||||||
if (util.isEmptyStr (text) || !yb_chat.boolean ()) {
|
if (util.isEmptyStr (text) || !yb_chat.bool_ ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
game.execBotCmd (ent (), "say \"%s\"", text);
|
game.botCommand (ent (), "say \"%s\"", text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Bot::sayTeam (const char *text) {
|
void Bot::sayTeam (const char *text) {
|
||||||
// this function prints saytext message only for teammates
|
// this function prints saytext message only for teammates
|
||||||
|
|
||||||
if (util.isEmptyStr (text) || !yb_chat.boolean ()) {
|
if (util.isEmptyStr (text) || !yb_chat.bool_ ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
game.execBotCmd (ent (), "say_team \"%s\"", text);
|
game.botCommand (ent (), "say_team \"%s\"", text);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
1205
source/control.cpp
1205
source/control.cpp
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
2940
source/graph.cpp
Normal file
2940
source/graph.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
#include <yapb.h>
|
#include <yapb.h>
|
||||||
|
|
||||||
ConVar yb_version ("yb_version", PRODUCT_VERSION, VT_READONLY);
|
ConVar yb_version ("yb_version", PRODUCT_VERSION, Var::ReadOnly);
|
||||||
|
|
||||||
gamefuncs_t dllapi;
|
gamefuncs_t dllapi;
|
||||||
enginefuncs_t engfuncs;
|
enginefuncs_t engfuncs;
|
||||||
|
|
@ -33,7 +33,7 @@ plugin_info_t Plugin_info = {
|
||||||
PT_ANYTIME, // when unloadable
|
PT_ANYTIME, // when unloadable
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace VariadicCallbacks {
|
namespace variadic {
|
||||||
void clientCommand (edict_t *ent, char const *format, ...) {
|
void clientCommand (edict_t *ent, char const *format, ...) {
|
||||||
// this function forces the client whose player entity is ent to issue a client command.
|
// this function forces the client whose player entity is ent to issue a client command.
|
||||||
// How it works is that clients all have a argv global string in their client DLL that
|
// How it works is that clients all have a argv global string in their client DLL that
|
||||||
|
|
@ -50,31 +50,31 @@ namespace VariadicCallbacks {
|
||||||
// case it's a bot asking for a client command, we handle it like we do for bot commands
|
// case it's a bot asking for a client command, we handle it like we do for bot commands
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
char buffer[MAX_PRINT_BUFFER];
|
auto buffer = strings.chars ();
|
||||||
|
|
||||||
va_start (ap, format);
|
va_start (ap, format);
|
||||||
_vsnprintf (buffer, cr::bufsize (buffer), format, ap);
|
_vsnprintf (buffer, StringBuffer::StaticBufferSize, format, ap);
|
||||||
va_end (ap);
|
va_end (ap);
|
||||||
|
|
||||||
if (ent && (ent->v.flags & (FL_FAKECLIENT | FL_DORMANT))) {
|
if (ent && (ent->v.flags & (FL_FAKECLIENT | FL_DORMANT))) {
|
||||||
if (bots.getBot (ent)) {
|
if (bots[ent]) {
|
||||||
game.execBotCmd (ent, buffer);
|
game.botCommand (ent, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_SUPERCEDE); // prevent bots to be forced to issue client commands
|
RETURN_META (MRES_SUPERCEDE); // prevent bots to be forced to issue client commands
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
engfuncs.pfnClientCommand (ent, buffer);
|
engfuncs.pfnClientCommand (ent, buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
CR_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
// this function is called right after GiveFnptrsToDll() by the engine in the game DLL (or
|
// this function is called right after GiveFnptrsToDll() by the engine in the game DLL (or
|
||||||
// what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can
|
// what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can
|
||||||
// be called by the engine, into a memory block pointed to by the functionTable pointer
|
// be called by the engine, into a memory block pointed to by the functionTable pointer
|
||||||
|
|
@ -87,13 +87,12 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
|
|
||||||
memset (functionTable, 0, sizeof (gamefuncs_t));
|
memset (functionTable, 0, sizeof (gamefuncs_t));
|
||||||
|
|
||||||
if (!(game.is (GAME_METAMOD))) {
|
if (!(game.is (GameFlags::Metamod))) {
|
||||||
auto api_GetEntityAPI = game.getLib ().resolve <int (*) (gamefuncs_t *, int)> ("GetEntityAPI");
|
auto api_GetEntityAPI = game.lib ().resolve <int (*) (gamefuncs_t *, int)> ("GetEntityAPI");
|
||||||
|
|
||||||
// pass other DLLs engine callbacks to function table...
|
// pass other DLLs engine callbacks to function table...
|
||||||
if (api_GetEntityAPI (&dllapi, INTERFACE_VERSION) == 0) {
|
if (!api_GetEntityAPI || api_GetEntityAPI (&dllapi, INTERFACE_VERSION) == 0) {
|
||||||
util.logEntry (true, LL_FATAL, "GetEntityAPI2: ERROR - Not Initialized.");
|
logger.fatal ("Could not resolve symbol \"%s\" in the game dll.", "GetEntityAPI");
|
||||||
return FALSE; // error initializing function table!!!
|
|
||||||
}
|
}
|
||||||
dllfuncs.dllapi_table = &dllapi;
|
dllfuncs.dllapi_table = &dllapi;
|
||||||
gpGamedllFuncs = &dllfuncs;
|
gpGamedllFuncs = &dllfuncs;
|
||||||
|
|
@ -101,7 +100,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
memcpy (functionTable, &dllapi, sizeof (gamefuncs_t));
|
memcpy (functionTable, &dllapi, sizeof (gamefuncs_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
functionTable->pfnGameInit = [] (void) {
|
functionTable->pfnGameInit = [] () {
|
||||||
// this function is a one-time call, and appears to be the second function called in the
|
// this function is a one-time call, and appears to be the second function called in the
|
||||||
// DLL after GiveFntprsToDll() has been called. Its purpose is to tell the MOD DLL to
|
// DLL after GiveFntprsToDll() has been called. Its purpose is to tell the MOD DLL to
|
||||||
// initialize the game before the engine actually hooks into it with its video frames and
|
// initialize the game before the engine actually hooks into it with its video frames and
|
||||||
|
|
@ -110,6 +109,14 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
// server is enabled. Here is a good place to do our own game session initialization, and
|
// server is enabled. Here is a good place to do our own game session initialization, and
|
||||||
// to register by the engine side the server commands we need to administrate our bots.
|
// to register by the engine side the server commands we need to administrate our bots.
|
||||||
|
|
||||||
|
// register bot cvars
|
||||||
|
game.registerCvars ();
|
||||||
|
|
||||||
|
// register logger
|
||||||
|
logger.initialize (strings.format ("%slogs/yapb.log", graph.getDataDirectory (false)), [] (const char *msg) {
|
||||||
|
game.print (msg);
|
||||||
|
});
|
||||||
|
|
||||||
conf.initWeapons ();
|
conf.initWeapons ();
|
||||||
|
|
||||||
// register server command(s)
|
// register server command(s)
|
||||||
|
|
@ -117,20 +124,20 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
game.registerCmd ("yb", BotControl::handleEngineCommands);
|
game.registerCmd ("yb", BotControl::handleEngineCommands);
|
||||||
|
|
||||||
// set correct version string
|
// set correct version string
|
||||||
yb_version.set (util.format ("%d.%d.%d", PRODUCT_VERSION_DWORD_INTERNAL, util.buildNumber ()));
|
yb_version.set (strings.format ("%d.%d.%d", PRODUCT_VERSION_DWORD_INTERNAL, util.buildNumber ()));
|
||||||
|
|
||||||
// execute main config
|
// execute main config
|
||||||
conf.load (true);
|
conf.loadMainConfig ();
|
||||||
|
|
||||||
// register fake metamod command handler if we not! under mm
|
// register fake metamod command handler if we not! under mm
|
||||||
if (!(game.is (GAME_METAMOD))) {
|
if (!(game.is (GameFlags::Metamod))) {
|
||||||
game.registerCmd ("meta", [] (void) {
|
game.registerCmd ("meta", [] () {
|
||||||
game.print ("You're launched standalone version of yapb. Metamod is not installed or not enabled!");
|
game.print ("You're launched standalone version of yapb. Metamod is not installed or not enabled!");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
conf.adjustWeaponPrices ();
|
conf.adjustWeaponPrices ();
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
dllapi.pfnGameInit ();
|
dllapi.pfnGameInit ();
|
||||||
|
|
@ -144,7 +151,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
|
|
||||||
game.precache ();
|
game.precache ();
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META_VALUE (MRES_IGNORED, 0);
|
RETURN_META_VALUE (MRES_IGNORED, 0);
|
||||||
}
|
}
|
||||||
int result = dllapi.pfnSpawn (ent); // get result
|
int result = dllapi.pfnSpawn (ent); // get result
|
||||||
|
|
@ -168,7 +175,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
// is called twice, once for each entity moving.
|
// is called twice, once for each entity moving.
|
||||||
|
|
||||||
if (!game.isNullEntity (pentTouched) && pentOther != game.getStartEntity ()) {
|
if (!game.isNullEntity (pentTouched) && pentOther != game.getStartEntity ()) {
|
||||||
Bot *bot = bots.getBot (pentTouched);
|
auto bot = bots[pentTouched];
|
||||||
|
|
||||||
if (bot != nullptr && pentOther != bot->ent ()) {
|
if (bot != nullptr && pentOther != bot->ent ()) {
|
||||||
|
|
||||||
|
|
@ -181,7 +188,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
dllapi.pfnTouch (pentTouched, pentOther);
|
dllapi.pfnTouch (pentTouched, pentOther);
|
||||||
|
|
@ -212,13 +219,13 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
if (strcmp (addr, "loopback") == 0) {
|
if (strcmp (addr, "loopback") == 0) {
|
||||||
game.setLocalEntity (ent); // save the edict of the listen server client...
|
game.setLocalEntity (ent); // save the edict of the listen server client...
|
||||||
|
|
||||||
// if not dedicated set the default editor for waypoints
|
// if not dedicated set the default editor for graph
|
||||||
if (!game.isDedicated ()) {
|
if (!game.isDedicated ()) {
|
||||||
waypoints.setEditor (ent);
|
graph.setEditor (ent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META_VALUE (MRES_IGNORED, 0);
|
RETURN_META_VALUE (MRES_IGNORED, 0);
|
||||||
}
|
}
|
||||||
return dllapi.pfnClientConnect (ent, name, addr, rejectReason);
|
return dllapi.pfnClientConnect (ent, name, addr, rejectReason);
|
||||||
|
|
@ -236,18 +243,18 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
// to reset his entity pointer for safety. There are still a few server frames to go once a
|
// to reset his entity pointer for safety. There are still a few server frames to go once a
|
||||||
// listen server client disconnects, and we don't want to send him any sort of message then.
|
// listen server client disconnects, and we don't want to send him any sort of message then.
|
||||||
|
|
||||||
int index = game.indexOfEntity (ent) - 1;
|
for (auto &bot : bots) {
|
||||||
|
if (bot->pev == &ent->v) {
|
||||||
if (index >= 0 && index < MAX_ENGINE_PLAYERS) {
|
|
||||||
auto bot = bots.getBot (index);
|
|
||||||
|
|
||||||
// check if its a bot
|
|
||||||
if (bot != nullptr && bot->pev == &ent->v) {
|
|
||||||
bot->showChaterIcon (false);
|
bot->showChaterIcon (false);
|
||||||
bots.destroy (index);
|
|
||||||
|
conf.clearUsedName (bot.get ()); // clear the bot name
|
||||||
|
bots.erase (bot.get ()); // remove the bot from bots array
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (game.is (GAME_METAMOD)) {
|
|
||||||
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
dllapi.pfnClientDisconnect (ent);
|
dllapi.pfnClientDisconnect (ent);
|
||||||
|
|
@ -261,7 +268,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
|
|
||||||
ctrl.assignAdminRights (ent, infobuffer);
|
ctrl.assignAdminRights (ent, infobuffer);
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
dllapi.pfnClientUserInfoChanged (ent, infobuffer);
|
dllapi.pfnClientUserInfoChanged (ent, infobuffer);
|
||||||
|
|
@ -282,14 +289,14 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
// clients. Hence it can lack of commenting a bit, since this code is very subject to change.
|
// clients. Hence it can lack of commenting a bit, since this code is very subject to change.
|
||||||
|
|
||||||
if (ctrl.handleClientCommands (ent)) {
|
if (ctrl.handleClientCommands (ent)) {
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_SUPERCEDE);
|
RETURN_META (MRES_SUPERCEDE);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (ctrl.handleMenuCommands (ent)) {
|
else if (ctrl.handleMenuCommands (ent)) {
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_SUPERCEDE);
|
RETURN_META (MRES_SUPERCEDE);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
@ -298,7 +305,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
// record stuff about radio and chat
|
// record stuff about radio and chat
|
||||||
bots.captureChatRadio (engfuncs.pfnCmd_Argv (0), engfuncs.pfnCmd_Argv (1), ent);
|
bots.captureChatRadio (engfuncs.pfnCmd_Argv (0), engfuncs.pfnCmd_Argv (1), ent);
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
dllapi.pfnClientCommand (ent);
|
dllapi.pfnClientCommand (ent);
|
||||||
|
|
@ -312,8 +319,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
// loading the bot profiles, and drawing the world map (ie, filling the navigation hashtable).
|
// loading the bot profiles, and drawing the world map (ie, filling the navigation hashtable).
|
||||||
// Once this function has been called, the server can be considered as "running".
|
// Once this function has been called, the server can be considered as "running".
|
||||||
|
|
||||||
bots.destroy ();
|
conf.loadConfigs (); // initialize all config files
|
||||||
conf.load (false); // initialize all config files
|
|
||||||
|
|
||||||
// do a level initialization
|
// do a level initialization
|
||||||
game.levelInitialize (pentEdictList, edictCount);
|
game.levelInitialize (pentEdictList, edictCount);
|
||||||
|
|
@ -322,27 +328,26 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
illum.resetWorldModel ();
|
illum.resetWorldModel ();
|
||||||
|
|
||||||
// do level initialization stuff here...
|
// do level initialization stuff here...
|
||||||
waypoints.init ();
|
graph.loadGraphData ();
|
||||||
waypoints.load ();
|
|
||||||
|
|
||||||
// execute main config
|
// execute main config
|
||||||
conf.load (true);
|
conf.loadMainConfig ();
|
||||||
|
|
||||||
if (File::exists (util.format ("%s/maps/%s_yapb.cfg", game.getModName (), game.getMapName ()))) {
|
if (File::exists (strings.format ("%s/maps/%s_yapb.cfg", game.getModName (), game.getMapName ()))) {
|
||||||
game.execCmd ("exec maps/%s_yapb.cfg", game.getMapName ());
|
game.serverCommand ("exec maps/%s_yapb.cfg", game.getMapName ());
|
||||||
game.print ("Executing Map-Specific config file");
|
game.print ("Executing Map-Specific config file");
|
||||||
}
|
}
|
||||||
bots.initQuota ();
|
bots.initQuota ();
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
dllapi.pfnServerActivate (pentEdictList, edictCount, clientMax);
|
dllapi.pfnServerActivate (pentEdictList, edictCount, clientMax);
|
||||||
|
|
||||||
waypoints.rebuildVisibility ();
|
graph.rebuildVisibility ();
|
||||||
};
|
};
|
||||||
|
|
||||||
functionTable->pfnServerDeactivate = [] (void) {
|
functionTable->pfnServerDeactivate = [] () {
|
||||||
// this function is called when the server is shutting down. A particular note about map
|
// this function is called when the server is shutting down. A particular note about map
|
||||||
// changes: changing the map means shutting down the server and starting a new one. Of course
|
// changes: changing the map means shutting down the server and starting a new one. Of course
|
||||||
// this process is transparent to the user, but either in single player when the hero reaches
|
// this process is transparent to the user, but either in single player when the hero reaches
|
||||||
|
|
@ -354,8 +359,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
// the loading of new bots and the new BSP data parsing there.
|
// the loading of new bots and the new BSP data parsing there.
|
||||||
|
|
||||||
// save collected experience on shutdown
|
// save collected experience on shutdown
|
||||||
waypoints.saveExperience ();
|
graph.savePractice ();
|
||||||
waypoints.saveVisibility ();
|
|
||||||
|
|
||||||
// destroy global killer entity
|
// destroy global killer entity
|
||||||
bots.destroyKillerEntity ();
|
bots.destroyKillerEntity ();
|
||||||
|
|
@ -370,19 +374,21 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
util.setNeedForWelcome (false);
|
util.setNeedForWelcome (false);
|
||||||
|
|
||||||
// xash is not kicking fakeclients on changelevel
|
// xash is not kicking fakeclients on changelevel
|
||||||
if (game.is (GAME_XASH_ENGINE)) {
|
if (game.is (GameFlags::Xash3D)) {
|
||||||
bots.kickEveryone (true, false);
|
bots.kickEveryone (true, false);
|
||||||
bots.destroy ();
|
|
||||||
}
|
}
|
||||||
waypoints.init ();
|
graph.initGraph ();
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
// clear all the bots
|
||||||
|
bots.destroy ();
|
||||||
|
|
||||||
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
dllapi.pfnServerDeactivate ();
|
dllapi.pfnServerDeactivate ();
|
||||||
};
|
};
|
||||||
|
|
||||||
functionTable->pfnStartFrame = [] (void) {
|
functionTable->pfnStartFrame = [] () {
|
||||||
// this function starts a video frame. It is called once per video frame by the game. If
|
// this function starts a video frame. It is called once per video frame by the game. If
|
||||||
// you run Half-Life at 90 fps, this function will then be called 90 times per second. By
|
// you run Half-Life at 90 fps, this function will then be called 90 times per second. By
|
||||||
// placing a hook on it, we have a good place to do things that should be done continuously
|
// placing a hook on it, we have a good place to do things that should be done continuously
|
||||||
|
|
@ -400,10 +406,9 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
// update some stats for clients
|
// update some stats for clients
|
||||||
util.updateClients ();
|
util.updateClients ();
|
||||||
|
|
||||||
if (waypoints.hasEditFlag (WS_EDIT_ENABLED) && waypoints.hasEditor ()) {
|
if (graph.hasEditFlag (GraphEdit::On) && graph.hasEditor ()) {
|
||||||
waypoints.frame ();
|
graph.frame ();
|
||||||
}
|
}
|
||||||
bots.updateDeathMsgState (false);
|
|
||||||
|
|
||||||
// run stuff periodically
|
// run stuff periodically
|
||||||
game.slowFrame ();
|
game.slowFrame ();
|
||||||
|
|
@ -419,7 +424,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
// keep bot number up to date
|
// keep bot number up to date
|
||||||
bots.maintainQuota ();
|
bots.maintainQuota ();
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
dllapi.pfnStartFrame ();
|
dllapi.pfnStartFrame ();
|
||||||
|
|
@ -428,17 +433,24 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
bots.slowFrame ();
|
bots.slowFrame ();
|
||||||
};
|
};
|
||||||
|
|
||||||
functionTable->pfnUpdateClientData = [] (const struct edict_s *ent, int sendweapons, struct clientdata_s *cd) {
|
functionTable->pfnCmdStart = [] (const edict_t *player, usercmd_t *cmd, unsigned int random_seed) {
|
||||||
extern ConVar yb_latency_display;
|
auto ent = const_cast <edict_t *> (player);
|
||||||
|
|
||||||
if (game.is (GAME_SUPPORT_SVC_PINGS) && yb_latency_display.integer () == 2 && bots.hasBotsOnline ()) {
|
// if we're handle pings for bots and clients, clear IN_SCORE button so SV_ShouldUpdatePing engine function return false
|
||||||
bots.sendPingOffsets (const_cast <edict_t *> (ent));
|
// and SV_EmitPings will not overwrite our results
|
||||||
|
if (game.is (GameFlags::HasFakePings) && yb_show_latency.int_ () == 2) {
|
||||||
|
if ((cmd->buttons & IN_SCORE) || (ent->v.oldbuttons & IN_SCORE)) {
|
||||||
|
cmd->buttons &= ~IN_SCORE;
|
||||||
|
|
||||||
|
// send our version of pings
|
||||||
|
util.sendPings (ent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
dllapi.pfnUpdateClientData (ent, sendweapons, cd);
|
dllapi.pfnCmdStart (player, cmd, random_seed);
|
||||||
};
|
};
|
||||||
|
|
||||||
functionTable->pfnPM_Move = [] (playermove_t *playerMove, int server) {
|
functionTable->pfnPM_Move = [] (playermove_t *playerMove, int server) {
|
||||||
|
|
@ -449,7 +461,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
|
|
||||||
illum.setWorldModel (playerMove->physents[0].model);
|
illum.setWorldModel (playerMove->physents[0].model);
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
dllapi.pfnPM_Move (playerMove, server);
|
dllapi.pfnPM_Move (playerMove, server);
|
||||||
|
|
@ -457,8 +469,8 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2 (gamefuncs_t *functionTable, int *) {
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHARED_LIBRARAY_EXPORT int GetEntityAPI2_Post (gamefuncs_t *functionTable, int *) {
|
CR_EXPORT int GetEntityAPI2_Post (gamefuncs_t *table, int *) {
|
||||||
// this function is called right after FuncPointers_t() by the engine in the game DLL (or
|
// this function is called right after GiveFnptrsToDll() by the engine in the game DLL (or
|
||||||
// what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can
|
// what it BELIEVES to be the game DLL), in order to copy the list of MOD functions that can
|
||||||
// be called by the engine, into a memory block pointed to by the functionTable pointer
|
// be called by the engine, into a memory block pointed to by the functionTable pointer
|
||||||
// that is passed into this function (explanation comes straight from botman). This allows
|
// that is passed into this function (explanation comes straight from botman). This allows
|
||||||
|
|
@ -468,9 +480,9 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2_Post (gamefuncs_t *functionTable, int *
|
||||||
// engine, and then calls the MOD DLL's version of GetEntityAPI to get the REAL gamedll
|
// engine, and then calls the MOD DLL's version of GetEntityAPI to get the REAL gamedll
|
||||||
// functions this time (to use in the bot code). Post version, called only by metamod.
|
// functions this time (to use in the bot code). Post version, called only by metamod.
|
||||||
|
|
||||||
memset (functionTable, 0, sizeof (gamefuncs_t));
|
memset (table, 0, sizeof (gamefuncs_t));
|
||||||
|
|
||||||
functionTable->pfnSpawn = [] (edict_t *ent) {
|
table->pfnSpawn = [] (edict_t *ent) {
|
||||||
// this function asks the game DLL to spawn (i.e, give a physical existence in the virtual
|
// this function asks the game DLL to spawn (i.e, give a physical existence in the virtual
|
||||||
// world, in other words to 'display') the entity pointed to by ent in the game. The
|
// world, in other words to 'display') the entity pointed to by ent in the game. The
|
||||||
// Spawn() function is one of the functions any entity is supposed to have in the game DLL,
|
// Spawn() function is one of the functions any entity is supposed to have in the game DLL,
|
||||||
|
|
@ -484,7 +496,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2_Post (gamefuncs_t *functionTable, int *
|
||||||
RETURN_META_VALUE (MRES_IGNORED, 0);
|
RETURN_META_VALUE (MRES_IGNORED, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
functionTable->pfnStartFrame = [] (void) {
|
table->pfnStartFrame = [] () {
|
||||||
// this function starts a video frame. It is called once per video frame by the game. If
|
// this function starts a video frame. It is called once per video frame by the game. If
|
||||||
// you run Half-Life at 90 fps, this function will then be called 90 times per second. By
|
// you run Half-Life at 90 fps, this function will then be called 90 times per second. By
|
||||||
// placing a hook on it, we have a good place to do things that should be done continuously
|
// placing a hook on it, we have a good place to do things that should be done continuously
|
||||||
|
|
@ -496,7 +508,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2_Post (gamefuncs_t *functionTable, int *
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
};
|
};
|
||||||
|
|
||||||
functionTable->pfnServerActivate = [] (edict_t *, int, int) {
|
table->pfnServerActivate = [] (edict_t *, int, int) {
|
||||||
// this function is called when the server has fully loaded and is about to manifest itself
|
// this function is called when the server has fully loaded and is about to manifest itself
|
||||||
// on the network as such. Since a mapchange is actually a server shutdown followed by a
|
// on the network as such. Since a mapchange is actually a server shutdown followed by a
|
||||||
// restart, this function is also called when a new map is being loaded. Hence it's the
|
// restart, this function is also called when a new map is being loaded. Hence it's the
|
||||||
|
|
@ -505,7 +517,7 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2_Post (gamefuncs_t *functionTable, int *
|
||||||
// Once this function has been called, the server can be considered as "running". Post version
|
// Once this function has been called, the server can be considered as "running". Post version
|
||||||
// called only by metamod.
|
// called only by metamod.
|
||||||
|
|
||||||
waypoints.rebuildVisibility ();
|
graph.rebuildVisibility ();
|
||||||
|
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
};
|
};
|
||||||
|
|
@ -513,21 +525,21 @@ SHARED_LIBRARAY_EXPORT int GetEntityAPI2_Post (gamefuncs_t *functionTable, int *
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHARED_LIBRARAY_EXPORT int GetNewDLLFunctions (newgamefuncs_t *functionTable, int *interfaceVersion) {
|
CR_EXPORT int GetNewDLLFunctions (newgamefuncs_t *functionTable, int *interfaceVersion) {
|
||||||
// it appears that an extra function table has been added in the engine to gamedll interface
|
// it appears that an extra function table has been added in the engine to gamedll interface
|
||||||
// since the date where the first enginefuncs table standard was frozen. These ones are
|
// since the date where the first enginefuncs table standard was frozen. These ones are
|
||||||
// facultative and we don't hook them, but since some MODs might be featuring it, we have to
|
// facultative and we don't hook them, but since some MODs might be featuring it, we have to
|
||||||
// pass them too, else the DLL interfacing wouldn't be complete and the game possibly wouldn't
|
// pass them too, else the DLL interfacing wouldn't be complete and the game possibly wouldn't
|
||||||
// run properly.
|
// run properly.
|
||||||
|
|
||||||
auto api_GetNewDLLFunctions = game.getLib ().resolve <int (*) (newgamefuncs_t *, int *)> ("GetNewDLLFunctions");
|
auto api_GetNewDLLFunctions = game.lib ().resolve <int (*) (newgamefuncs_t *, int *)> (__FUNCTION__);
|
||||||
|
|
||||||
if (api_GetNewDLLFunctions == nullptr) {
|
if (api_GetNewDLLFunctions == nullptr) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!api_GetNewDLLFunctions (functionTable, interfaceVersion)) {
|
if (!api_GetNewDLLFunctions || !api_GetNewDLLFunctions (functionTable, interfaceVersion)) {
|
||||||
util.logEntry (true, LL_ERROR, "GetNewDLLFunctions: ERROR - Not Initialized.");
|
logger.error ("Could not resolve symbol \"%s\" in the game dll. Continuing...", __FUNCTION__);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -535,8 +547,8 @@ SHARED_LIBRARAY_EXPORT int GetNewDLLFunctions (newgamefuncs_t *functionTable, in
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
|
CR_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int *) {
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
memset (functionTable, 0, sizeof (enginefuncs_t));
|
memset (functionTable, 0, sizeof (enginefuncs_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -551,10 +563,9 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
// spawn point named "tr_2lm".
|
// spawn point named "tr_2lm".
|
||||||
|
|
||||||
// save collected experience on map change
|
// save collected experience on map change
|
||||||
waypoints.saveExperience ();
|
graph.savePractice ();
|
||||||
waypoints.saveVisibility ();
|
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
engfuncs.pfnChangeLevel (s1, s2);
|
engfuncs.pfnChangeLevel (s1, s2);
|
||||||
|
|
@ -565,7 +576,7 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
|
|
||||||
illum.updateLight (style, val);
|
illum.updateLight (style, val);
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
engfuncs.pfnLightStyle (style, val);
|
engfuncs.pfnLightStyle (style, val);
|
||||||
|
|
@ -573,11 +584,11 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
|
|
||||||
functionTable->pfnFindEntityByString = [] (edict_t *edictStartSearchAfter, const char *field, const char *value) {
|
functionTable->pfnFindEntityByString = [] (edict_t *edictStartSearchAfter, const char *field, const char *value) {
|
||||||
// round starts in counter-strike 1.5
|
// round starts in counter-strike 1.5
|
||||||
if ((game.is (GAME_LEGACY)) && strcmp (value, "info_map_parameters") == 0) {
|
if ((game.is (GameFlags::Legacy)) && strcmp (value, "info_map_parameters") == 0) {
|
||||||
bots.initRound ();
|
bots.initRound ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META_VALUE (MRES_IGNORED, static_cast <edict_t *> (nullptr));
|
RETURN_META_VALUE (MRES_IGNORED, static_cast <edict_t *> (nullptr));
|
||||||
}
|
}
|
||||||
return engfuncs.pfnFindEntityByString (edictStartSearchAfter, field, value);
|
return engfuncs.pfnFindEntityByString (edictStartSearchAfter, field, value);
|
||||||
|
|
@ -596,7 +607,7 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
|
|
||||||
util.attachSoundsToClients (entity, sample, volume);
|
util.attachSoundsToClients (entity, sample, volume);
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
engfuncs.pfnEmitSound (entity, channel, sample, volume, attenuation, flags, pitch);
|
engfuncs.pfnEmitSound (entity, channel, sample, volume, attenuation, flags, pitch);
|
||||||
|
|
@ -607,29 +618,26 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
|
|
||||||
game.beginMessage (ed, msgDest, msgType);
|
game.beginMessage (ed, msgDest, msgType);
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
engfuncs.pfnMessageBegin (msgDest, msgType, origin, ed);
|
engfuncs.pfnMessageBegin (msgDest, msgType, origin, ed);
|
||||||
};
|
};
|
||||||
|
|
||||||
functionTable->pfnMessageEnd = [] (void) {
|
functionTable->pfnMessageEnd = [] () {
|
||||||
game.resetMessages ();
|
game.resetMessages ();
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
engfuncs.pfnMessageEnd ();
|
engfuncs.pfnMessageEnd ();
|
||||||
|
|
||||||
// send latency fix
|
|
||||||
bots.sendDeathMsgFix ();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
functionTable->pfnWriteByte = [] (int value) {
|
functionTable->pfnWriteByte = [] (int value) {
|
||||||
// if this message is for a bot, call the client message function...
|
// if this message is for a bot, call the client message function...
|
||||||
game.processMessages ((void *) &value);
|
game.processMessages (reinterpret_cast <void *> (&value));
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
engfuncs.pfnWriteByte (value);
|
engfuncs.pfnWriteByte (value);
|
||||||
|
|
@ -637,9 +645,9 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
|
|
||||||
functionTable->pfnWriteChar = [] (int value) {
|
functionTable->pfnWriteChar = [] (int value) {
|
||||||
// if this message is for a bot, call the client message function...
|
// if this message is for a bot, call the client message function...
|
||||||
game.processMessages ((void *) &value);
|
game.processMessages (reinterpret_cast <void *> (&value));
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
engfuncs.pfnWriteChar (value);
|
engfuncs.pfnWriteChar (value);
|
||||||
|
|
@ -647,9 +655,9 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
|
|
||||||
functionTable->pfnWriteShort = [] (int value) {
|
functionTable->pfnWriteShort = [] (int value) {
|
||||||
// if this message is for a bot, call the client message function...
|
// if this message is for a bot, call the client message function...
|
||||||
game.processMessages ((void *) &value);
|
game.processMessages (reinterpret_cast <void *> (&value));
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
engfuncs.pfnWriteShort (value);
|
engfuncs.pfnWriteShort (value);
|
||||||
|
|
@ -657,9 +665,9 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
|
|
||||||
functionTable->pfnWriteLong = [] (int value) {
|
functionTable->pfnWriteLong = [] (int value) {
|
||||||
// if this message is for a bot, call the client message function...
|
// if this message is for a bot, call the client message function...
|
||||||
game.processMessages ((void *) &value);
|
game.processMessages (reinterpret_cast <void *> (&value));
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
engfuncs.pfnWriteLong (value);
|
engfuncs.pfnWriteLong (value);
|
||||||
|
|
@ -667,9 +675,9 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
|
|
||||||
functionTable->pfnWriteAngle = [] (float value) {
|
functionTable->pfnWriteAngle = [] (float value) {
|
||||||
// if this message is for a bot, call the client message function...
|
// if this message is for a bot, call the client message function...
|
||||||
game.processMessages ((void *) &value);
|
game.processMessages (reinterpret_cast <void *> (&value));
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
engfuncs.pfnWriteAngle (value);
|
engfuncs.pfnWriteAngle (value);
|
||||||
|
|
@ -677,9 +685,9 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
|
|
||||||
functionTable->pfnWriteCoord = [] (float value) {
|
functionTable->pfnWriteCoord = [] (float value) {
|
||||||
// if this message is for a bot, call the client message function...
|
// if this message is for a bot, call the client message function...
|
||||||
game.processMessages ((void *) &value);
|
game.processMessages (reinterpret_cast <void *> (&value));
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
engfuncs.pfnWriteCoord (value);
|
engfuncs.pfnWriteCoord (value);
|
||||||
|
|
@ -687,9 +695,9 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
|
|
||||||
functionTable->pfnWriteString = [] (const char *sz) {
|
functionTable->pfnWriteString = [] (const char *sz) {
|
||||||
// if this message is for a bot, call the client message function...
|
// if this message is for a bot, call the client message function...
|
||||||
game.processMessages ((void *) sz);
|
game.processMessages (reinterpret_cast <void *> (const_cast <char *> (sz)));
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
engfuncs.pfnWriteString (sz);
|
engfuncs.pfnWriteString (sz);
|
||||||
|
|
@ -697,9 +705,9 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
|
|
||||||
functionTable->pfnWriteEntity = [] (int value) {
|
functionTable->pfnWriteEntity = [] (int value) {
|
||||||
// if this message is for a bot, call the client message function...
|
// if this message is for a bot, call the client message function...
|
||||||
game.processMessages ((void *) &value);
|
game.processMessages (reinterpret_cast <void *> (&value));
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
engfuncs.pfnWriteEntity (value);
|
engfuncs.pfnWriteEntity (value);
|
||||||
|
|
@ -716,76 +724,76 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
// using pfnMessageBegin (), it will know what message ID number to send, and the engine will
|
// using pfnMessageBegin (), it will know what message ID number to send, and the engine will
|
||||||
// know what to do, only for non-metamod version
|
// know what to do, only for non-metamod version
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META_VALUE (MRES_IGNORED, 0);
|
RETURN_META_VALUE (MRES_IGNORED, 0);
|
||||||
}
|
}
|
||||||
int message = engfuncs.pfnRegUserMsg (name, size);
|
int message = engfuncs.pfnRegUserMsg (name, size);
|
||||||
|
|
||||||
if (strcmp (name, "VGUIMenu") == 0) {
|
if (strcmp (name, "VGUIMenu") == 0) {
|
||||||
game.setMessageId (NETMSG_VGUI, message);
|
game.setMessageId (NetMsg::VGUI, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "ShowMenu") == 0) {
|
else if (strcmp (name, "ShowMenu") == 0) {
|
||||||
game.setMessageId (NETMSG_SHOWMENU, message);
|
game.setMessageId (NetMsg::ShowMenu, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "WeaponList") == 0) {
|
else if (strcmp (name, "WeaponList") == 0) {
|
||||||
game.setMessageId (NETMSG_WEAPONLIST, message);
|
game.setMessageId (NetMsg::WeaponList, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "CurWeapon") == 0) {
|
else if (strcmp (name, "CurWeapon") == 0) {
|
||||||
game.setMessageId (NETMSG_CURWEAPON, message);
|
game.setMessageId (NetMsg::CurWeapon, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "AmmoX") == 0) {
|
else if (strcmp (name, "AmmoX") == 0) {
|
||||||
game.setMessageId (NETMSG_AMMOX, message);
|
game.setMessageId (NetMsg::AmmoX, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "AmmoPickup") == 0) {
|
else if (strcmp (name, "AmmoPickup") == 0) {
|
||||||
game.setMessageId (NETMSG_AMMOPICKUP, message);
|
game.setMessageId (NetMsg::AmmoPickup, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "Damage") == 0) {
|
else if (strcmp (name, "Damage") == 0) {
|
||||||
game.setMessageId (NETMSG_DAMAGE, message);
|
game.setMessageId (NetMsg::Damage, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "Money") == 0) {
|
else if (strcmp (name, "Money") == 0) {
|
||||||
game.setMessageId (NETMSG_MONEY, message);
|
game.setMessageId (NetMsg::Money, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "StatusIcon") == 0) {
|
else if (strcmp (name, "StatusIcon") == 0) {
|
||||||
game.setMessageId (NETMSG_STATUSICON, message);
|
game.setMessageId (NetMsg::StatusIcon, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "DeathMsg") == 0) {
|
else if (strcmp (name, "DeathMsg") == 0) {
|
||||||
game.setMessageId (NETMSG_DEATH, message);
|
game.setMessageId (NetMsg::DeathMsg, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "ScreenFade") == 0) {
|
else if (strcmp (name, "ScreenFade") == 0) {
|
||||||
game.setMessageId (NETMSG_SCREENFADE, message);
|
game.setMessageId (NetMsg::ScreenFade, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "HLTV") == 0) {
|
else if (strcmp (name, "HLTV") == 0) {
|
||||||
game.setMessageId (NETMSG_HLTV, message);
|
game.setMessageId (NetMsg::HLTV, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "TextMsg") == 0) {
|
else if (strcmp (name, "TextMsg") == 0) {
|
||||||
game.setMessageId (NETMSG_TEXTMSG, message);
|
game.setMessageId (NetMsg::TextMsg, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "TeamInfo") == 0) {
|
else if (strcmp (name, "TeamInfo") == 0) {
|
||||||
game.setMessageId (NETMSG_TEAMINFO, message);
|
game.setMessageId (NetMsg::TeamInfo, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "BarTime") == 0) {
|
else if (strcmp (name, "BarTime") == 0) {
|
||||||
game.setMessageId (NETMSG_BARTIME, message);
|
game.setMessageId (NetMsg::BarTime, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "SendAudio") == 0) {
|
else if (strcmp (name, "SendAudio") == 0) {
|
||||||
game.setMessageId (NETMSG_SENDAUDIO, message);
|
game.setMessageId (NetMsg::SendAudio, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "SayText") == 0) {
|
else if (strcmp (name, "SayText") == 0) {
|
||||||
game.setMessageId (NETMSG_SAYTEXT, message);
|
game.setMessageId (NetMsg::SayText, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "BotVoice") == 0) {
|
else if (strcmp (name, "BotVoice") == 0) {
|
||||||
game.setMessageId (NETMSG_BOTVOICE, message);
|
game.setMessageId (NetMsg::BotVoice, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "NVGToggle") == 0) {
|
else if (strcmp (name, "NVGToggle") == 0) {
|
||||||
game.setMessageId (NETMSG_NVGTOGGLE, message);
|
game.setMessageId (NetMsg::NVGToggle, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "FlashBat") == 0) {
|
else if (strcmp (name, "FlashBat") == 0) {
|
||||||
game.setMessageId (NETMSG_FLASHBAT, message);
|
game.setMessageId (NetMsg::FlashBat, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "Flashlight") == 0) {
|
else if (strcmp (name, "Flashlight") == 0) {
|
||||||
game.setMessageId (NETMSG_FLASHLIGHT, message);
|
game.setMessageId (NetMsg::Fashlight, message);
|
||||||
}
|
}
|
||||||
else if (strcmp (name, "ItemStatus") == 0) {
|
else if (strcmp (name, "ItemStatus") == 0) {
|
||||||
game.setMessageId (NETMSG_ITEMSTATUS, message);
|
game.setMessageId (NetMsg::ItemStatus, message);
|
||||||
}
|
}
|
||||||
return message;
|
return message;
|
||||||
};
|
};
|
||||||
|
|
@ -798,19 +806,19 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
// we know, right ? But since stupidity rules this world, we do a preventive check :)
|
// we know, right ? But since stupidity rules this world, we do a preventive check :)
|
||||||
|
|
||||||
if (util.isFakeClient (ent)) {
|
if (util.isFakeClient (ent)) {
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_SUPERCEDE);
|
RETURN_META (MRES_SUPERCEDE);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
engfuncs.pfnClientPrintf (ent, printType, message);
|
engfuncs.pfnClientPrintf (ent, printType, message);
|
||||||
};
|
};
|
||||||
|
|
||||||
functionTable->pfnCmd_Args = [] (void) {
|
functionTable->pfnCmd_Args = [] () {
|
||||||
// this function returns a pointer to the whole current client command string. Since bots
|
// this function returns a pointer to the whole current client command string. Since bots
|
||||||
// have no client DLL and we may want a bot to execute a client command, we had to implement
|
// have no client DLL and we may want a bot to execute a client command, we had to implement
|
||||||
// a argv string in the bot DLL for holding the bots' commands, and also keep track of the
|
// a argv string in the bot DLL for holding the bots' commands, and also keep track of the
|
||||||
|
|
@ -820,13 +828,13 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
|
|
||||||
// is this a bot issuing that client command?
|
// is this a bot issuing that client command?
|
||||||
if (game.isBotCmd ()) {
|
if (game.isBotCmd ()) {
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META_VALUE (MRES_SUPERCEDE, game.botArgs ());
|
RETURN_META_VALUE (MRES_SUPERCEDE, game.botArgs ());
|
||||||
}
|
}
|
||||||
return game.botArgs (); // else return the whole bot client command string we know
|
return game.botArgs (); // else return the whole bot client command string we know
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META_VALUE (MRES_IGNORED, static_cast <const char *> (nullptr));
|
RETURN_META_VALUE (MRES_IGNORED, static_cast <const char *> (nullptr));
|
||||||
}
|
}
|
||||||
return engfuncs.pfnCmd_Args (); // ask the client command string to the engine
|
return engfuncs.pfnCmd_Args (); // ask the client command string to the engine
|
||||||
|
|
@ -842,19 +850,19 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
|
|
||||||
// is this a bot issuing that client command?
|
// is this a bot issuing that client command?
|
||||||
if (game.isBotCmd ()) {
|
if (game.isBotCmd ()) {
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META_VALUE (MRES_SUPERCEDE, game.botArgv (argc));
|
RETURN_META_VALUE (MRES_SUPERCEDE, game.botArgv (argc));
|
||||||
}
|
}
|
||||||
return game.botArgv (argc); // if so, then return the wanted argument we know
|
return game.botArgv (argc); // if so, then return the wanted argument we know
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META_VALUE (MRES_IGNORED, static_cast <const char *> (nullptr));
|
RETURN_META_VALUE (MRES_IGNORED, static_cast <const char *> (nullptr));
|
||||||
}
|
}
|
||||||
return engfuncs.pfnCmd_Argv (argc); // ask the argument number "argc" to the engine
|
return engfuncs.pfnCmd_Argv (argc); // ask the argument number "argc" to the engine
|
||||||
};
|
};
|
||||||
|
|
||||||
functionTable->pfnCmd_Argc = [] (void) {
|
functionTable->pfnCmd_Argc = [] () {
|
||||||
// this function returns the number of arguments the current client command string has. Since
|
// this function returns the number of arguments the current client command string has. Since
|
||||||
// bots have no client DLL and we may want a bot to execute a client command, we had to
|
// bots have no client DLL and we may want a bot to execute a client command, we had to
|
||||||
// implement a argv string in the bot DLL for holding the bots' commands, and also keep
|
// implement a argv string in the bot DLL for holding the bots' commands, and also keep
|
||||||
|
|
@ -864,61 +872,52 @@ SHARED_LIBRARAY_EXPORT int GetEngineFunctions (enginefuncs_t *functionTable, int
|
||||||
|
|
||||||
// is this a bot issuing that client command?
|
// is this a bot issuing that client command?
|
||||||
if (game.isBotCmd ()) {
|
if (game.isBotCmd ()) {
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META_VALUE (MRES_SUPERCEDE, game.botArgc ());
|
RETURN_META_VALUE (MRES_SUPERCEDE, game.botArgc ());
|
||||||
}
|
}
|
||||||
return game.botArgc (); // if so, then return the argument count we know
|
return game.botArgc (); // if so, then return the argument count we know
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META_VALUE (MRES_IGNORED, 0);
|
RETURN_META_VALUE (MRES_IGNORED, 0);
|
||||||
}
|
}
|
||||||
return engfuncs.pfnCmd_Argc (); // ask the engine how many arguments there are
|
return engfuncs.pfnCmd_Argc (); // ask the engine how many arguments there are
|
||||||
};
|
};
|
||||||
|
|
||||||
functionTable->pfnSetClientMaxspeed = [] (const edict_t *ent, float newMaxspeed) {
|
functionTable->pfnSetClientMaxspeed = [] (const edict_t *ent, float newMaxspeed) {
|
||||||
Bot *bot = bots.getBot (const_cast <edict_t *> (ent));
|
auto bot = bots[const_cast <edict_t *> (ent)];
|
||||||
|
|
||||||
// check wether it's not a bot
|
// check wether it's not a bot
|
||||||
if (bot != nullptr) {
|
if (bot != nullptr) {
|
||||||
bot->pev->maxspeed = newMaxspeed;
|
bot->pev->maxspeed = newMaxspeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game.is (GAME_METAMOD)) {
|
if (game.is (GameFlags::Metamod)) {
|
||||||
RETURN_META (MRES_IGNORED);
|
RETURN_META (MRES_IGNORED);
|
||||||
}
|
}
|
||||||
engfuncs.pfnSetClientMaxspeed (ent, newMaxspeed);
|
engfuncs.pfnSetClientMaxspeed (ent, newMaxspeed);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
functionTable->pfnClientCommand = variadic::clientCommand;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHARED_LIBRARAY_EXPORT int GetEngineFunctions_Post (enginefuncs_t *functionTable, int *) {
|
CR_EXPORT int Server_GetBlendingInterface (int version, void **ppinterface, void *pstudio, float (*rotationmatrix)[3][4], float (*bonetransform)[128][3][4]) {
|
||||||
|
|
||||||
memset (functionTable, 0, sizeof (enginefuncs_t));
|
|
||||||
|
|
||||||
functionTable->pfnMessageEnd = [] (void) {
|
|
||||||
// send latency fix
|
|
||||||
bots.sendDeathMsgFix ();
|
|
||||||
|
|
||||||
RETURN_META (MRES_IGNORED);
|
|
||||||
};
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
SHARED_LIBRARAY_EXPORT int Server_GetBlendingInterface (int version, void **ppinterface, void *pstudio, float (*rotationmatrix)[3][4], float (*bonetransform)[128][3][4]) {
|
|
||||||
// this function synchronizes the studio model animation blending interface (i.e, what parts
|
// this function synchronizes the studio model animation blending interface (i.e, what parts
|
||||||
// of the body move, which bones, which hitboxes and how) between the server and the game DLL.
|
// of the body move, which bones, which hitboxes and how) between the server and the game DLL.
|
||||||
// some MODs can be using a different hitbox scheme than the standard one.
|
// some MODs can be using a different hitbox scheme than the standard one.
|
||||||
|
|
||||||
auto api_GetBlendingInterface = game.getLib ().resolve <int (*) (int, void **, void *, float(*)[3][4], float(*)[128][3][4])> ("Server_GetBlendingInterface");
|
auto api_GetBlendingInterface = game.lib ().resolve <int (*) (int, void **, void *, float(*)[3][4], float(*)[128][3][4])> (__FUNCTION__);
|
||||||
|
|
||||||
if (api_GetBlendingInterface == nullptr) {
|
if (!api_GetBlendingInterface) {
|
||||||
|
logger.error ("Could not resolve symbol \"%s\" in the game dll. Continuing...", __FUNCTION__);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
return api_GetBlendingInterface (version, ppinterface, pstudio, rotationmatrix, bonetransform);
|
return api_GetBlendingInterface (version, ppinterface, pstudio, rotationmatrix, bonetransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
SHARED_LIBRARAY_EXPORT int Meta_Query (char *, plugin_info_t **pPlugInfo, mutil_funcs_t *pMetaUtilFuncs) {
|
CR_EXPORT int Meta_Query (char *, plugin_info_t **pPlugInfo, mutil_funcs_t *pMetaUtilFuncs) {
|
||||||
// this function is the first function ever called by metamod in the plugin DLL. Its purpose
|
// this function is the first function ever called by metamod in the plugin DLL. Its purpose
|
||||||
// is for metamod to retrieve basic information about the plugin, such as its meta-interface
|
// is for metamod to retrieve basic information about the plugin, such as its meta-interface
|
||||||
// version, for ensuring compatibility with the current version of the running metamod.
|
// version, for ensuring compatibility with the current version of the running metamod.
|
||||||
|
|
@ -929,7 +928,7 @@ SHARED_LIBRARAY_EXPORT int Meta_Query (char *, plugin_info_t **pPlugInfo, mutil_
|
||||||
return TRUE; // tell metamod this plugin looks safe
|
return TRUE; // tell metamod this plugin looks safe
|
||||||
}
|
}
|
||||||
|
|
||||||
SHARED_LIBRARAY_EXPORT int Meta_Attach (PLUG_LOADTIME, metamod_funcs_t *functionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs) {
|
CR_EXPORT int Meta_Attach (PLUG_LOADTIME, metamod_funcs_t *functionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs) {
|
||||||
// this function is called when metamod attempts to load the plugin. Since it's the place
|
// this function is called when metamod attempts to load the plugin. Since it's the place
|
||||||
// where we can tell if the plugin will be allowed to run or not, we wait until here to make
|
// where we can tell if the plugin will be allowed to run or not, we wait until here to make
|
||||||
// our initialization stuff, like registering CVARs and dedicated server commands.
|
// our initialization stuff, like registering CVARs and dedicated server commands.
|
||||||
|
|
@ -943,7 +942,7 @@ SHARED_LIBRARAY_EXPORT int Meta_Attach (PLUG_LOADTIME, metamod_funcs_t *function
|
||||||
nullptr, // pfnGetNewDLLFunctions ()
|
nullptr, // pfnGetNewDLLFunctions ()
|
||||||
nullptr, // pfnGetNewDLLFunctions_Post ()
|
nullptr, // pfnGetNewDLLFunctions_Post ()
|
||||||
GetEngineFunctions, // pfnGetEngineFunctions ()
|
GetEngineFunctions, // pfnGetEngineFunctions ()
|
||||||
GetEngineFunctions_Post, // pfnGetEngineFunctions_Post ()
|
nullptr, // pfnGetEngineFunctions_Post ()
|
||||||
};
|
};
|
||||||
|
|
||||||
// keep track of the pointers to engine function tables metamod gives us
|
// keep track of the pointers to engine function tables metamod gives us
|
||||||
|
|
@ -954,23 +953,44 @@ SHARED_LIBRARAY_EXPORT int Meta_Attach (PLUG_LOADTIME, metamod_funcs_t *function
|
||||||
return TRUE; // returning true enables metamod to attach this plugin
|
return TRUE; // returning true enables metamod to attach this plugin
|
||||||
}
|
}
|
||||||
|
|
||||||
SHARED_LIBRARAY_EXPORT int Meta_Detach (PLUG_LOADTIME, PL_UNLOAD_REASON) {
|
CR_EXPORT int Meta_Detach (PLUG_LOADTIME, PL_UNLOAD_REASON) {
|
||||||
// this function is called when metamod unloads the plugin. A basic check is made in order
|
// this function is called when metamod unloads the plugin. A basic check is made in order
|
||||||
// to prevent unloading the plugin if its processing should not be interrupted.
|
// to prevent unloading the plugin if its processing should not be interrupted.
|
||||||
|
|
||||||
bots.kickEveryone (true); // kick all bots off this server
|
bots.kickEveryone (true); // kick all bots off this server
|
||||||
waypoints.init ();
|
|
||||||
|
// save collected experience on shutdown
|
||||||
|
graph.savePractice ();
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHARED_LIBRARAY_EXPORT void Meta_Init (void) {
|
CR_EXPORT void Meta_Init () {
|
||||||
// this function is called by metamod, before any other interface functions. Purpose of this
|
// this function is called by metamod, before any other interface functions. Purpose of this
|
||||||
// function to give plugin a chance to determine is plugin running under metamod or not.
|
// function to give plugin a chance to determine is plugin running under metamod or not.
|
||||||
|
|
||||||
game.addGameFlag (GAME_METAMOD);
|
game.addGameFlag (GameFlags::Metamod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// games GiveFnptrsToDll is a bit tricky
|
||||||
|
#if defined(CR_WINDOWS)
|
||||||
|
# if defined(CR_CXX_MSVC) || defined (CR_CXX_MSVC)
|
||||||
|
# if defined (CR_ARCH_X86)
|
||||||
|
# pragma comment(linker, "/EXPORT:GiveFnptrsToDll=_GiveFnptrsToDll@8,@1")
|
||||||
|
# endif
|
||||||
|
# pragma comment(linker, "/SECTION:.data,RW")
|
||||||
|
# endif
|
||||||
|
# define DLL_STDCALL __stdcall
|
||||||
|
# if defined(CR_CXX_MSVC) && !defined(CR_ARCH_X64)
|
||||||
|
# define DLL_GIVEFNPTRSTODLL extern "C" void DLL_STDCALL
|
||||||
|
# elif defined(CR_CXX_CLANG) || defined(CR_ARCH_X64)
|
||||||
|
# define DLL_GIVEFNPTRSTODLL CR_EXPORT void DLL_STDCALL
|
||||||
|
# endif
|
||||||
|
#elif defined(CR_LINUX) || defined (CR_OSX) || defined (CR_ANDROID)
|
||||||
|
# define DLL_GIVEFNPTRSTODLL CR_EXPORT void
|
||||||
|
# define DLL_STDCALL
|
||||||
|
#endif
|
||||||
|
|
||||||
DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t *pGlobals) {
|
DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t *pGlobals) {
|
||||||
// this is the very first function that is called in the game DLL by the game. Its purpose
|
// this is the very first function that is called in the game DLL by the game. Its purpose
|
||||||
// is to set the functions interfacing up, by exchanging the functionTable function list
|
// is to set the functions interfacing up, by exchanging the functionTable function list
|
||||||
|
|
@ -990,30 +1010,22 @@ DLL_GIVEFNPTRSTODLL GiveFnptrsToDll (enginefuncs_t *functionTable, globalvars_t
|
||||||
if (game.postload ()) {
|
if (game.postload ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto api_GiveFnptrsToDll = game.getLib ().resolve <void (STD_CALL *) (enginefuncs_t *, globalvars_t *)> ("GiveFnptrsToDll");
|
auto api_GiveFnptrsToDll = game.lib ().resolve <void (DLL_STDCALL *) (enginefuncs_t *, globalvars_t *)> (__FUNCTION__);
|
||||||
|
|
||||||
assert (api_GiveFnptrsToDll != nullptr);
|
if (!api_GiveFnptrsToDll) {
|
||||||
|
logger.fatal ("Could not resolve symbol \"%s\" in the game dll.", __FUNCTION__);
|
||||||
|
}
|
||||||
GetEngineFunctions (functionTable, nullptr);
|
GetEngineFunctions (functionTable, nullptr);
|
||||||
|
|
||||||
// give the engine functions to the other DLL...
|
// give the engine functions to the other DLL...
|
||||||
api_GiveFnptrsToDll (functionTable, pGlobals);
|
if (api_GiveFnptrsToDll) {
|
||||||
}
|
api_GiveFnptrsToDll (functionTable, pGlobals);
|
||||||
|
|
||||||
DLL_ENTRYPOINT {
|
|
||||||
// dynamic library entry point, can be used for uninitialization stuff. NOT for initializing
|
|
||||||
// anything because if you ever attempt to wander outside the scope of this function on a
|
|
||||||
// DLL attach, LoadLibrary() will simply fail. And you can't do I/Os here either.
|
|
||||||
|
|
||||||
// dynamic library detaching ??
|
|
||||||
if (DLL_DETACHING) {
|
|
||||||
waypoints.init (); // free everything that's freeable
|
|
||||||
}
|
}
|
||||||
DLL_RETENTRY; // the return data type is OS specific too
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void helper_LinkEntity (EntityFunction &addr, const char *name, entvars_t *pev) {
|
void helper_LinkEntity (EntityFunction &addr, const char *name, entvars_t *pev) {
|
||||||
if (addr == nullptr) {
|
if (addr == nullptr) {
|
||||||
addr = game.getLib ().resolve <EntityFunction> (name);
|
addr = game.lib ().resolve <EntityFunction> (name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addr == nullptr) {
|
if (addr == nullptr) {
|
||||||
|
|
@ -1022,10 +1034,10 @@ void helper_LinkEntity (EntityFunction &addr, const char *name, entvars_t *pev)
|
||||||
addr (pev);
|
addr (pev);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LINK_ENTITY(entityName) \
|
#define LINK_ENTITY(entityName) \
|
||||||
SHARED_LIBRARAY_EXPORT void entityName (entvars_t *pev) { \
|
CR_EXPORT void entityName (entvars_t *pev) { \
|
||||||
static EntityFunction addr; \
|
static EntityFunction addr; \
|
||||||
helper_LinkEntity (addr, #entityName, pev); \
|
helper_LinkEntity (addr, #entityName, pev); \
|
||||||
}
|
}
|
||||||
|
|
||||||
// entities in counter-strike...
|
// entities in counter-strike...
|
||||||
|
|
|
||||||
1799
source/manager.cpp
1799
source/manager.cpp
File diff suppressed because it is too large
Load diff
1362
source/navigate.cpp
1362
source/navigate.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
ConVar yb_display_welcome_text ("yb_display_welcome_text", "1");
|
ConVar yb_display_welcome_text ("yb_display_welcome_text", "1");
|
||||||
|
|
||||||
BotUtils::BotUtils (void) {
|
BotUtils::BotUtils () {
|
||||||
m_needToSendWelcome = false;
|
m_needToSendWelcome = false;
|
||||||
m_welcomeReceiveTime = 0.0f;
|
m_welcomeReceiveTime = 0.0f;
|
||||||
|
|
||||||
|
|
@ -32,47 +32,30 @@ BotUtils::BotUtils (void) {
|
||||||
m_sentences.push ("attention, expect experimental armed hostile presence");
|
m_sentences.push ("attention, expect experimental armed hostile presence");
|
||||||
m_sentences.push ("warning, medical attention required");
|
m_sentences.push ("warning, medical attention required");
|
||||||
|
|
||||||
m_tags.push ({ "[[", "]]" });
|
m_tags.emplace ("[[", "]]");
|
||||||
m_tags.push ({ "-=", "=-" });
|
m_tags.emplace ("-=", "=-");
|
||||||
m_tags.push ({ "-[", "]-" });
|
m_tags.emplace ("-[", "]-");
|
||||||
m_tags.push ({ "-]", "[-" });
|
m_tags.emplace ("-]", "[-");
|
||||||
m_tags.push ({ "-}", "{-" });
|
m_tags.emplace ("-}", "{-");
|
||||||
m_tags.push ({ "-{", "}-" });
|
m_tags.emplace ("-{", "}-");
|
||||||
m_tags.push ({ "<[", "]>" });
|
m_tags.emplace ("<[", "]>");
|
||||||
m_tags.push ({ "<]", "[>" });
|
m_tags.emplace ("<]", "[>");
|
||||||
m_tags.push ({ "[-", "-]" });
|
m_tags.emplace ("[-", "-]");
|
||||||
m_tags.push ({ "]-", "-[" });
|
m_tags.emplace ("]-", "-[");
|
||||||
m_tags.push ({ "{-", "-}" });
|
m_tags.emplace ("{-", "-}");
|
||||||
m_tags.push ({ "}-", "-{" });
|
m_tags.emplace ("}-", "-{");
|
||||||
m_tags.push ({ "[", "]" });
|
m_tags.emplace ("[", "]");
|
||||||
m_tags.push ({ "{", "}" });
|
m_tags.emplace ("{", "}");
|
||||||
m_tags.push ({ "<", "[" });
|
m_tags.emplace ("<", "[");
|
||||||
m_tags.push ({ ">", "<" });
|
m_tags.emplace (">", "<");
|
||||||
m_tags.push ({ "-", "-" });
|
m_tags.emplace ("-", "-");
|
||||||
m_tags.push ({ "|", "|" });
|
m_tags.emplace ("|", "|");
|
||||||
m_tags.push ({ "=", "=" });
|
m_tags.emplace ("=", "=");
|
||||||
m_tags.push ({ "+", "+" });
|
m_tags.emplace ("+", "+");
|
||||||
m_tags.push ({ "(", ")" });
|
m_tags.emplace ("(", ")");
|
||||||
m_tags.push ({ ")", "(" });
|
m_tags.emplace (")", "(");
|
||||||
|
|
||||||
m_clients.resize (MAX_ENGINE_PLAYERS + 1);
|
m_clients.resize (kGameMaxPlayers + 1);
|
||||||
}
|
|
||||||
|
|
||||||
const char *BotUtils::format (const char *format, ...) {
|
|
||||||
static char strBuffer[2][MAX_PRINT_BUFFER];
|
|
||||||
static int rotator = 0;
|
|
||||||
|
|
||||||
if (format == nullptr) {
|
|
||||||
return strBuffer[rotator];
|
|
||||||
}
|
|
||||||
static char *ptr = strBuffer[rotator ^= 1];
|
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
va_start (ap, format);
|
|
||||||
vsnprintf (ptr, MAX_PRINT_BUFFER - 1, format, ap);
|
|
||||||
va_end (ap);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BotUtils::isAlive (edict_t *ent) {
|
bool BotUtils::isAlive (edict_t *ent) {
|
||||||
|
|
@ -90,7 +73,7 @@ float BotUtils::getShootingCone (edict_t *ent, const Vector &position) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BotUtils::isInViewCone (const Vector &origin, edict_t *ent) {
|
bool BotUtils::isInViewCone (const Vector &origin, edict_t *ent) {
|
||||||
return getShootingCone (ent, origin) >= cr::cosf (cr::deg2rad ((ent->v.fov > 0 ? ent->v.fov : 90.0f) * 0.5f));
|
return getShootingCone (ent, origin) >= cr::cosf (cr::degreesToRadians ((ent->v.fov > 0 ? ent->v.fov : 90.0f) * 0.5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BotUtils::isVisible (const Vector &origin, edict_t *ent) {
|
bool BotUtils::isVisible (const Vector &origin, edict_t *ent) {
|
||||||
|
|
@ -98,7 +81,7 @@ bool BotUtils::isVisible (const Vector &origin, edict_t *ent) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
TraceResult tr;
|
TraceResult tr;
|
||||||
game.testLine (ent->v.origin + ent->v.view_ofs, origin, TRACE_IGNORE_EVERYTHING, ent, &tr);
|
game.testLine (ent->v.origin + ent->v.view_ofs, origin, TraceIgnore::Everything, ent, &tr);
|
||||||
|
|
||||||
if (tr.flFraction != 1.0f) {
|
if (tr.flFraction != 1.0f) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -109,13 +92,10 @@ bool BotUtils::isVisible (const Vector &origin, edict_t *ent) {
|
||||||
void BotUtils::traceDecals (entvars_t *pev, TraceResult *trace, int logotypeIndex) {
|
void BotUtils::traceDecals (entvars_t *pev, TraceResult *trace, int logotypeIndex) {
|
||||||
// this function draw spraypaint depending on the tracing results.
|
// this function draw spraypaint depending on the tracing results.
|
||||||
|
|
||||||
static StringArray logotypes;
|
auto logo = conf.getRandomLogoName (logotypeIndex);
|
||||||
|
|
||||||
if (logotypes.empty ()) {
|
|
||||||
logotypes = String ("{biohaz;{graf003;{graf004;{graf005;{lambda06;{target;{hand1;{spit2;{bloodhand6;{foot_l;{foot_r").split (";");
|
|
||||||
}
|
|
||||||
int entityIndex = -1, message = TE_DECAL;
|
int entityIndex = -1, message = TE_DECAL;
|
||||||
int decalIndex = engfuncs.pfnDecalIndex (logotypes[logotypeIndex].chars ());
|
int decalIndex = engfuncs.pfnDecalIndex (logo.chars ());
|
||||||
|
|
||||||
if (decalIndex < 0) {
|
if (decalIndex < 0) {
|
||||||
decalIndex = engfuncs.pfnDecalIndex ("{lambda06");
|
decalIndex = engfuncs.pfnDecalIndex ("{lambda06");
|
||||||
|
|
@ -151,7 +131,7 @@ void BotUtils::traceDecals (entvars_t *pev, TraceResult *trace, int logotypeInde
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logotypes[logotypeIndex].contains ("{")) {
|
if (logo.startsWith ("{")) {
|
||||||
MessageWriter (MSG_BROADCAST, SVC_TEMPENTITY)
|
MessageWriter (MSG_BROADCAST, SVC_TEMPENTITY)
|
||||||
.writeByte (TE_PLAYERDECAL)
|
.writeByte (TE_PLAYERDECAL)
|
||||||
.writeByte (game.indexOfEntity (pev->pContainingEntity))
|
.writeByte (game.indexOfEntity (pev->pContainingEntity))
|
||||||
|
|
@ -187,14 +167,14 @@ bool BotUtils::isPlayer (edict_t *ent) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ent->v.flags & (FL_CLIENT | FL_FAKECLIENT)) || bots.getBot (ent) != nullptr) {
|
if ((ent->v.flags & (FL_CLIENT | FL_FAKECLIENT)) || bots[ent] != nullptr) {
|
||||||
return !isEmptyStr (STRING (ent->v.netname));
|
return !isEmptyStr (STRING (ent->v.netname));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BotUtils::isPlayerVIP (edict_t *ent) {
|
bool BotUtils::isPlayerVIP (edict_t *ent) {
|
||||||
if (!game.mapIs (MAP_AS)) {
|
if (!game.mapIs (MapFlags::Assassination)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,14 +185,14 @@ bool BotUtils::isPlayerVIP (edict_t *ent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BotUtils::isFakeClient (edict_t *ent) {
|
bool BotUtils::isFakeClient (edict_t *ent) {
|
||||||
if (bots.getBot (ent) != nullptr || (!game.isNullEntity (ent) && (ent->v.flags & FL_FAKECLIENT))) {
|
if (bots[ent] != nullptr || (!game.isNullEntity (ent) && (ent->v.flags & FL_FAKECLIENT))) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BotUtils::openConfig (const char *fileName, const char *errorIfNotExists, MemFile *outFile, bool languageDependant /*= false*/) {
|
bool BotUtils::openConfig (const char *fileName, const char *errorIfNotExists, MemFile *outFile, bool languageDependant /*= false*/) {
|
||||||
if (outFile->isValid ()) {
|
if (*outFile) {
|
||||||
outFile->close ();
|
outFile->close ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,165 +205,75 @@ bool BotUtils::openConfig (const char *fileName, const char *errorIfNotExists, M
|
||||||
if (strcmp (fileName, "lang.cfg") == 0 && strcmp (yb_language.str (), "en") == 0) {
|
if (strcmp (fileName, "lang.cfg") == 0 && strcmp (yb_language.str (), "en") == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const char *langConfig = format ("%s/lang/%s_%s", configDir, yb_language.str (), fileName);
|
auto langConfig = strings.format ("%s/lang/%s_%s", configDir, yb_language.str (), fileName);
|
||||||
|
|
||||||
// check file existence
|
|
||||||
int size = 0;
|
|
||||||
uint8 *buffer = nullptr;
|
|
||||||
|
|
||||||
// check is file is exists for this language
|
// check is file is exists for this language
|
||||||
if ((buffer = MemoryLoader::ref ().load (langConfig, &size)) != nullptr) {
|
if (!outFile->open (langConfig)) {
|
||||||
MemoryLoader::ref ().unload (buffer);
|
outFile->open (strings.format ("%s/lang/en_%s", configDir, fileName));
|
||||||
|
|
||||||
// unload and reopen file using MemoryFile
|
|
||||||
outFile->open (langConfig);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
outFile->open (format ("%s/lang/en_%s", configDir, fileName));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
outFile->open (format ("%s/%s", configDir, fileName));
|
outFile->open (strings.format ("%s/%s", configDir, fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!outFile->isValid ()) {
|
if (!*outFile) {
|
||||||
logEntry (true, LL_ERROR, errorIfNotExists);
|
logger.error (errorIfNotExists);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotUtils::checkWelcome (void) {
|
void BotUtils::checkWelcome () {
|
||||||
// the purpose of this function, is to send quick welcome message, to the listenserver entity.
|
// the purpose of this function, is to send quick welcome message, to the listenserver entity.
|
||||||
|
|
||||||
if (game.isDedicated () || !yb_display_welcome_text.boolean () || !m_needToSendWelcome) {
|
if (game.isDedicated () || !yb_display_welcome_text.bool_ () || !m_needToSendWelcome) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_welcomeReceiveTime = 0.0f;
|
m_welcomeReceiveTime = 0.0f;
|
||||||
|
|
||||||
if (game.is (GAME_LEGACY)) {
|
|
||||||
m_needToSendWelcome = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
bool needToSendMsg = (waypoints.length () > 0 ? m_needToSendWelcome : true);
|
|
||||||
|
|
||||||
if (isAlive (game.getLocalEntity ()) && m_welcomeReceiveTime < 1.0 && needToSendMsg) {
|
bool needToSendMsg = (graph.length () > 0 ? m_needToSendWelcome : true);
|
||||||
|
auto receiveEntity = game.getLocalEntity ();
|
||||||
|
|
||||||
|
if (isAlive (receiveEntity) && m_welcomeReceiveTime < 1.0 && needToSendMsg) {
|
||||||
m_welcomeReceiveTime = game.timebase () + 4.0f; // receive welcome message in four seconds after game has commencing
|
m_welcomeReceiveTime = game.timebase () + 4.0f; // receive welcome message in four seconds after game has commencing
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_welcomeReceiveTime > 0.0f && needToSendMsg) {
|
|
||||||
if (!game.is (GAME_MOBILITY | GAME_XASH_ENGINE)) {
|
|
||||||
game.execCmd ("speak \"%s\"", m_sentences.random ().chars ());
|
|
||||||
}
|
|
||||||
game.chatPrint ("----- %s v%s (Build: %u), {%s}, (c) %s, by %s (%s)-----", PRODUCT_SHORT_NAME, PRODUCT_VERSION, buildNumber (), PRODUCT_DATE, PRODUCT_END_YEAR, PRODUCT_AUTHOR, PRODUCT_URL);
|
|
||||||
|
|
||||||
MessageWriter (MSG_ONE, SVC_TEMPENTITY, Vector::null (), game.getLocalEntity ())
|
if (m_welcomeReceiveTime > 0.0f && needToSendMsg) {
|
||||||
|
if (!game.is (GameFlags::Mobility | GameFlags::Xash3D)) {
|
||||||
|
game.serverCommand ("speak \"%s\"", m_sentences.random ().chars ());
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageWriter (MSG_ONE, game.getMessageId (NetMsg::TextMsg), nullvec, receiveEntity)
|
||||||
|
.writeByte (HUD_PRINTTALK)
|
||||||
|
.writeString (strings.format ("----- %s v%s (Build: %u), {%s}, (c) %s, by %s (%s)-----", PRODUCT_SHORT_NAME, PRODUCT_VERSION, buildNumber (), PRODUCT_DATE, PRODUCT_END_YEAR, PRODUCT_AUTHOR, PRODUCT_URL));
|
||||||
|
|
||||||
|
MessageWriter (MSG_ONE, SVC_TEMPENTITY, nullvec, receiveEntity)
|
||||||
.writeByte (TE_TEXTMESSAGE)
|
.writeByte (TE_TEXTMESSAGE)
|
||||||
.writeByte (1)
|
.writeByte (1)
|
||||||
.writeShort (MessageWriter::fs16 (-1, 1 << 13))
|
.writeShort (MessageWriter::fs16 (-1.0f, 13.0f))
|
||||||
.writeShort (MessageWriter::fs16 (-1, 1 << 13))
|
.writeShort (MessageWriter::fs16 (-1.0f, 13.0f))
|
||||||
.writeByte (2)
|
.writeByte (2)
|
||||||
.writeByte (rng.getInt (33, 255))
|
.writeByte (rg.int_ (33, 255))
|
||||||
.writeByte (rng.getInt (33, 255))
|
.writeByte (rg.int_ (33, 255))
|
||||||
.writeByte (rng.getInt (33, 255))
|
.writeByte (rg.int_ (33, 255))
|
||||||
.writeByte (0)
|
.writeByte (0)
|
||||||
.writeByte (rng.getInt (230, 255))
|
.writeByte (rg.int_ (230, 255))
|
||||||
.writeByte (rng.getInt (230, 255))
|
.writeByte (rg.int_ (230, 255))
|
||||||
.writeByte (rng.getInt (230, 255))
|
.writeByte (rg.int_ (230, 255))
|
||||||
.writeByte (200)
|
.writeByte (200)
|
||||||
.writeShort (MessageWriter::fu16 (0.0078125f, 1 << 8))
|
.writeShort (MessageWriter::fu16 (0.0078125f, 8.0f))
|
||||||
.writeShort (MessageWriter::fu16 (2.0f, 1 << 8))
|
.writeShort (MessageWriter::fu16 (2.0f, 8.0f))
|
||||||
.writeShort (MessageWriter::fu16 (6.0f, 1 << 8))
|
.writeShort (MessageWriter::fu16 (6.0f, 8.0f))
|
||||||
.writeShort (MessageWriter::fu16 (0.1f, 1 << 8))
|
.writeShort (MessageWriter::fu16 (0.1f, 8.0f))
|
||||||
.writeString (format ("\nServer is running %s v%s (Build: %u)\nDeveloped by %s\n\n%s", PRODUCT_SHORT_NAME, PRODUCT_VERSION, buildNumber (), PRODUCT_AUTHOR, waypoints.getAuthor ()));
|
.writeString (strings.format ("\nServer is running %s v%s (Build: %u)\nDeveloped by %s\n\n%s", PRODUCT_SHORT_NAME, PRODUCT_VERSION, buildNumber (), PRODUCT_AUTHOR, graph.getAuthor ()));
|
||||||
|
|
||||||
m_welcomeReceiveTime = 0.0f;
|
m_welcomeReceiveTime = 0.0f;
|
||||||
m_needToSendWelcome = false;
|
m_needToSendWelcome = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotUtils::logEntry (bool outputToConsole, int logLevel, const char *format, ...) {
|
|
||||||
// this function logs a message to the message log file root directory.
|
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
char buffer[MAX_PRINT_BUFFER] = { 0, }, levelString[32] = { 0, };
|
|
||||||
|
|
||||||
va_start (ap, format);
|
|
||||||
vsnprintf (buffer, cr::bufsize (buffer), format, ap);
|
|
||||||
va_end (ap);
|
|
||||||
|
|
||||||
switch (logLevel) {
|
|
||||||
case LL_DEFAULT:
|
|
||||||
strcpy (levelString, "LOG: ");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LL_WARNING:
|
|
||||||
strcpy (levelString, "WARN: ");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LL_ERROR:
|
|
||||||
strcpy (levelString, "ERROR: ");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LL_FATAL:
|
|
||||||
strcpy (levelString, "FATAL: ");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (outputToConsole) {
|
|
||||||
game.print ("%s%s", levelString, buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// now check if logging disabled
|
|
||||||
if (!(logLevel & LL_IGNORE)) {
|
|
||||||
extern ConVar yb_debug;
|
|
||||||
|
|
||||||
if (logLevel == LL_DEFAULT && yb_debug.integer () < 3) {
|
|
||||||
return; // no log, default logging is disabled
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logLevel == LL_WARNING && yb_debug.integer () < 2) {
|
|
||||||
return; // no log, warning logging is disabled
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logLevel == LL_ERROR && yb_debug.integer () < 1) {
|
|
||||||
return; // no log, error logging is disabled
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// open file in a standard stream
|
|
||||||
File fp ("yapb.txt", "at");
|
|
||||||
|
|
||||||
// check if we got a valid handle
|
|
||||||
if (!fp.isValid ()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
time_t tickTime = time (&tickTime);
|
|
||||||
tm *time = localtime (&tickTime);
|
|
||||||
|
|
||||||
fp.writeFormat ("%02d:%02d:%02d --> %s%s\n", time->tm_hour, time->tm_min, time->tm_sec, levelString, buffer);
|
|
||||||
fp.close ();
|
|
||||||
|
|
||||||
if (logLevel == LL_FATAL) {
|
|
||||||
bots.kickEveryone (true);
|
|
||||||
waypoints.init ();
|
|
||||||
|
|
||||||
#if defined(PLATFORM_WIN32)
|
|
||||||
DestroyWindow (GetForegroundWindow ());
|
|
||||||
MessageBoxA (GetActiveWindow (), buffer, "YaPB Error", MB_ICONSTOP);
|
|
||||||
#else
|
|
||||||
printf ("%s\n", buffer);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(PLATFORM_WIN32)
|
|
||||||
_exit (1);
|
|
||||||
#else
|
|
||||||
exit (1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BotUtils::findNearestPlayer (void **pvHolder, edict_t *to, float searchDistance, bool sameTeam, bool needBot, bool needAlive, bool needDrawn, bool needBotWithC4) {
|
bool BotUtils::findNearestPlayer (void **pvHolder, edict_t *to, float searchDistance, bool sameTeam, bool needBot, bool needAlive, bool needDrawn, bool needBotWithC4) {
|
||||||
// this function finds nearest to to, player with set of parameters, like his
|
// this function finds nearest to to, player with set of parameters, like his
|
||||||
// team, live status, search distance etc. if needBot is true, then pvHolder, will
|
// team, live status, search distance etc. if needBot is true, then pvHolder, will
|
||||||
|
|
@ -395,11 +285,11 @@ bool BotUtils::findNearestPlayer (void **pvHolder, edict_t *to, float searchDist
|
||||||
int toTeam = game.getTeam (to);
|
int toTeam = game.getTeam (to);
|
||||||
|
|
||||||
for (const auto &client : m_clients) {
|
for (const auto &client : m_clients) {
|
||||||
if (!(client.flags & CF_USED) || client.ent == to) {
|
if (!(client.flags & ClientFlags::Used) || client.ent == to) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((sameTeam && client.team != toTeam) || (needAlive && !(client.flags & CF_ALIVE)) || (needBot && !isFakeClient (client.ent)) || (needDrawn && (client.ent->v.effects & EF_NODRAW)) || (needBotWithC4 && (client.ent->v.weapons & WEAPON_C4))) {
|
if ((sameTeam && client.team != toTeam) || (needAlive && !(client.flags & ClientFlags::Alive)) || (needBot && !isFakeClient (client.ent)) || (needDrawn && (client.ent->v.effects & EF_NODRAW)) || (needBotWithC4 && (client.ent->v.weapons & Weapon::C4))) {
|
||||||
continue; // filter players with parameters
|
continue; // filter players with parameters
|
||||||
}
|
}
|
||||||
float distance = (client.ent->v.origin - to->v.origin).length ();
|
float distance = (client.ent->v.origin - to->v.origin).length ();
|
||||||
|
|
@ -416,7 +306,7 @@ bool BotUtils::findNearestPlayer (void **pvHolder, edict_t *to, float searchDist
|
||||||
|
|
||||||
// fill the holder
|
// fill the holder
|
||||||
if (needBot) {
|
if (needBot) {
|
||||||
*pvHolder = reinterpret_cast <void *> (bots.getBot (survive));
|
*pvHolder = reinterpret_cast <void *> (bots[survive]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
*pvHolder = reinterpret_cast <void *> (survive);
|
*pvHolder = reinterpret_cast <void *> (survive);
|
||||||
|
|
@ -436,16 +326,16 @@ void BotUtils::attachSoundsToClients (edict_t *ent, const char *sample, float vo
|
||||||
if (origin.empty ()) {
|
if (origin.empty ()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int index = game.indexOfEntity (ent) - 1;
|
int index = game.indexOfPlayer (ent);
|
||||||
|
|
||||||
if (index < 0 || index >= game.maxClients ()) {
|
if (index < 0 || index >= game.maxClients ()) {
|
||||||
float nearestDistance = 99999.0f;
|
float nearestDistance = 99999.0f;
|
||||||
|
|
||||||
// loop through all players
|
// loop through all players
|
||||||
for (int i = 0; i < game.maxClients (); i++) {
|
for (int i = 0; i < game.maxClients (); ++i) {
|
||||||
const Client &client = m_clients[i];
|
const Client &client = m_clients[i];
|
||||||
|
|
||||||
if (!(client.flags & CF_USED) || !(client.flags & CF_ALIVE)) {
|
if (!(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
float distance = (client.origin - origin).length ();
|
float distance = (client.origin - origin).length ();
|
||||||
|
|
@ -545,9 +435,9 @@ void BotUtils::simulateSoundUpdates (int playerIndex) {
|
||||||
else {
|
else {
|
||||||
extern ConVar mp_footsteps;
|
extern ConVar mp_footsteps;
|
||||||
|
|
||||||
if (mp_footsteps.boolean ()) {
|
if (mp_footsteps.bool_ ()) {
|
||||||
// moves fast enough?
|
// moves fast enough?
|
||||||
hearDistance = 1280.0f * (client.ent->v.velocity.length2D () / 260.0f);
|
hearDistance = 1280.0f * (client.ent->v.velocity.length2d () / 260.0f);
|
||||||
timeSound = game.timebase () + 0.3f;
|
timeSound = game.timebase () + 0.3f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -573,36 +463,129 @@ void BotUtils::simulateSoundUpdates (int playerIndex) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BotUtils::updateClients (void) {
|
void BotUtils::updateClients () {
|
||||||
|
|
||||||
// record some stats of all players on the server
|
// record some stats of all players on the server
|
||||||
for (int i = 0; i < game.maxClients (); i++) {
|
for (int i = 0; i < game.maxClients (); ++i) {
|
||||||
edict_t *player = game.entityOfIndex (i + 1);
|
edict_t *player = game.playerOfIndex (i);
|
||||||
Client &client = m_clients[i];
|
Client &client = m_clients[i];
|
||||||
|
|
||||||
if (!game.isNullEntity (player) && (player->v.flags & FL_CLIENT)) {
|
if (!game.isNullEntity (player) && (player->v.flags & FL_CLIENT)) {
|
||||||
client.ent = player;
|
client.ent = player;
|
||||||
client.flags |= CF_USED;
|
client.flags |= ClientFlags::Used;
|
||||||
|
|
||||||
if (util.isAlive (player)) {
|
if (util.isAlive (player)) {
|
||||||
client.flags |= CF_ALIVE;
|
client.flags |= ClientFlags::Alive;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
client.flags &= ~CF_ALIVE;
|
client.flags &= ~ClientFlags::Alive;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client.flags & CF_ALIVE) {
|
if (client.flags & ClientFlags::Alive) {
|
||||||
client.origin = player->v.origin;
|
client.origin = player->v.origin;
|
||||||
simulateSoundUpdates (i);
|
simulateSoundUpdates (i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
client.flags &= ~(CF_USED | CF_ALIVE);
|
client.flags &= ~(ClientFlags::Used | ClientFlags::Alive);
|
||||||
client.ent = nullptr;
|
client.ent = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int BotUtils::buildNumber (void) {
|
int BotUtils::getPingBitmask (edict_t *ent, int loss, int ping) {
|
||||||
|
// this function generats bitmask for SVC_PINGS engine message. See SV_EmitPings from engine for details
|
||||||
|
|
||||||
|
const auto emit = [] (int s0, int s1, int s2) {
|
||||||
|
return (s0 & (cr::bit (s1) - 1)) << s2;
|
||||||
|
};
|
||||||
|
return emit (loss, 7, 18) | emit (ping, 12, 6) | emit (game.indexOfPlayer (ent), 5, 1) | 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BotUtils::calculatePings () {
|
||||||
|
if (!game.is (GameFlags::HasFakePings) || yb_show_latency.int_ () != 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Twin <int, int> average { 0, 0 };
|
||||||
|
int numHumans = 0;
|
||||||
|
|
||||||
|
// first get average ping on server, and store real client pings
|
||||||
|
for (auto &client : m_clients) {
|
||||||
|
if (!(client.flags & ClientFlags::Used) || isFakeClient (client.ent)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int ping, loss;
|
||||||
|
engfuncs.pfnGetPlayerStats (client.ent, &ping, &loss);
|
||||||
|
|
||||||
|
// store normal client ping
|
||||||
|
client.ping = getPingBitmask (client.ent, loss, ping > 0 ? ping / 2 : rg.int_ (8, 16)); // getting player ping sometimes fails
|
||||||
|
client.pingUpdate = true; // force resend ping
|
||||||
|
|
||||||
|
numHumans++;
|
||||||
|
|
||||||
|
average.first += ping;
|
||||||
|
average.second += loss;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (numHumans > 0) {
|
||||||
|
average.first /= numHumans;
|
||||||
|
average.second /= numHumans;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
average.first = rg.int_ (30, 40);
|
||||||
|
average.second = rg.int_ (5, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now calculate bot ping based on average from players
|
||||||
|
for (auto &client : m_clients) {
|
||||||
|
if (!(client.flags & ClientFlags::Used)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto bot = bots[client.ent];
|
||||||
|
|
||||||
|
// we're only intrested in bots here
|
||||||
|
if (!bot) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int part = static_cast <int> (average.first * 0.2f);
|
||||||
|
|
||||||
|
int botPing = bot->m_basePing + rg.int_ (average.first - part, average.first + part) + rg.int_ (bot->m_difficulty / 2, bot->m_difficulty);
|
||||||
|
int botLoss = rg.int_ (average.second / 2, average.second);
|
||||||
|
|
||||||
|
client.ping = getPingBitmask (client.ent, botLoss, botPing);
|
||||||
|
client.pingUpdate = true; // force resend ping
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BotUtils::sendPings (edict_t *to) {
|
||||||
|
MessageWriter msg;
|
||||||
|
|
||||||
|
// missing from sdk
|
||||||
|
constexpr int kGamePingSVC = 17;
|
||||||
|
|
||||||
|
for (auto &client : m_clients) {
|
||||||
|
if (!(client.flags & ClientFlags::Used)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!client.pingUpdate) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
client.pingUpdate = false;
|
||||||
|
|
||||||
|
// no ping, no fun
|
||||||
|
if (!client.ping) {
|
||||||
|
client.ping = getPingBitmask (client.ent, rg.int_ (5, 10), rg.int_ (15, 40));
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.start (MSG_ONE_UNRELIABLE, kGamePingSVC, nullvec, to)
|
||||||
|
.writeLong (client.ping)
|
||||||
|
.end ();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int BotUtils::buildNumber () {
|
||||||
// this function generates build number from the compiler date macros
|
// this function generates build number from the compiler date macros
|
||||||
|
|
||||||
static int buildNumber = 0;
|
static int buildNumber = 0;
|
||||||
|
|
@ -624,7 +607,7 @@ int BotUtils::buildNumber (void) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
// go through all months, and calculate, days since year start
|
// go through all months, and calculate, days since year start
|
||||||
for (i = 0; i < 11; i++) {
|
for (i = 0; i < 11; ++i) {
|
||||||
if (strncmp (&date[0], months[i], 3) == 0) {
|
if (strncmp (&date[0], months[i], 3) == 0) {
|
||||||
break; // found current month break
|
break; // found current month break
|
||||||
}
|
}
|
||||||
|
|
@ -655,38 +638,38 @@ int BotUtils::getWeaponAlias (bool needString, const char *weaponAlias, int weap
|
||||||
|
|
||||||
// weapon enumeration
|
// weapon enumeration
|
||||||
WeaponTab_t weaponTab[] = {
|
WeaponTab_t weaponTab[] = {
|
||||||
{WEAPON_USP, "usp"}, // HK USP .45 Tactical
|
{Weapon::USP, "usp"}, // HK USP .45 Tactical
|
||||||
{WEAPON_GLOCK, "glock"}, // Glock18 Select Fire
|
{Weapon::Glock18, "glock"}, // Glock18 Select Fire
|
||||||
{WEAPON_DEAGLE, "deagle"}, // Desert Eagle .50AE
|
{Weapon::Deagle, "deagle"}, // Desert Eagle .50AE
|
||||||
{WEAPON_P228, "p228"}, // SIG P228
|
{Weapon::P228, "p228"}, // SIG P228
|
||||||
{WEAPON_ELITE, "elite"}, // Dual Beretta 96G Elite
|
{Weapon::Elite, "elite"}, // Dual Beretta 96G Elite
|
||||||
{WEAPON_FIVESEVEN, "fn57"}, // FN Five-Seven
|
{Weapon::FiveSeven, "fn57"}, // FN Five-Seven
|
||||||
{WEAPON_M3, "m3"}, // Benelli M3 Super90
|
{Weapon::M3, "m3"}, // Benelli M3 Super90
|
||||||
{WEAPON_XM1014, "xm1014"}, // Benelli XM1014
|
{Weapon::XM1014, "xm1014"}, // Benelli XM1014
|
||||||
{WEAPON_MP5, "mp5"}, // HK MP5-Navy
|
{Weapon::MP5, "mp5"}, // HK MP5-Navy
|
||||||
{WEAPON_TMP, "tmp"}, // Steyr Tactical Machine Pistol
|
{Weapon::TMP, "tmp"}, // Steyr Tactical Machine Pistol
|
||||||
{WEAPON_P90, "p90"}, // FN P90
|
{Weapon::P90, "p90"}, // FN P90
|
||||||
{WEAPON_MAC10, "mac10"}, // Ingram MAC-10
|
{Weapon::MAC10, "mac10"}, // Ingram MAC-10
|
||||||
{WEAPON_UMP45, "ump45"}, // HK UMP45
|
{Weapon::UMP45, "ump45"}, // HK UMP45
|
||||||
{WEAPON_AK47, "ak47"}, // Automat Kalashnikov AK-47
|
{Weapon::AK47, "ak47"}, // Automat Kalashnikov AK-47
|
||||||
{WEAPON_GALIL, "galil"}, // IMI Galil
|
{Weapon::Galil, "galil"}, // IMI Galil
|
||||||
{WEAPON_FAMAS, "famas"}, // GIAT FAMAS
|
{Weapon::Famas, "famas"}, // GIAT FAMAS
|
||||||
{WEAPON_SG552, "sg552"}, // Sig SG-552 Commando
|
{Weapon::SG552, "sg552"}, // Sig SG-552 Commando
|
||||||
{WEAPON_M4A1, "m4a1"}, // Colt M4A1 Carbine
|
{Weapon::M4A1, "m4a1"}, // Colt M4A1 Carbine
|
||||||
{WEAPON_AUG, "aug"}, // Steyr Aug
|
{Weapon::AUG, "aug"}, // Steyr Aug
|
||||||
{WEAPON_SCOUT, "scout"}, // Steyr Scout
|
{Weapon::Scout, "scout"}, // Steyr Scout
|
||||||
{WEAPON_AWP, "awp"}, // AI Arctic Warfare/Magnum
|
{Weapon::AWP, "awp"}, // AI Arctic Warfare/Magnum
|
||||||
{WEAPON_G3SG1, "g3sg1"}, // HK G3/SG-1 Sniper Rifle
|
{Weapon::G3SG1, "g3sg1"}, // HK G3/SG-1 Sniper Rifle
|
||||||
{WEAPON_SG550, "sg550"}, // Sig SG-550 Sniper
|
{Weapon::SG550, "sg550"}, // Sig SG-550 Sniper
|
||||||
{WEAPON_M249, "m249"}, // FN M249 Para
|
{Weapon::M249, "m249"}, // FN M249 Para
|
||||||
{WEAPON_FLASHBANG, "flash"}, // Concussion Grenade
|
{Weapon::Flashbang, "flash"}, // Concussion Grenade
|
||||||
{WEAPON_EXPLOSIVE, "hegren"}, // High-Explosive Grenade
|
{Weapon::Explosive, "hegren"}, // High-Explosive Grenade
|
||||||
{WEAPON_SMOKE, "sgren"}, // Smoke Grenade
|
{Weapon::Smoke, "sgren"}, // Smoke Grenade
|
||||||
{WEAPON_ARMOR, "vest"}, // Kevlar Vest
|
{Weapon::Armor, "vest"}, // Kevlar Vest
|
||||||
{WEAPON_ARMORHELM, "vesthelm"}, // Kevlar Vest and Helmet
|
{Weapon::ArmorHelm, "vesthelm"}, // Kevlar Vest and Helmet
|
||||||
{WEAPON_DEFUSER, "defuser"}, // Defuser Kit
|
{Weapon::Defuser, "defuser"}, // Defuser Kit
|
||||||
{WEAPON_SHIELD, "shield"}, // Tactical Shield
|
{Weapon::Shield, "shield"}, // Tactical Shield
|
||||||
{WEAPON_KNIFE, "knife"} // Knife
|
{Weapon::Knife, "knife"} // Knife
|
||||||
};
|
};
|
||||||
|
|
||||||
// if we need to return the string, find by weapon id
|
// if we need to return the string, find by weapon id
|
||||||
|
|
|
||||||
2928
source/waypoint.cpp
2928
source/waypoint.cpp
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue