<commit_before>#define DEBUG 1
/**
 * File    : F.cpp
 * Author  : Kazune Takahashi
 * Created : 2020/3/7 22:17:00
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::multiprecision::cpp_int;
using ll = long long;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
// constexpr ll MOD{1000000007LL};
constexpr ll MOD{998244353LL}; // be careful
constexpr ll MAX_SIZE{3000010LL};
// constexpr ll MAX_SIZE{30000010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(const Mint &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(const Mint &a) { return *this += -a; }
  Mint &operator++() { return *this += 1; }
  Mint &operator++(int)
  {
    Mint tmp{*this};
    ++*this;
    return tmp;
  }
  Mint &operator--() { return *this -= 1; }
  Mint &operator--(int)
  {
    Mint tmp{*this};
    --*this;
    return tmp;
  }
  Mint &operator*=(const Mint &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(const Mint &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(const Mint &a) const { return Mint(*this) += a; }
  Mint operator-(const Mint &a) const { return Mint(*this) -= a; }
  Mint operator*(const Mint &a) const { return Mint(*this) *= a; }
  Mint operator/(const Mint &a) const { return Mint(*this) /= a; }
  bool operator<(const Mint &a) const { return x < a.x; }
  bool operator<=(const Mint &a) const { return x <= a.x; }
  bool operator>(const Mint &a) const { return x > a.x; }
  bool operator>=(const Mint &a) const { return x >= a.x; }
  bool operator==(const Mint &a) const { return x == a.x; }
  bool operator!=(const Mint &a) const { return !(*this == a); }
  const Mint power(ll N)
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, const Mint<MOD> &rhs)
{
  return rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator-(ll lhs, const Mint<MOD> &rhs)
{
  return -rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator*(ll lhs, const Mint<MOD> &rhs)
{
  return rhs * lhs;
}
template <ll MOD>
Mint<MOD> operator/(ll lhs, const Mint<MOD> &rhs)
{
  return Mint<MOD>{lhs} / rhs;
}
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a)
{
  return stream >> a.x;
}
template <ll MOD>
ostream &operator<<(ostream &stream, const Mint<MOD> &a)
{
  return stream << a.x;
}
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i = 2LL; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i = 1LL; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
template <typename T>
T gcd(T x, T y) { return y ? gcd(y, x % y) : x; }
template <typename T>
T lcm(T x, T y) { return x / gcd(x, y) * y; }
// ----- for C++17 -----
template <typename T>
int popcount(T x) // C++20
{
  int ans{0};
  while (x != 0)
  {
    ans += x & 1;
    x >>= 1;
  }
  return ans;
}
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
constexpr ll infty{1000000000000000LL}; // or
// constexpr int infty{1'000'000'010};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- SegTree -----

template <typename T>
class SegTree
{ // 0-indexed, [0, N).
private:
  int N;
  vector<T> dat;
  T unit;  // モノイドの単位元
  T(*func) // モノイドの演算
  (T, T);
  T(*_update) // update で値をどうするか書く
  (T, T);

public:
  SegTree() {}

  SegTree(int n, T unit, T (*func)(T, T), T (*_update)(T, T)) : N{1}, unit{unit}, func{func}, _update{_update}
  {
    while (N < n)
    {
      N *= 2;
    }
    dat = vector<T>(2 * N - 1, unit);
  }

  void update(int k, T a)
  {
    k += N - 1;
    dat[k] = _update(dat[k], a);
    while (k > 0)
    {
      k = (k - 1) / 2;
      dat[k] = func(dat[k * 2 + 1], dat[k * 2 + 2]);
    }
  }

private:
  T find(int a, int b, int k, int l, int r)
  {
    if (r <= a || b <= l)
    {
      return unit;
    }
    if (a <= l && r <= b)
    {
      return dat[k];
    }
    T vl = find(a, b, k * 2 + 1, l, (l + r) / 2);
    T vr = find(a, b, k * 2 + 2, (l + r) / 2, r);
    return func(vl, vr);
  }

public:
  T find(int a, int b)
  { // [a, b) の find をする。
    return find(a, b, 0, 0, N);
  }
};

// ----- frequently used examples -----

auto func = [](auto x, auto y) {
  return min(x, y);
};
auto _update = [](auto x, auto y) {
  return min(x, y);
};
constexpr int unit{1 << 30};

// ----- main() -----

using robot = tuple<ll, ll>;
using info = tuple<ll, int>;

int main()
{
  int N;
  cin >> N;
  vector<robot> V(N);
  for (auto i = 0; i < N; ++i)
  {
    ll X, D;
    cin >> X >> D;
    V[i] = robot(X, X + D);
  }
  sort(V.rbegin(), V.rend());
  // make I part
  vector<int> I(N);
  SegTree<int> tree{N, unit, func, _update};
  set<info> S;
  S.insert(info(infty, -1));
  for (auto i = 0; i < N; ++i)
  {
    int l, r;
    tie(l, r) = V[i];
    S.insert(info(l, i));
    auto finish{get<1>(*S.lower_bound(info(r, i)))};
#if DEBUG == 1
    cerr << "l = " << l << ", r = " << r << ", finish = " << finish << endl;
#endif
    auto mini{tree.find(finish + 1, i)};
    ch_min(mini, i - 1);
    I[i] = mini;
  }
  // DP part
  vector<mint> DP(N + 1);
  DP[0] = 1;
  for (auto i = 0; i < N; ++i)
  {
    DP[i + 1] = DP[i] + DP[I[i]];
  }
  cout << DP[N] << endl;
}
<commit_msg>tried F.cpp to 'F'<commit_after>#define DEBUG 1
/**
 * File    : F.cpp
 * Author  : Kazune Takahashi
 * Created : 2020/3/7 22:17:00
 * Powered by Visual Studio Code
 */
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cctype>
#include <chrono>
#include <cmath>
#include <complex>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <functional>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <vector>
// ----- boost -----
#include <boost/rational.hpp>
#include <boost/multiprecision/cpp_int.hpp>
// ----- using directives and manipulations -----
using namespace std;
using boost::rational;
using boost::multiprecision::cpp_int;
using ll = long long;
template <typename T>
using max_heap = priority_queue<T>;
template <typename T>
using min_heap = priority_queue<T, vector<T>, greater<T>>;
// ----- constexpr for Mint and Combination -----
// constexpr ll MOD{1000000007LL};
constexpr ll MOD{998244353LL}; // be careful
constexpr ll MAX_SIZE{3000010LL};
// constexpr ll MAX_SIZE{30000010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{(x % MOD + MOD) % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(const Mint &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(const Mint &a) { return *this += -a; }
  Mint &operator++() { return *this += 1; }
  Mint &operator++(int)
  {
    Mint tmp{*this};
    ++*this;
    return tmp;
  }
  Mint &operator--() { return *this -= 1; }
  Mint &operator--(int)
  {
    Mint tmp{*this};
    --*this;
    return tmp;
  }
  Mint &operator*=(const Mint &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(const Mint &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(const Mint &a) const { return Mint(*this) += a; }
  Mint operator-(const Mint &a) const { return Mint(*this) -= a; }
  Mint operator*(const Mint &a) const { return Mint(*this) *= a; }
  Mint operator/(const Mint &a) const { return Mint(*this) /= a; }
  bool operator<(const Mint &a) const { return x < a.x; }
  bool operator<=(const Mint &a) const { return x <= a.x; }
  bool operator>(const Mint &a) const { return x > a.x; }
  bool operator>=(const Mint &a) const { return x >= a.x; }
  bool operator==(const Mint &a) const { return x == a.x; }
  bool operator!=(const Mint &a) const { return !(*this == a); }
  const Mint power(ll N)
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, const Mint<MOD> &rhs)
{
  return rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator-(ll lhs, const Mint<MOD> &rhs)
{
  return -rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator*(ll lhs, const Mint<MOD> &rhs)
{
  return rhs * lhs;
}
template <ll MOD>
Mint<MOD> operator/(ll lhs, const Mint<MOD> &rhs)
{
  return Mint<MOD>{lhs} / rhs;
}
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a)
{
  return stream >> a.x;
}
template <ll MOD>
ostream &operator<<(ostream &stream, const Mint<MOD> &a)
{
  return stream << a.x;
}
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i = 2LL; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i = 1LL; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
template <typename T>
T gcd(T x, T y) { return y ? gcd(y, x % y) : x; }
template <typename T>
T lcm(T x, T y) { return x / gcd(x, y) * y; }
// ----- for C++17 -----
template <typename T>
int popcount(T x) // C++20
{
  int ans{0};
  while (x != 0)
  {
    ans += x & 1;
    x >>= 1;
  }
  return ans;
}
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
constexpr ll infty{1000000000000000LL}; // or
// constexpr int infty{1'000'000'010};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- SegTree -----

template <typename T>
class SegTree
{ // 0-indexed, [0, N).
private:
  int N;
  vector<T> dat;
  T unit;  // モノイドの単位元
  T(*func) // モノイドの演算
  (T, T);
  T(*_update) // update で値をどうするか書く
  (T, T);

public:
  SegTree() {}

  SegTree(int n, T unit, T (*func)(T, T), T (*_update)(T, T)) : N{1}, unit{unit}, func{func}, _update{_update}
  {
    while (N < n)
    {
      N *= 2;
    }
    dat = vector<T>(2 * N - 1, unit);
  }

  void update(int k, T a)
  {
    k += N - 1;
    dat[k] = _update(dat[k], a);
    while (k > 0)
    {
      k = (k - 1) / 2;
      dat[k] = func(dat[k * 2 + 1], dat[k * 2 + 2]);
    }
  }

private:
  T find(int a, int b, int k, int l, int r)
  {
    if (r <= a || b <= l)
    {
      return unit;
    }
    if (a <= l && r <= b)
    {
      return dat[k];
    }
    T vl = find(a, b, k * 2 + 1, l, (l + r) / 2);
    T vr = find(a, b, k * 2 + 2, (l + r) / 2, r);
    return func(vl, vr);
  }

public:
  T find(int a, int b)
  { // [a, b) の find をする。
    return find(a, b, 0, 0, N);
  }
};

// ----- frequently used examples -----

auto func = [](auto x, auto y) {
  return min(x, y);
};
auto _update = [](auto x, auto y) {
  return min(x, y);
};
constexpr int unit{1 << 30};

// ----- main() -----

using robot = tuple<ll, ll>;
using info = tuple<ll, int>;

int main()
{
  int N;
  cin >> N;
  vector<robot> V(N);
  for (auto i = 0; i < N; ++i)
  {
    ll X, D;
    cin >> X >> D;
    V[i] = robot(X, X + D);
  }
  sort(V.rbegin(), V.rend());
  // make I part
  vector<int> I(N);
  SegTree<int> tree{N, unit, func, _update};
  set<info> S;
  S.insert(info(infty, -1));
  for (auto i = 0; i < N; ++i)
  {
    int l, r;
    tie(l, r) = V[i];
    S.insert(info(l, i));
    auto finish{get<1>(*S.lower_bound(info(r, -1)))};
#if DEBUG == 1
    cerr << "l = " << l << ", r = " << r << ", finish = " << finish << endl;
#endif
    auto mini{tree.find(finish + 1, i)};
    ch_min(mini, i - 1);
    I[i] = mini;
  }
  // DP part
  vector<mint> DP(N + 1);
  DP[0] = 1;
  for (auto i = 0; i < N; ++i)
  {
    DP[i + 1] = DP[i] + DP[I[i]];
  }
  cout << DP[N] << endl;
}
<|endoftext|>


<commit_before>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#include "bsecxxutils.hh"
#include "bsecxxbase.hh"
#include "bsecategories.hh"
#include <list>
using namespace std;
namespace Bse {
/* --- functions --- */
struct TypeRegistry::TypeEntry {
  guint               instance_size;
  const gchar        *name;
  const gchar        *parent;
  const ClassInfo    *cinfo;
  GBaseInitFunc       binit;
  GClassInitFunc      cinit;
  GInstanceInitFunc   iinit;
  TypeRegistry::Flags flags;
  TypeRegistry       *reg;
  /*Con*/ TypeEntry (guint               instance_size,
                     const gchar        *name,
                     const gchar        *parent,
                     const ClassInfo    *cinfo,
                     GBaseInitFunc       binit,
                     GClassInitFunc      cinit,
                     GInstanceInitFunc   iinit,
                     TypeRegistry::Flags flags)
    : reg (NULL)
  {
    this->instance_size = instance_size;
    this->name = name;
    this->parent = parent;
    this->cinfo = cinfo;
    this->binit = binit;
    this->cinit = cinit;
    this->iinit = iinit;
    this->flags = flags;
  }
};
static list<TypeRegistry::TypeEntry> *type_entries = NULL;
TypeRegistry::TypeRegistry (guint             instance_size,
                            const gchar      *name,
                            const gchar      *parent,
                            const ClassInfo  *cinfo,
                            GBaseInitFunc     binit,
                            void            (*class_init) (CxxBaseClass*),
                            GInstanceInitFunc iinit,
                            Flags             flags)
  : gtype_id (0)
{
  TypeEntry entry (instance_size, name, parent, cinfo, binit,
                   (GClassInitFunc) class_init,
                   iinit, flags);
  entry.reg = this;
  if (!type_entries)
    type_entries = new list<TypeEntry>();
  list<TypeEntry>::iterator li;
  for (li = type_entries->begin(); li != type_entries->end(); li++)
    if (strcmp (li->name, parent) == 0)
      break;
  if (li != type_entries->end())
    type_entries->insert (++li, entry);
  else  // parent not found in list
    type_entries->push_front (entry);
}
void
TypeRegistry::init_types()
{
  for (list<TypeEntry>::iterator li = type_entries->begin (); li != type_entries->end (); li++)
    {
      TypeRegistry *self = li->reg;
      GTypeInfo info = { 0, };
      info.class_size = BSE_CXX_COMMON_CLASS_SIZE;
      info.base_init = li->binit;
      info.class_init = li->cinit;
      info.instance_size = BSE_CXX_INSTANCE_OFFSET + li->instance_size;
      info.instance_init = li->iinit;
      self->gtype_id = g_type_register_static (g_type_from_name (li->parent),
                                               li->name, &info, (GTypeFlags) li->flags);
      if (li->cinfo)
        {
          if (li->cinfo->category)
            bse_categories_register (li->cinfo->category, NULL, self->gtype_id, NULL);
          if (li->cinfo->blurb)
            bse_type_add_blurb (self->gtype_id, li->cinfo->blurb, li->cinfo->file, li->cinfo->line);
        }
    }
  delete type_entries;
  type_entries = NULL;
}
static void
bse_terminate_handler ()
{
  try {
    throw;      // rethrow
  }
  catch (Exception &e) {
    g_error ("aborting due to exception: %s [in %s]", e.what(), e.where());
  }
  catch (std::exception &e) {
    g_error ("aborting due to exception: %s", e.what());
  }
  catch (...) {
    g_error ("aborting due to uncaught exception");
  }
}
static void
init_exception_handler ()
{
#if 0
  unexpected_handler former = set_unexpected (bse_unexpected_handler);
  if (former != std::unexpected)
    set_unexpected (former);
#else
  set_terminate (bse_terminate_handler);
#endif
}
extern "C" void
bse_cxx_init (void)  // prototyped in bseutils.hh
{
  init_exception_handler ();
  Bse::TypeRegistry::init_types();
}
} // Bse
<commit_msg>BSE: prevent messing with std::terminate<commit_after>// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
#include "bsecxxutils.hh"
#include "bsecxxbase.hh"
#include "bsecategories.hh"
#include <list>
using namespace std;    // FIXME

namespace Bse {

struct TypeRegistry::TypeEntry {
  guint               instance_size;
  const gchar        *name;
  const gchar        *parent;
  const ClassInfo    *cinfo;
  GBaseInitFunc       binit;
  GClassInitFunc      cinit;
  GInstanceInitFunc   iinit;
  TypeRegistry::Flags flags;
  TypeRegistry       *reg;
  /*Con*/ TypeEntry (guint               instance_size,
                     const gchar        *name,
                     const gchar        *parent,
                     const ClassInfo    *cinfo,
                     GBaseInitFunc       binit,
                     GClassInitFunc      cinit,
                     GInstanceInitFunc   iinit,
                     TypeRegistry::Flags flags)
    : reg (NULL)
  {
    this->instance_size = instance_size;
    this->name = name;
    this->parent = parent;
    this->cinfo = cinfo;
    this->binit = binit;
    this->cinit = cinit;
    this->iinit = iinit;
    this->flags = flags;
  }
};

static list<TypeRegistry::TypeEntry> *type_entries = NULL;

TypeRegistry::TypeRegistry (guint             instance_size,
                            const gchar      *name,
                            const gchar      *parent,
                            const ClassInfo  *cinfo,
                            GBaseInitFunc     binit,
                            void            (*class_init) (CxxBaseClass*),
                            GInstanceInitFunc iinit,
                            Flags             flags)
  : gtype_id (0)
{
  TypeEntry entry (instance_size, name, parent, cinfo, binit,
                   (GClassInitFunc) class_init,
                   iinit, flags);
  entry.reg = this;
  if (!type_entries)
    type_entries = new list<TypeEntry>();
  list<TypeEntry>::iterator li;
  for (li = type_entries->begin(); li != type_entries->end(); li++)
    if (strcmp (li->name, parent) == 0)
      break;
  if (li != type_entries->end())
    type_entries->insert (++li, entry);
  else  // parent not found in list
    type_entries->push_front (entry);
}

void
TypeRegistry::init_types()
{
  for (list<TypeEntry>::iterator li = type_entries->begin (); li != type_entries->end (); li++)
    {
      TypeRegistry *self = li->reg;
      GTypeInfo info = { 0, };
      info.class_size = BSE_CXX_COMMON_CLASS_SIZE;
      info.base_init = li->binit;
      info.class_init = li->cinit;
      info.instance_size = BSE_CXX_INSTANCE_OFFSET + li->instance_size;
      info.instance_init = li->iinit;
      self->gtype_id = g_type_register_static (g_type_from_name (li->parent),
                                               li->name, &info, (GTypeFlags) li->flags);
      if (li->cinfo)
        {
          if (li->cinfo->category)
            bse_categories_register (li->cinfo->category, NULL, self->gtype_id, NULL);
          if (li->cinfo->blurb)
            bse_type_add_blurb (self->gtype_id, li->cinfo->blurb, li->cinfo->file, li->cinfo->line);
        }
    }
  delete type_entries;
  type_entries = NULL;
}

extern "C" void
bse_cxx_init (void)  // prototyped in bseutils.hh
{
  // FIXME: delete: init_exception_handler ();
  Bse::TypeRegistry::init_types();
}

} // Bse
<|endoftext|>


<commit_before>#include "main.h"
#include "CNetwork.h"
#include "CServer.h"
#include "CUtils.h"

#include <istream>
#include <boost/date_time/posix_time/posix_time.hpp>

#include "format.h"

void CNetwork::NetAlive(const boost::system::error_code &error_code, bool from_write)
{
	if (from_write == false)
	{
		if (m_Socket.is_open())
		{
			static string empty_data("\n");
			m_Socket.async_send(asio::buffer(empty_data), boost::bind(&CNetwork::NetAlive, this, boost::asio::placeholders::error, true));
		}
		m_AliveTimer.expires_from_now(boost::posix_time::seconds(60));
		m_AliveTimer.async_wait(boost::bind(&CNetwork::NetAlive, this, boost::asio::placeholders::error, false));
	}
}

void CNetwork::Connect(char *ip, unsigned short port, unsigned short query_port)
{
	m_SocketDest = tcp::endpoint(asio::ip::address::from_string(ip), query_port);
	m_ServerPort = port;
	AsyncConnect();
	m_IoThread = new thread(boost::bind(&asio::io_service::run, boost::ref(m_IoService)));

	Execute(fmt::format("use port={}", m_ServerPort));
}

void CNetwork::Disconnect()
{
	if (m_Socket.is_open() == false)
		return;

	m_Socket.close();
	m_IoService.stop();

	if (m_IoThread != nullptr)
	{
		if (m_IoThread->get_id() != boost::this_thread::get_id())
			m_IoThread->join();
		delete m_IoThread;
		m_IoThread = nullptr;
	}
}

void CNetwork::AsyncRead()
{
	asio::async_read_until(m_Socket, m_ReadStreamBuf, '\r', boost::bind(&CNetwork::OnRead, this, _1));
}

void CNetwork::AsyncWrite(string &data)
{
	m_CmdWriteBuffer = data;
	if (data.at(data.length()-1) != '\n')
		m_CmdWriteBuffer.push_back('\n');

	m_Socket.async_send(asio::buffer(m_CmdWriteBuffer), boost::bind(&CNetwork::OnWrite, this, _1));
}

void CNetwork::AsyncConnect()
{
	if (m_Socket.is_open())
		m_Socket.close();

	m_Socket.async_connect(m_SocketDest, boost::bind(&CNetwork::OnConnect, this, _1));
}

void CNetwork::OnConnect(const boost::system::error_code &error_code)
{
	if (error_code.value() == 0)
	{
		AsyncRead();
	}
	else
	{
		logprintf(">> plugin.TSConnector: Error while connecting to server: \"%s\"", error_code.message().c_str());
		Disconnect();
	}
}

/*
	- result data is sent as a string which ends with "\n\r"
	- the Teamspeak3 server can send multiple strings
	- the end of a result set is always an error result string
*/
void CNetwork::OnRead(const boost::system::error_code &error_code)
{
	if (error_code.value() == 0)
	{
		static vector<string> captured_data;
		std::istream tmp_stream(&m_ReadStreamBuf);
		string read_data;
		std::getline(tmp_stream, read_data, '\r');

#ifdef _DEBUG
		if (read_data.length() < 512)
			logprintf(">>>> %s", read_data.c_str());
		else
			logprintf(">>>> <INPUT TOO LONG>");
#endif

		//regex: parse error
		//if this is an error message, it means that no other result data will come
		static const boost::regex error_rx("error id=([0-9]+) msg=([^ \n]+)");
		boost::smatch error_rx_result;
		if (boost::regex_search(read_data, error_rx_result, error_rx))
		{
			if (error_rx_result[1].str() == "0")
			{
				for (auto i = captured_data.begin(); i != captured_data.end(); ++i)
				{
					string &data = *i;
					if (data.find('|') != string::npos) //multiple data rows with '|' as delimiter
					{
						vector<string> result_set;
						size_t delim_pos = 0;
						do
						{
							size_t old_delim_pos = delim_pos;
							delim_pos = data.find('|', delim_pos);
							string row = data.substr(old_delim_pos, delim_pos - old_delim_pos);
							result_set.push_back(row);
						} while (delim_pos != string::npos && ++delim_pos);

						i = captured_data.erase(i);
						for (auto j = result_set.begin(), jend = result_set.end(); j != jend; ++j)
							i = captured_data.insert(i, *j);
					}
				}

				//call callback and send next command
				m_CmdQueueMutex.lock();
				if (m_CmdQueue.empty() == false)
				{
					ReadCallback_t &callback = m_CmdQueue.front().get<1>();
					m_CmdQueueMutex.unlock();
					if (callback.empty() == false)
						callback(captured_data); //calls the callback
					m_CmdQueueMutex.lock();
					m_CmdQueue.pop();

					if (m_CmdQueue.empty() == false)
						AsyncWrite(m_CmdQueue.front().get<0>());
				}
				m_CmdQueueMutex.unlock();
			}
			else
			{
				string error_str(error_rx_result[2].str());
				CUtils::Get()->UnEscapeString(error_str);

				logprintf(">> plugin.TSConnector: Error while executing \"%s\": %s (#%s)",
					m_CmdQueue.front().get<0>().c_str(), error_str.c_str(), error_rx_result[1].str().c_str());
				m_CmdQueue.pop();
			}

			captured_data.clear();
		}
		else if (read_data.find("notify") == 0)
		{
			static string last_notify_data;
			//check if notify is duplicate
			if (last_notify_data != read_data)
			{
				//notify event
				boost::smatch event_result;
				for (auto &event : m_EventList)
				{
					if (boost::regex_search(read_data, event_result, event.get<0>()))
					{
						event.get<1>()(event_result);
						break;
					}
				}
			}
			last_notify_data = read_data;
		}
		else
		{
			//stack the result data if it is not an error or notification message
			captured_data.push_back(read_data);
		}

		AsyncRead();
	}
	else if (error_code == asio::error::eof)
	{
		AsyncConnect();
	}
	else
		logprintf(">> plugin.TSConnector: Error while reading: %s (#%d)", error_code.message().c_str(), error_code.value());
}

void CNetwork::OnWrite(const boost::system::error_code &error_code)
{
#ifdef _DEBUG
	logprintf("<<<< %s", m_CmdWriteBuffer.c_str());
#endif
	m_CmdWriteBuffer.clear();
	if (error_code.value() != 0)
		logprintf(">> plugin.TSConnector: Error while writing: %s (#%d)", error_code.message().c_str(), error_code.value());
}

void CNetwork::Execute(string cmd, ReadCallback_t callback)
{
	boost::lock_guard<boost::mutex> queue_lock_guard(m_CmdQueueMutex);
	m_CmdQueue.push(boost::make_tuple(boost::move(cmd), boost::move(callback)));
	if (m_CmdQueue.size() == 1)
		AsyncWrite(m_CmdQueue.front().get<0>());
}

<commit_msg>improved debug message<commit_after>#include "main.h"
#include "CNetwork.h"
#include "CServer.h"
#include "CUtils.h"

#include <istream>
#include <boost/date_time/posix_time/posix_time.hpp>

#include "format.h"

void CNetwork::NetAlive(const boost::system::error_code &error_code, bool from_write)
{
	if (from_write == false)
	{
		if (m_Socket.is_open())
		{
			static string empty_data("\n");
			m_Socket.async_send(asio::buffer(empty_data), boost::bind(&CNetwork::NetAlive, this, boost::asio::placeholders::error, true));
		}
		m_AliveTimer.expires_from_now(boost::posix_time::seconds(60));
		m_AliveTimer.async_wait(boost::bind(&CNetwork::NetAlive, this, boost::asio::placeholders::error, false));
	}
}

void CNetwork::Connect(char *ip, unsigned short port, unsigned short query_port)
{
	m_SocketDest = tcp::endpoint(asio::ip::address::from_string(ip), query_port);
	m_ServerPort = port;
	AsyncConnect();
	m_IoThread = new thread(boost::bind(&asio::io_service::run, boost::ref(m_IoService)));

	Execute(fmt::format("use port={}", m_ServerPort));
}

void CNetwork::Disconnect()
{
	if (m_Socket.is_open() == false)
		return;

	m_Socket.close();
	m_IoService.stop();

	if (m_IoThread != nullptr)
	{
		if (m_IoThread->get_id() != boost::this_thread::get_id())
			m_IoThread->join();
		delete m_IoThread;
		m_IoThread = nullptr;
	}
}

void CNetwork::AsyncRead()
{
	asio::async_read_until(m_Socket, m_ReadStreamBuf, '\r', boost::bind(&CNetwork::OnRead, this, _1));
}

void CNetwork::AsyncWrite(string &data)
{
	m_CmdWriteBuffer = data;
	if (data.at(data.length()-1) != '\n')
		m_CmdWriteBuffer.push_back('\n');

	m_Socket.async_send(asio::buffer(m_CmdWriteBuffer), boost::bind(&CNetwork::OnWrite, this, _1));
}

void CNetwork::AsyncConnect()
{
	if (m_Socket.is_open())
		m_Socket.close();

	m_Socket.async_connect(m_SocketDest, boost::bind(&CNetwork::OnConnect, this, _1));
}

void CNetwork::OnConnect(const boost::system::error_code &error_code)
{
	if (error_code.value() == 0)
	{
		AsyncRead();
	}
	else
	{
		logprintf(">> plugin.TSConnector: Error while connecting to server: \"%s\"", error_code.message().c_str());
		Disconnect();
	}
}

/*
	- result data is sent as a string which ends with "\n\r"
	- the Teamspeak3 server can send multiple strings
	- the end of a result set is always an error result string
*/
void CNetwork::OnRead(const boost::system::error_code &error_code)
{
	if (error_code.value() == 0)
	{
		static vector<string> captured_data;
		std::istream tmp_stream(&m_ReadStreamBuf);
		string read_data;
		std::getline(tmp_stream, read_data, '\r');

#ifdef _DEBUG
		if (read_data.length() < 512)
			logprintf(">>>> %s", read_data.c_str());
		else
		{
			string shortened_data(read_data);
			shortened_data.resize(256);
			logprintf(">>>> %s", shortened_data.c_str());
		}
#endif

		//regex: parse error
		//if this is an error message, it means that no other result data will come
		static const boost::regex error_rx("error id=([0-9]+) msg=([^ \n]+)");
		boost::smatch error_rx_result;
		if (boost::regex_search(read_data, error_rx_result, error_rx))
		{
			if (error_rx_result[1].str() == "0")
			{
				for (auto i = captured_data.begin(); i != captured_data.end(); ++i)
				{
					string &data = *i;
					if (data.find('|') != string::npos) //multiple data rows with '|' as delimiter
					{
						vector<string> result_set;
						size_t delim_pos = 0;
						do
						{
							size_t old_delim_pos = delim_pos;
							delim_pos = data.find('|', delim_pos);
							string row = data.substr(old_delim_pos, delim_pos - old_delim_pos);
							result_set.push_back(row);
						} while (delim_pos != string::npos && ++delim_pos);

						i = captured_data.erase(i);
						for (auto j = result_set.begin(), jend = result_set.end(); j != jend; ++j)
							i = captured_data.insert(i, *j);
					}
				}

				//call callback and send next command
				m_CmdQueueMutex.lock();
				if (m_CmdQueue.empty() == false)
				{
					ReadCallback_t &callback = m_CmdQueue.front().get<1>();
					m_CmdQueueMutex.unlock();
					if (callback.empty() == false)
						callback(captured_data); //calls the callback
					m_CmdQueueMutex.lock();
					m_CmdQueue.pop();

					if (m_CmdQueue.empty() == false)
						AsyncWrite(m_CmdQueue.front().get<0>());
				}
				m_CmdQueueMutex.unlock();
			}
			else
			{
				string error_str(error_rx_result[2].str());
				CUtils::Get()->UnEscapeString(error_str);

				logprintf(">> plugin.TSConnector: Error while executing \"%s\": %s (#%s)",
					m_CmdQueue.front().get<0>().c_str(), error_str.c_str(), error_rx_result[1].str().c_str());
				m_CmdQueue.pop();
			}

			captured_data.clear();
		}
		else if (read_data.find("notify") == 0)
		{
			static string last_notify_data;
			//check if notify is duplicate
			if (last_notify_data != read_data)
			{
				//notify event
				boost::smatch event_result;
				for (auto &event : m_EventList)
				{
					if (boost::regex_search(read_data, event_result, event.get<0>()))
					{
						event.get<1>()(event_result);
						break;
					}
				}
			}
			last_notify_data = read_data;
		}
		else
		{
			//stack the result data if it is not an error or notification message
			captured_data.push_back(read_data);
		}

		AsyncRead();
	}
	else if (error_code == asio::error::eof)
	{
		AsyncConnect();
	}
	else
		logprintf(">> plugin.TSConnector: Error while reading: %s (#%d)", error_code.message().c_str(), error_code.value());
}

void CNetwork::OnWrite(const boost::system::error_code &error_code)
{
#ifdef _DEBUG
	logprintf("<<<< %s", m_CmdWriteBuffer.c_str());
#endif
	m_CmdWriteBuffer.clear();
	if (error_code.value() != 0)
		logprintf(">> plugin.TSConnector: Error while writing: %s (#%d)", error_code.message().c_str(), error_code.value());
}

void CNetwork::Execute(string cmd, ReadCallback_t callback)
{
	boost::lock_guard<boost::mutex> queue_lock_guard(m_CmdQueueMutex);
	m_CmdQueue.push(boost::make_tuple(boost::move(cmd), boost::move(callback)));
	if (m_CmdQueue.size() == 1)
		AsyncWrite(m_CmdQueue.front().get<0>());
}

<|endoftext|>


<commit_before>#include "CVehicle.h"
#include "CPlayer.h"
#include "CFuncCall.h"
#include "COption.h"

#include <sampgdk/a_vehicles.h>

#include <boost/chrono/chrono.hpp>
namespace chrono = boost::chrono;

CVehicleHandler *CVehicleHandler::m_Instance = nullptr;

void CVehicleHandler::AddVehicle(CVehicle *veh, bool only_rtree /* = false*/)
{
	if(only_rtree == false)
	{
		veh->m_Id = 1;
		while(m_Vehicles.find(veh->m_Id) != m_Vehicles.end())
			veh->m_Id++;

		m_Vehicles.insert(unordered_map<uint32_t, CVehicle *>::value_type(veh->m_Id, veh));
	}
	m_Rtree.insert(boost::make_tuple(veh->m_Pos, veh));
}

void CVehicleHandler::RemoveVehicle(CVehicle *veh, bool only_rtree /* = false*/)
{
	if(only_rtree == false)
		m_Vehicles.quick_erase(m_Vehicles.find(veh->m_Id));

	m_Rtree.remove(boost::make_tuple(veh->m_Pos, veh));
}

CVehicle *CVehicleHandler::FindVehicle(uint32_t vid)
{
	unordered_map<uint32_t, CVehicle *>::iterator i = m_Vehicles.find(vid);
	return (i != m_Vehicles.end()) ? i->second : nullptr;
}

CVehicle *CVehicleHandler::FindVehicleByRealID(uint32_t vehid)
{
	for(unordered_map<uint32_t, CVehicle *>::iterator i = m_Vehicles.begin(), end = m_Vehicles.end(); i != end; ++i)
	{
		if(i->second->m_VehicleId == vehid)
			return i->second;
	}
	return nullptr;
}

bool stream_check_func(const boost::tuple<point, CVehicle *> &v, CPlayer *player)
{
	const point &veh_pos = boost::get<0>(v);
	return player->ShouldStream(geo::get<0>(veh_pos), geo::get<1>(veh_pos), geo::get<2>(veh_pos), COption::Get()->GetVehicleStreamDistance());
}
void CVehicleHandler::StreamAll(CPlayer *player)
{
	std::vector<boost::tuple<point, CVehicle *> > query_res;
	m_Rtree.query(geo::index::satisfies(boost::bind(&stream_check_func, _1, player)), std::back_inserter(query_res));

	set<CVehicle *> invalid_vehicles = player->StreamedVehicles;

	for(auto &t : query_res)
	{
		CVehicle *vehicle = boost::get<1>(t);
		if(vehicle->m_StreamedFor.empty())
			CFuncCall::Get()->QueueFunc(boost::bind(&CVehicle::CreateInternalVeh, vehicle));

		vehicle->m_StreamedFor.insert(player->GetId());
		player->StreamedVehicles.insert(vehicle);

		invalid_vehicles.erase(vehicle);
	}

	for(auto &v : invalid_vehicles)
	{
		if(!v->m_StreamedFor.empty() && v->m_SeatInfo.empty())
		{
			v->m_StreamedFor.erase(player->GetId());
			player->StreamedVehicles.erase(v);

			if(v->m_StreamedFor.empty())
				CFuncCall::Get()->QueueFunc(boost::bind(&CVehicle::DestroyInternalVeh, v));

		}
	}
}

CVehicleHandler::~CVehicleHandler()
{
	for(unordered_map<uint32_t, CVehicle *>::iterator i = m_Vehicles.begin(), end = m_Vehicles.end(); i != end; ++i)
		i->second->Destroy();
}

CVehicle *CVehicle::Create(uint16_t modelid,
	float pos_x, float pos_y, float pos_z, float pos_a,
	int16_t color1, int16_t color2)
{
	CVehicle *veh = new CVehicle;

	veh->m_ModelId = modelid;

	veh->m_Pos = point(pos_x, pos_y, pos_z);
	veh->m_FacingAngle = pos_a;

	veh->m_Color[0] = color1;
	veh->m_Color[1] = color2;

	CVehicleHandler::Get()->AddVehicle(veh); //vehicle id is assigned in this function

	return veh;
}

void CVehicle::Destroy()
{
	CVehicleHandler::Get()->RemoveVehicle(this);
	delete this;
}

void CVehicle::CreateInternalVeh()
{
	m_VehicleId = CreateVehicle(m_ModelId, geo::get<0>(m_Pos), geo::get<1>(m_Pos), geo::get<2>(m_Pos), m_FacingAngle, m_Color[0], m_Color[1], -1);
	SetVehicleParamsEx(m_VehicleId, m_ParamsEx[0], m_ParamsEx[1], m_ParamsEx[2], m_ParamsEx[3], m_ParamsEx[4], m_ParamsEx[5], m_ParamsEx[6]);
	ChangeVehiclePaintjob(m_VehicleId, m_Paintjob);
	SetVehicleHealth(m_VehicleId, m_Health);
	UpdateVehicleDamageStatus(m_VehicleId, m_DamageStatus[0], m_DamageStatus[1], m_DamageStatus[2], m_DamageStatus[3]);
	SetVehicleVirtualWorld(m_VehicleId, m_VirtualWorld);
}

void CVehicle::DestroyInternalVeh()
{
	Update();
	DestroyVehicle(m_VehicleId);
	m_VehicleId = 0;
}

void CVehicle::Update()
{
	float tmp_pos[3];

	GetVehiclePos(m_VehicleId, &tmp_pos[0], &tmp_pos[1], &tmp_pos[2]);
	geo::set<0>(m_Pos, tmp_pos[0]);
	geo::set<1>(m_Pos, tmp_pos[1]);
	geo::set<2>(m_Pos, tmp_pos[2]);

	GetVehicleZAngle(m_VehicleId, &m_FacingAngle);
	GetVehicleParamsEx(m_VehicleId, &m_ParamsEx[0], &m_ParamsEx[1], &m_ParamsEx[2], &m_ParamsEx[3], &m_ParamsEx[4], &m_ParamsEx[5], &m_ParamsEx[6]);
	GetVehicleHealth(m_VehicleId, &m_Health);
	GetVehicleDamageStatus(m_VehicleId, &m_DamageStatus[0], &m_DamageStatus[1], &m_DamageStatus[2], &m_DamageStatus[3]);
	m_VirtualWorld = GetVehicleVirtualWorld(m_VehicleId);
}

void CVehicle::OnPlayerEnter(CPlayer *player, int8_t seatid)
{
	m_SeatInfo.insert( unordered_map<int8_t, uint32_t>::value_type(seatid, player->GetId()) );
	CVehicleHandler::Get()->RemoveVehicle(this, true);
}

void CVehicle::OnPlayerExit(CPlayer *player)
{
	Update();
	for(unordered_map<int8_t, uint32_t>::iterator i = m_SeatInfo.begin(), end = m_SeatInfo.end(); i != end; ++i)
	{
		if(i->second == player->GetId())
		{
			m_SeatInfo.quick_erase(i);
			break;
		}
	}
	CVehicleHandler::Get()->AddVehicle(this, true);
}
<commit_msg>destroying the vehicle itself is also a good idea<commit_after>#include "CVehicle.h"
#include "CPlayer.h"
#include "CFuncCall.h"
#include "COption.h"

#include <sampgdk/a_vehicles.h>

#include <boost/chrono/chrono.hpp>
namespace chrono = boost::chrono;

CVehicleHandler *CVehicleHandler::m_Instance = nullptr;

void CVehicleHandler::AddVehicle(CVehicle *veh, bool only_rtree /* = false*/)
{
	if(only_rtree == false)
	{
		veh->m_Id = 1;
		while(m_Vehicles.find(veh->m_Id) != m_Vehicles.end())
			veh->m_Id++;

		m_Vehicles.insert(unordered_map<uint32_t, CVehicle *>::value_type(veh->m_Id, veh));
	}
	m_Rtree.insert(boost::make_tuple(veh->m_Pos, veh));
}

void CVehicleHandler::RemoveVehicle(CVehicle *veh, bool only_rtree /* = false*/)
{
	if(only_rtree == false)
		m_Vehicles.quick_erase(m_Vehicles.find(veh->m_Id));

	m_Rtree.remove(boost::make_tuple(veh->m_Pos, veh));
}

CVehicle *CVehicleHandler::FindVehicle(uint32_t vid)
{
	unordered_map<uint32_t, CVehicle *>::iterator i = m_Vehicles.find(vid);
	return (i != m_Vehicles.end()) ? i->second : nullptr;
}

CVehicle *CVehicleHandler::FindVehicleByRealID(uint32_t vehid)
{
	for(unordered_map<uint32_t, CVehicle *>::iterator i = m_Vehicles.begin(), end = m_Vehicles.end(); i != end; ++i)
	{
		if(i->second->m_VehicleId == vehid)
			return i->second;
	}
	return nullptr;
}

bool stream_check_func(const boost::tuple<point, CVehicle *> &v, CPlayer *player)
{
	const point &veh_pos = boost::get<0>(v);
	return player->ShouldStream(geo::get<0>(veh_pos), geo::get<1>(veh_pos), geo::get<2>(veh_pos), COption::Get()->GetVehicleStreamDistance());
}
void CVehicleHandler::StreamAll(CPlayer *player)
{
	std::vector<boost::tuple<point, CVehicle *> > query_res;
	m_Rtree.query(geo::index::satisfies(boost::bind(&stream_check_func, _1, player)), std::back_inserter(query_res));

	set<CVehicle *> invalid_vehicles = player->StreamedVehicles;

	for(auto &t : query_res)
	{
		CVehicle *vehicle = boost::get<1>(t);
		if(vehicle->m_StreamedFor.empty())
			CFuncCall::Get()->QueueFunc(boost::bind(&CVehicle::CreateInternalVeh, vehicle));

		vehicle->m_StreamedFor.insert(player->GetId());
		player->StreamedVehicles.insert(vehicle);

		invalid_vehicles.erase(vehicle);
	}

	for(auto &v : invalid_vehicles)
	{
		if(!v->m_StreamedFor.empty() && v->m_SeatInfo.empty())
		{
			v->m_StreamedFor.erase(player->GetId());
			player->StreamedVehicles.erase(v);

			if(v->m_StreamedFor.empty())
				CFuncCall::Get()->QueueFunc(boost::bind(&CVehicle::DestroyInternalVeh, v));

		}
	}
}

CVehicleHandler::~CVehicleHandler()
{
	for(unordered_map<uint32_t, CVehicle *>::iterator i = m_Vehicles.begin(), end = m_Vehicles.end(); i != end; ++i)
		i->second->Destroy();
}

CVehicle *CVehicle::Create(uint16_t modelid,
	float pos_x, float pos_y, float pos_z, float pos_a,
	int16_t color1, int16_t color2)
{
	CVehicle *veh = new CVehicle;

	veh->m_ModelId = modelid;

	veh->m_Pos = point(pos_x, pos_y, pos_z);
	veh->m_FacingAngle = pos_a;

	veh->m_Color[0] = color1;
	veh->m_Color[1] = color2;

	CVehicleHandler::Get()->AddVehicle(veh); //vehicle id is assigned in this function

	return veh;
}

void CVehicle::Destroy()
{
	CVehicleHandler::Get()->RemoveVehicle(this);
	if (m_VehicleId != 0)
		DestroyVehicle(m_VehicleId);
	delete this;
}

void CVehicle::CreateInternalVeh()
{
	m_VehicleId = CreateVehicle(m_ModelId, geo::get<0>(m_Pos), geo::get<1>(m_Pos), geo::get<2>(m_Pos), m_FacingAngle, m_Color[0], m_Color[1], -1);
	SetVehicleParamsEx(m_VehicleId, m_ParamsEx[0], m_ParamsEx[1], m_ParamsEx[2], m_ParamsEx[3], m_ParamsEx[4], m_ParamsEx[5], m_ParamsEx[6]);
	ChangeVehiclePaintjob(m_VehicleId, m_Paintjob);
	SetVehicleHealth(m_VehicleId, m_Health);
	UpdateVehicleDamageStatus(m_VehicleId, m_DamageStatus[0], m_DamageStatus[1], m_DamageStatus[2], m_DamageStatus[3]);
	SetVehicleVirtualWorld(m_VehicleId, m_VirtualWorld);
}

void CVehicle::DestroyInternalVeh()
{
	Update();
	DestroyVehicle(m_VehicleId);
	m_VehicleId = 0;
}

void CVehicle::Update()
{
	float tmp_pos[3];

	GetVehiclePos(m_VehicleId, &tmp_pos[0], &tmp_pos[1], &tmp_pos[2]);
	geo::set<0>(m_Pos, tmp_pos[0]);
	geo::set<1>(m_Pos, tmp_pos[1]);
	geo::set<2>(m_Pos, tmp_pos[2]);

	GetVehicleZAngle(m_VehicleId, &m_FacingAngle);
	GetVehicleParamsEx(m_VehicleId, &m_ParamsEx[0], &m_ParamsEx[1], &m_ParamsEx[2], &m_ParamsEx[3], &m_ParamsEx[4], &m_ParamsEx[5], &m_ParamsEx[6]);
	GetVehicleHealth(m_VehicleId, &m_Health);
	GetVehicleDamageStatus(m_VehicleId, &m_DamageStatus[0], &m_DamageStatus[1], &m_DamageStatus[2], &m_DamageStatus[3]);
	m_VirtualWorld = GetVehicleVirtualWorld(m_VehicleId);
}

void CVehicle::OnPlayerEnter(CPlayer *player, int8_t seatid)
{
	m_SeatInfo.insert( unordered_map<int8_t, uint32_t>::value_type(seatid, player->GetId()) );
	CVehicleHandler::Get()->RemoveVehicle(this, true);
}

void CVehicle::OnPlayerExit(CPlayer *player)
{
	Update();
	for(unordered_map<int8_t, uint32_t>::iterator i = m_SeatInfo.begin(), end = m_SeatInfo.end(); i != end; ++i)
	{
		if(i->second == player->GetId())
		{
			m_SeatInfo.quick_erase(i);
			break;
		}
	}
	CVehicleHandler::Get()->AddVehicle(this, true);
}
<|endoftext|>


<commit_before>//
//  main.cpp
//  class1
//
//  Created by Aaron Taylor on 9/11/14.
//  Copyright (c) 2014 Aaron Taylor. All rights reserved.
//

#define _USE_MATH_DEFINES
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
// Needed on MsWindows
#include <windows.h>
#endif // Win32 platform

#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
// Download glut from:
// http://www.opengl.org/resources/libraries/glut/
#include <GLUT/glut.h>

#define ARC4RANDOM_MAX 0x100000000
// random double between 0.0 and 1.0
#define LITTLE_RAND ((double)arc4random() / ARC4RANDOM_MAX)

//////////////////////////////
// game tuning parameters
//////////////////////////////

#define NUM_BLOCKS 45
#define STEP_SIZE 0.02
#define MOUSE_WEIGHT 25.0
#define PLAYER_SIZE 0.05
#define COLLISION_DIST 0.07

//////////////////////////////
// call back method definitions
//////////////////////////////

void onReshape(int winWidth0, int winHeight0);
void onKeyboard(unsigned char key, int x, int y);
void onMotion(int x, int y);
void onIdle();
void onDisplay();

//////////////////////////////
// global variables and types
//////////////////////////////

typedef enum{
    selection,
    straightGame,
    diagonalGame,
    sinGame,
    jitterGame
}mode;

mode gameMode = selection;

int score = 0;

//////////////////////////////
// game objects
//////////////////////////////

class Block {
    float baseYOffset = 0.5; // allows for centered behavior such as sine curves
    float yOffset = 0.5;
    float xOffset = -1.0;

    float size = 0.05;

    float speedMultiplier = 1.0;
    float verticalMovement = 0.0;

    float rColor = 0.0;
    float gColor = 0.0;
    float bColor = 0.0;
public:
    Block() {
        this->setRandValues();
        xOffset += 1.0;
    }
    void moveX(float i)
    {
        xOffset += i * speedMultiplier;
        switch (gameMode) {
            case straightGame:
                // nothing to do
                break;
            case diagonalGame:
                yOffset += verticalMovement/10.0;
                break;
            case sinGame:
                yOffset = baseYOffset + sin(xOffset*10)*verticalMovement*30.0;
                break;
            case jitterGame:
                // 1/10 chance that it will change direction
                if (rand()%15 == 0) {
                    verticalMovement = -1 * verticalMovement;
                }
                yOffset = yOffset + 0.8*verticalMovement;

            default:
                break;
        }
    }
    void setRandValues()
    {
        baseYOffset = LITTLE_RAND * 2.0 - 1.0;
        yOffset = baseYOffset;
        xOffset = LITTLE_RAND * 3.0 - 3.0;
        size = LITTLE_RAND * 0.07 + 0.02;
        speedMultiplier = LITTLE_RAND * 0.5 + 0.8;
        verticalMovement = LITTLE_RAND * 0.01 - 0.005;
        rColor = LITTLE_RAND;
        gColor = LITTLE_RAND;
        bColor = LITTLE_RAND;
    }
    void draw()
    {
        // blocks recycle themselves when they go off screen
        if (xOffset > 1.09) {
            setRandValues();
            // if a block is reset, it has passed the player so the score is incremented
            score += 1;
        }
        glBegin(GL_POLYGON);
        glColor3d(rColor,gColor,bColor);
        glVertex2d(xOffset, yOffset + size);
        glVertex2d(xOffset - 0.8 * size, yOffset - size);
        glVertex2d(xOffset + 0.8 * size, yOffset - size);
        glEnd();
    }
    // takes as parameters the left upper corner of the player and the right lower, in order to calculate collisions
    bool hasCollided(float lx, float uy, float rx, float ly) {
        // checks if this block contains any of the 4 corners of the player
        if (selfContainsPoint(lx, uy) ||
            selfContainsPoint(lx, ly) ||
            selfContainsPoint(rx, uy) ||
            selfContainsPoint(rx, ly) ) {
            return true;
        }
        return false;
    }
private:
    bool selfContainsPoint(float x, float y)
    {
        // top vertice
        float xt = xOffset;
        float yt = yOffset + size;
        // bottom left vertice
        float xl = xOffset - 0.8 * size;
        float yl = yOffset - size;
        // bottom right vertice
        float xr = xOffset + 0.8 * size;
        float yr = yOffset - size;

        // slopes of the sides
        float mr = (yt-yr)/(xt-xr);
        float ml = (yt-yl)/(xt-xl); // or -1*mr for the current setup

        if (y < (mr*(x-xr) + yr) && // under the right side
            y < (ml*(x-xl) + yl) && // under the left side
            y > yr                  // over the bottom
            ) {
            return true;
        }
        return false;
    }
};

class Player {
public:
    float yOffset = 0.0;
    float death = 0.0;

    Player() {
        yOffset = ((double)arc4random() / ARC4RANDOM_MAX) * 1.5 - 0.5;
    }
    void stepUp() {
        if (yOffset < 0.91) { yOffset += STEP_SIZE; }
    }
    void stepDown() {
        if (yOffset > -0.91) { yOffset -= STEP_SIZE; }
    }
    void draw(float pos)
    {
        // turnary statements ensure that the player is within the bounds of the screen
        pos = pos > -1.0 ? pos : -1.0;
        yOffset = pos < 1.0 ? pos : 1.0;
        glBegin(GL_POLYGON);
        glColor3d(1.0, 0.1, 0.1);
        // upper right edge
        glVertex2d(0.90, yOffset + 0.4*PLAYER_SIZE);
        glVertex2d(0.95, yOffset + PLAYER_SIZE);
        // right inset
        glVertex2d(0.92, yOffset );
        // lower edge
        glVertex2d(0.95, yOffset - PLAYER_SIZE);
        glVertex2d(0.90, yOffset - 0.4*PLAYER_SIZE);
        glVertex2d(0.85, yOffset - PLAYER_SIZE);
        // upper left
        glVertex2d(0.88, yOffset );
        glVertex2d(0.85, yOffset + PLAYER_SIZE);
        glEnd();
    }
    void drawDeath(float pos) {

    }
};

//////////////////////////////
// global variables for game code
//////////////////////////////

bool showPlayer = false;
bool newPlayer = false;

bool alive = false;

float weightedMousePos = 0.0;
float curMousePos = 0.0;

float gameStart = 0;

Block *blocks[NUM_BLOCKS];

Player *player;

//////////////////////////////
// game actions
//////////////////////////////

void returnToLife( )
{
    if (alive) {
        return;
    }

    alive = true;
    score = 0;
    for (int i = 0; i < NUM_BLOCKS; i++) {
        blocks[i]->setRandValues();
        blocks[i]->moveX(0.5);
    }
}

//////////////////////////////
// drawing code
//////////////////////////////

void drawSelection( )
{
    for (int i = 1; i <= 4; i++) {
        // draw each of the blocks
    }
    glBegin(GL_POLYGON);

    glColor3d(0.0f, 0.0f, 0.0f);
    glVertex2d(-0.7, 0.3);
    glVertex2d(0.7, 0.3);
    glVertex2d(0.7, -0.3);
    glVertex2d(-0.7, -0.3);

    glEnd();

    char buf[BUFSIZ];
    char name[] = "Straight:1 Diagonal:2\n Sine:3 Jitter:4";

    snprintf(buf, sizeof(buf), "%s", name);

    //printf("chars: %s\n",buf);
    //int len = (int)strlen(buf);
    glColor3d(1.0f, 1.0f, 1.0f);
    glPushMatrix();
    glRasterPos2f(-0.55,0.0);
    for (char *p = buf; *p; p++)
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *p);
    glPopMatrix();
}

void drawGround( )
{
    glBegin(GL_POLYGON);

    if (alive) {
        glColor3d(0.9f, 0.7f, 0.3f);
    } else {
        glColor3d(0.9f, 0.1f, 0.3f);
    }
    glVertex2d(-1.0, -1.0);
    glColor3d(0.5f, 0.7f, 0.3f);
    for (int i = -10; i < 10; i++) {
        i%2 == 0 ? glVertex2d(0.1*i, -0.8) : glVertex2d(0.1*i, -0.5);
    }
    if (alive) {
        glColor3d(0.9f, 0.7f, 0.3f);
    } else {
        glColor3d(0.9f, 0.1f, 0.3f);
    }
    glVertex2d(1.0, -1.0);

    glEnd();
}

void drawScore( )
{
    char buf[BUFSIZ];
    char name[] = "Score";

    snprintf(buf, sizeof(buf), "%s: %08d", name, score);

    //printf("chars: %s\n",buf);
    //int len = (int)strlen(buf);
    glPushMatrix();
    glRasterPos2f(-0.97,0.9);
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    for (char *p = buf; *p; p++)
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *p);
    glPopMatrix();
}

//////////////////////////////
// callback functions
//////////////////////////////

void onReshape(int winWidth0, int winHeight0)
{
    glViewport(0, 0, winWidth0, winHeight0);
}

void onKeyboard(unsigned char key, int x, int y)
{
    // if the game is happening
    switch (key) {
            // restart the game
        case 'r':
            returnToLife();
            break;

            // pause the game
        case 'p':
            // do something helpful
            break;

        case '1':
            gameMode = straightGame;
            if (!alive) {
                returnToLife();
            }
            break;

        case '2':
            gameMode = diagonalGame;
            if (!alive) {
                returnToLife();
            }
            break;

        case '3':
            gameMode = sinGame;
            if (!alive) {
                returnToLife();
            }
            break;

        case '4':
            gameMode = jitterGame;
            if (!alive) {
                returnToLife();
            }
            break;

        default:
            break;
    }

    glutPostRedisplay();
}

// move player up and down based on keyboard input
void onMotion(int x, int y)
{
    int h = glutGet(GLUT_WINDOW_HEIGHT);
    curMousePos = -2.0 * (float)y / (float)h + 1.0;
    if (weightedMousePos == 0.0) {
        weightedMousePos = curMousePos;
    }
    weightedMousePos = ((weightedMousePos * (MOUSE_WEIGHT - 1)) + curMousePos) / MOUSE_WEIGHT;
    //printf("cur: %f\nscore: %i\n",curMousePos,score);
}

void onIdle()
{
    // time elapsed since program started, in seconds
    double cur_t = glutGet(GLUT_ELAPSED_TIME) * 0.001;

    // variable to remember last time idle was called
    static double lastTime = 0.0;
    // time difference between calls: time step
    double dt = cur_t - lastTime;
    // store time
    if (alive) {
        lastTime = cur_t;
    } else {
        lastTime = cur_t;
        gameStart = cur_t;
    }

    // base speed of 0.2 units/sec, increases as game progresses
    float inc = dt * 0.2 + 0.01 * (cur_t - gameStart);
    for (int i = 0; alive && i < NUM_BLOCKS; i++)
    {
        blocks[i]->moveX(dt * inc);
    }

    weightedMousePos = ((weightedMousePos * (MOUSE_WEIGHT - 1)) + curMousePos) / MOUSE_WEIGHT;

    // show
    glutPostRedisplay();
}

void onDisplay()
{
    // draw here
    glClearColor(0.4f, 0.7f, 0.9f, 0.5f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    drawGround();

    if (gameMode == selection) {
        // show
        drawSelection();

        glutSwapBuffers();
        return;
    }

    drawScore();

    for (int i = 0; i < NUM_BLOCKS; i++) {
        float px = 0.9;
        float py = player->yOffset;
        if (blocks[i]->hasCollided(px - PLAYER_SIZE, py + PLAYER_SIZE, px + PLAYER_SIZE, py - PLAYER_SIZE)) {
            alive = false;
        } else {
            blocks[i]->draw();
        }

    }
    player->draw(weightedMousePos);

    glutSwapBuffers();
}

//////////////////////////////
// main function, entry point to program
//////////////////////////////

int main(int argc, char *argv[]) {
    *blocks = new Block[NUM_BLOCKS];
    int i;
    Block * currentPointer;
    for (i = 0; i < NUM_BLOCKS; i++)
    {
        currentPointer = new Block();
        blocks[i] = currentPointer;
        //delete currentPointer;
    }

    player = new Player();

    glutInit(&argc, argv);
    glutInitWindowSize(640, 480);
    glutInitWindowPosition(100, 100);
    // rgb to specify color, double specifies two buffers, depth is 3d stuff
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("Dodge");

    // Register event handlers here
    glutDisplayFunc(onDisplay);
    glutReshapeFunc(onReshape);
    glutKeyboardFunc(onKeyboard);
    glutPassiveMotionFunc(onMotion);
    glutIdleFunc(onIdle);

    glutMainLoop();
    return 0;
}
<commit_msg>limited checks on collision to right quarter of the screen and added a silly little death animation<commit_after>//
//  main.cpp
//  class1
//
//  Created by Aaron Taylor on 9/11/14.
//  Copyright (c) 2014 Aaron Taylor. All rights reserved.
//

#define _USE_MATH_DEFINES
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
// Needed on MsWindows
#include <windows.h>
#endif // Win32 platform

#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
// Download glut from:
// http://www.opengl.org/resources/libraries/glut/
#include <GLUT/glut.h>

#define ARC4RANDOM_MAX 0x100000000
// random double between 0.0 and 1.0
#define LITTLE_RAND ((double)arc4random() / ARC4RANDOM_MAX)

//////////////////////////////
// game tuning parameters
//////////////////////////////

#define NUM_BLOCKS 45
#define STEP_SIZE 0.02
#define MOUSE_WEIGHT 25.0
#define PLAYER_SIZE 0.05
#define COLLISION_DIST 0.07

//////////////////////////////
// call back method definitions
//////////////////////////////

void onReshape(int winWidth0, int winHeight0);
void onKeyboard(unsigned char key, int x, int y);
void onMotion(int x, int y);
void onIdle();
void onDisplay();

//////////////////////////////
// global variables and types
//////////////////////////////

typedef enum{
    selection,
    straightGame,
    diagonalGame,
    sinGame,
    jitterGame
}mode;

mode gameMode = selection;

int score = 0;

//////////////////////////////
// game objects
//////////////////////////////

// objects coming across the screen that are to be avoided
// currently all triangles with randomized colors and sizes within set bounds
class Block {
    float baseYOffset = 0.5; // allows for centered behavior such as sine curves
    float yOffset = 0.5;
    float xOffset = -1.0;

    float size = 0.05;

    float speedMultiplier = 1.0;
    float verticalMovement = 0.0;

    float rColor = 0.0;
    float gColor = 0.0;
    float bColor = 0.0;
public:
    Block() {
        this->setRandValues();
        xOffset += 1.0;
    }
    void moveX(float i)
    {
        xOffset += i * speedMultiplier;
        switch (gameMode) {
            case straightGame:
                // nothing to do
                break;
            case diagonalGame:
                yOffset += verticalMovement/10.0;
                break;
            case sinGame:
                yOffset = baseYOffset + sin(xOffset*10)*verticalMovement*30.0;
                break;
            case jitterGame:
                // 1/10 chance that it will change direction
                if (rand()%15 == 0) {
                    verticalMovement = -1 * verticalMovement;
                }
                yOffset = yOffset + 0.8*verticalMovement;

            default:
                break;
        }
    }
    void setRandValues()
    {
        baseYOffset = LITTLE_RAND * 2.0 - 1.0;
        yOffset = baseYOffset;
        xOffset = LITTLE_RAND * 3.0 - 3.5;
        size = LITTLE_RAND * 0.07 + 0.02;
        speedMultiplier = LITTLE_RAND * 0.5 + 0.8;
        verticalMovement = LITTLE_RAND * 0.01 - 0.005;
        rColor = LITTLE_RAND;
        gColor = LITTLE_RAND;
        bColor = LITTLE_RAND;
    }
    void draw()
    {
        // blocks recycle themselves when they go off screen
        if (xOffset > 1.09) {
            setRandValues();
            // if a block is reset, it has passed the player so the score is incremented
            score += 1;
        }
        glBegin(GL_POLYGON);
        glColor3d(rColor,gColor,bColor);
        glVertex2d(xOffset, yOffset + size);
        glVertex2d(xOffset - 0.8 * size, yOffset - size);
        glVertex2d(xOffset + 0.8 * size, yOffset - size);
        glEnd();
    }
    // takes as parameters the left upper corner of the player and the right lower, in order to calculate collisions
    bool hasCollided(float lx, float uy, float rx, float ly) {
        if (xOffset < 0.75) {
            return false; // eliminates unnecessary calculations on blocks that could not contact player with a fixed x coordinate
        }
        // checks if this block contains any of the 4 corners of the player
        if (selfContainsPoint(lx, uy) ||
            selfContainsPoint(lx, ly) ||
            selfContainsPoint(rx, uy) ||
            selfContainsPoint(rx, ly) ) {
            return true;
        }
        return false;
    }
private:
    // determines whether or not the given point is within the bounds of the block (which is a triangle)
    bool selfContainsPoint(float x, float y)
    {
        // top vertice
        float xt = xOffset;
        float yt = yOffset + size;
        // bottom left vertice
        float xl = xOffset - 0.8 * size;
        float yl = yOffset - size;
        // bottom right vertice
        float xr = xOffset + 0.8 * size;
        float yr = yOffset - size;

        // slopes of the sides
        float mr = (yt-yr)/(xt-xr);
        float ml = (yt-yl)/(xt-xl); // or -1*mr for the current setup

        if (y < (mr*(x-xr) + yr) && // under the right side
            y < (ml*(x-xl) + yl) && // under the left side
            y > yr                  // over the bottom
            ) {
            return true;
        }
        return false;
    }
};

// the icon for the player in a start shape
class Player {
public:
    float yOffset = 0.0;
    float death = 0.0;

    Player() {
        yOffset = ((double)arc4random() / ARC4RANDOM_MAX) * 1.5 - 0.5;
    }
    void stepUp() {
        if (yOffset < 0.91) { yOffset += STEP_SIZE; }
    }
    void stepDown() {
        if (yOffset > -0.91) { yOffset -= STEP_SIZE; }
    }
    void draw(float pos)
    {
        // turnary statements ensure that the player is within the bounds of the screen
        pos = pos > -1.0 ? pos : -1.0;
        yOffset = pos < 1.0 ? pos : 1.0;
        glBegin(GL_POLYGON);
        glColor3d(1.0, 0.1, 0.1);
        // upper right edge
        glVertex2d(0.90, yOffset + 0.4*PLAYER_SIZE);
        glVertex2d(0.95, yOffset + PLAYER_SIZE);
        // right inset
        glVertex2d(0.92, yOffset );
        // lower edge
        glVertex2d(0.95, yOffset - PLAYER_SIZE);
        glVertex2d(0.90, yOffset - 0.4*PLAYER_SIZE);
        glVertex2d(0.85, yOffset - PLAYER_SIZE);
        // upper left
        glVertex2d(0.88, yOffset );
        glVertex2d(0.85, yOffset + PLAYER_SIZE);
        glEnd();
    }
    void drawDeath(float pos, float t) {
        float tdiv = ((1.0 + t)*1.05);

        glBegin(GL_POLYGON);
        glColor3d(1.0, 0.5, 0.0);
        float backScale = 0.06 - 0.06/tdiv;
        glVertex2d(0.90, yOffset + backScale);
        glVertex2d(0.90 + backScale, yOffset);
        glVertex2d(0.90, yOffset - backScale);
        glVertex2d(0.90 - backScale, yOffset);
        glEnd();

        // original shape shrinks and goes to black
        glBegin(GL_POLYGON);
        glColor3d(1.0 / tdiv, 0.1, 0.1);
        // upper right edge
        glVertex2d(0.90, yOffset + (0.4/tdiv)*PLAYER_SIZE);
        glVertex2d(0.95, yOffset + PLAYER_SIZE);
        // right inset
        glVertex2d(0.92, yOffset );
        // lower edge
        glVertex2d(0.95, yOffset - PLAYER_SIZE);
        glVertex2d(0.90, yOffset - (0.4/tdiv)*PLAYER_SIZE);
        glVertex2d(0.85, yOffset - PLAYER_SIZE);
        // upper left
        glVertex2d(0.88, yOffset );
        glVertex2d(0.85, yOffset + PLAYER_SIZE);
        glEnd();
    }
};

//////////////////////////////
// global variables for game code
//////////////////////////////

bool showPlayer = false;
bool newPlayer = false;

bool alive = false;

float weightedMousePos = 0.0;
float curMousePos = 0.0;

float gameStart = 0.0;
float deathTime = 0.0;

Block *blocks[NUM_BLOCKS];

Player *player;

//////////////////////////////
// game actions
//////////////////////////////

void returnToLife( )
{
    if (alive) {
        return;
    }

    alive = true;
    score = 0;
    for (int i = 0; i < NUM_BLOCKS; i++) {
        blocks[i]->setRandValues();
        blocks[i]->moveX(0.5);
    }
}

//////////////////////////////
// drawing code
//////////////////////////////

void drawSelection( )
{
    for (int i = 1; i <= 4; i++) {
        // draw each of the blocks
    }
    glBegin(GL_POLYGON);

    glColor3d(0.0f, 0.0f, 0.0f);
    glVertex2d(-0.7, 0.3);
    glVertex2d(0.7, 0.3);
    glVertex2d(0.7, -0.3);
    glVertex2d(-0.7, -0.3);

    glEnd();

    char buf[BUFSIZ];
    char name[] = "Straight:1 Diagonal:2\n Sine:3 Jitter:4";

    snprintf(buf, sizeof(buf), "%s", name);

    //printf("chars: %s\n",buf);
    //int len = (int)strlen(buf);
    glColor3d(1.0f, 1.0f, 1.0f);
    glPushMatrix();
    glRasterPos2f(-0.55,0.0);
    for (char *p = buf; *p; p++)
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *p);
    glPopMatrix();
}

void drawGround( )
{
    glBegin(GL_POLYGON);

    if (alive) {
        glColor3d(0.9f, 0.7f, 0.3f);
    } else {
        glColor3d(0.9f, 0.1f, 0.3f);
    }
    glVertex2d(-1.0, -1.0);
    glColor3d(0.5f, 0.7f, 0.3f);
    for (int i = -10; i < 10; i++) {
        i%2 == 0 ? glVertex2d(0.1*i, -0.8) : glVertex2d(0.1*i, -0.5);
    }
    if (alive) {
        glColor3d(0.9f, 0.7f, 0.3f);
    } else {
        glColor3d(0.9f, 0.1f, 0.3f);
    }
    glVertex2d(1.0, -1.0);

    glEnd();
}

void drawScore( )
{
    char buf[BUFSIZ];
    char name[] = "Score";

    snprintf(buf, sizeof(buf), "%s: %08d", name, score);

    //printf("chars: %s\n",buf);
    //int len = (int)strlen(buf);
    glPushMatrix();
    glRasterPos2f(-0.97,0.9);
    glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
    for (char *p = buf; *p; p++)
        glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *p);
    glPopMatrix();
}

//////////////////////////////
// callback functions
//////////////////////////////

void onReshape(int winWidth0, int winHeight0)
{
    glViewport(0, 0, winWidth0, winHeight0);
}

void onKeyboard(unsigned char key, int x, int y)
{
    // if the game is happening
    switch (key) {
            // restart the game
        case 'r':
            returnToLife();
            break;

            // pause the game
        case 'p':
            // do something helpful
            break;

        case '1':
            gameMode = straightGame;
            if (!alive) {
                returnToLife();
            }
            break;

        case '2':
            gameMode = diagonalGame;
            if (!alive) {
                returnToLife();
            }
            break;

        case '3':
            gameMode = sinGame;
            if (!alive) {
                returnToLife();
            }
            break;

        case '4':
            gameMode = jitterGame;
            if (!alive) {
                returnToLife();
            }
            break;

        default:
            break;
    }

    glutPostRedisplay();
}

// move player up and down based on keyboard input
void onMotion(int x, int y)
{
    int h = glutGet(GLUT_WINDOW_HEIGHT);
    curMousePos = -2.0 * (float)y / (float)h + 1.0;
    if (weightedMousePos == 0.0) {
        weightedMousePos = curMousePos;
    }
    weightedMousePos = ((weightedMousePos * (MOUSE_WEIGHT - 1)) + curMousePos) / MOUSE_WEIGHT;
    //printf("cur: %f\nscore: %i\n",curMousePos,score);
}

void onIdle()
{
    // time elapsed since program started, in seconds
    double cur_t = glutGet(GLUT_ELAPSED_TIME) * 0.001;

    // variable to remember last time idle was called
    static double lastTime = 0.0;
    // time difference between calls: time step
    double dt = cur_t - lastTime;
    // store time
    if (alive) {
        lastTime = cur_t;
    } else {
        lastTime = cur_t;
        gameStart = cur_t;
    }

    // base speed of 0.2 units/sec, increases as game progresses
    float inc = dt * 0.2 + 0.01 * (cur_t - gameStart);
    for (int i = 0; alive && i < NUM_BLOCKS; i++)
    {
        blocks[i]->moveX(dt * inc);
    }

    weightedMousePos = ((weightedMousePos * (MOUSE_WEIGHT - 1)) + curMousePos) / MOUSE_WEIGHT;

    // show
    glutPostRedisplay();
}

void onDisplay()
{
    // draw here
    glClearColor(0.4f, 0.7f, 0.9f, 0.5f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    drawGround();

    if (gameMode == selection) {
        // show
        drawSelection();

        glutSwapBuffers();
        return;
    }

    drawScore();

    for (int i = 0; i < NUM_BLOCKS; i++) {
        float px = 0.9;
        float py = player->yOffset;
        if (blocks[i]->hasCollided(px - PLAYER_SIZE, py + PLAYER_SIZE, px + PLAYER_SIZE, py - PLAYER_SIZE)) {
            if (alive) {
                alive = false;
                deathTime = glutGet(GLUT_ELAPSED_TIME) * 0.001;
            }
        } else {
            blocks[i]->draw();
        }

    }
    if (alive) {
        player->draw(weightedMousePos);
    } else {
        float t_death = glutGet(GLUT_ELAPSED_TIME) * 0.001 - deathTime;
        player->drawDeath(weightedMousePos, t_death);
    }

    glutSwapBuffers();
}

//////////////////////////////
// main function, entry point to program
//////////////////////////////

int main(int argc, char *argv[]) {
    *blocks = new Block[NUM_BLOCKS];
    int i;
    Block * currentPointer;
    for (i = 0; i < NUM_BLOCKS; i++)
    {
        currentPointer = new Block();
        blocks[i] = currentPointer;
        //delete currentPointer;
    }

    player = new Player();

    glutInit(&argc, argv);
    glutInitWindowSize(640, 480);
    glutInitWindowPosition(100, 100);
    // rgb to specify color, double specifies two buffers, depth is 3d stuff
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);

    glutCreateWindow("Dodge");

    // Register event handlers here
    glutDisplayFunc(onDisplay);
    glutReshapeFunc(onReshape);
    glutKeyboardFunc(onKeyboard);
    glutPassiveMotionFunc(onMotion);
    glutIdleFunc(onIdle);

    glutMainLoop();
    return 0;
}
<|endoftext|>


<commit_before>#include "EngineUI.hpp"

#include "Application.hpp"

namespace Engine {
    namespace EngineUI {
        std::stringstream ss;

        std::stringstream currentConsoleInput;

        bool _active = true;
        bool _showConsole = false;

        char getSpecialChars(int key) {
            switch (key) {
                case '[':       return '{';
                case ']':       return '}';
                case '-':       return '_';
                case '=':       return '+';
                case '\\':      return '|';
                case '`':       return '~';
                case '1':       return '!';
                case '2':       return '@';
                case '3':       return '#';
                case '4':       return '$';
                case '5':       return '%';
                case '6':       return '^';
                case '7':       return '&';
                case '8':       return '*';
                case '9':       return '(';
                case '0':       return ')';
                case ',':       return '<';
                case '.':       return '>';
                case ';':       return ':';
                case '\'':      return '"';
                case '/':       return '?';
                default:        return key;
            }
        }

        // just temporey until the profiler has this built in
        float lastDrawTimes[100];
        int currentLastDrawTimePos = 0;

        float fpsTimer = 0.0f;
        float currentFPS = 0;

        std::vector<std::string> commandHistory;
        size_t currentHistoryLine = 0;

        void Draw() {
            if (!Config::GetBoolean("core.debug.engineUI")) {
                return;
            }

            Application* app = GetAppSingilton();

            if (!_showConsole) {
                Draw2D::SetColor(25 / 255.0f, 25 / 255.0f, 25 / 255.0f);
            } else {
                Draw2D::SetColor(40 / 255.0f, 40 / 255.0f, 40 / 255.0f, 0.95f);
            }

            Draw2D::Rect(0.0f, 0.0f, app->GetScreenWidth(), _showConsole ? app->GetScreenHeight() : 14);

            Draw2D::SetFont("basic", 10);
            if (!_showConsole) {
                Draw2D::SetColor(220 / 255.0f, 220 / 255.0f, 220 / 255.0f);
            } else {
                Draw2D::SetColor(1.0f, 1.0f, 1.0f);
            }

            double drawTime = Profiler::GetTime("Draw");
            lastDrawTimes[currentLastDrawTimePos++] = drawTime;
            if (currentLastDrawTimePos > 100) {
                currentLastDrawTimePos = 0;
            }

            float fps = 1000 / (Profiler::GetTime("Frame") * 1000);

            fpsTimer += Profiler::GetTime("Frame");

            if (fpsTimer > 0.1f) {
                currentFPS = glm::floor(fps);
                fpsTimer = 0;
            }

            Draw2D::Print(10, 4, "-- Engine2D --");
            ss.str("");
            ss.precision(4);
            ss << "FPS: " << currentFPS;
            ss << " | DrawTime: " << drawTime;
            Draw2D::Print(app->GetScreenWidth() - 220, 4, ss.str().c_str());

            Draw2D::DisableSmooth();

            Draw2D::LineGraph(app->GetScreenWidth() - 430, 14, 2, 200, lastDrawTimes, 100);

            Draw2D::EnableSmooth();

            if (!_showConsole) {
                return;
            }

            std::vector<Logger::LogEvent>* logEvents = Logger::GetEvents();

            bool showVerbose = Config::GetBoolean("core.debug.engineUI.showVerboseLog"); // pretty cheap

            int i = app->GetScreenHeight() - 40;

            for (auto iterator = logEvents->rbegin(); iterator < logEvents->rend(); iterator++) {
                if (iterator->Hidden) {
                    continue; // don't show it if it's hidden
                }

                if (iterator->Type == Logger::LogType_Text) {
                    if (iterator->Level == Logger::LogLevel_Verbose && !showVerbose) {
                        i -= 6; // add some padding to show that a message is there, just hidden
                        Draw2D::SetColor(80 / 255.0f, 80 / 255.0f, 80 / 255.0f);
                        Draw2D::Rect(0, i + 2, app->GetScreenWidth(), 2);
                    } else {
                        i -= 22;
                        Draw2D::SetColor(30 / 255.0f, 30 / 255.0f, 30 / 255.0f, 0.9f);
                        Draw2D::Rect(60, i + 1, app->GetScreenWidth() - 60, 20);
                    }
                }

                switch (iterator->Level) {
                    case Logger::LogLevel_Verbose:
                        Draw2D::SetColor(205 / 255.0f, 205 / 255.0f, 205 / 255.0f);
                        break;
                    case Logger::LogLevel_User:
                        Draw2D::SetColor(255 / 255.0f, 0 / 255.0f, 255 / 255.0f);
                        break;
                    case Logger::LogLevel_ConsoleInput:
                        Draw2D::SetColor(0 / 255.0f, 191 / 255.0f, 255 / 255.0f);
                        break;
                    case Logger::LogLevel_Log:
                        Draw2D::SetColor(250 / 255.0f, 250 / 255.0f, 250 / 255.0f);
                        break;
                    case Logger::LogLevel_Warning:
                        Draw2D::SetColor(255 / 255.0f, 165 / 255.0f, 0 / 255.0f);
                        break;
                    case Logger::LogLevel_Error:
                        Draw2D::SetColor(178 / 255.0f, 34 / 255.0f, 34 / 255.0f);
                        break;
                    case Logger::LogLevel_TestLog:
                        Draw2D::SetColor(250 / 255.0f, 250 / 255.0f, 250 / 255.0f);
                        break;
                    case Logger::LogLevel_TestError:
                        Draw2D::SetColor(178 / 255.0f, 34 / 255.0f, 34 / 255.0f);
                        break;
                }

                std::string time = std::to_string(iterator->time);
                time.resize(6, '0');

                if (iterator->Level != Logger::LogLevel_Verbose || showVerbose) {
                    Draw2D::Print(5, i + 7, (time + "s").c_str());
                }

                if (iterator->Level != Logger::LogLevel_Verbose || showVerbose) {
                    if (iterator->Type == Logger::LogType_Text) {
                        Draw2D::Print(65, i + 7, iterator->Event.c_str());
                    } else if (iterator->Type == Logger::LogType_Graphical) {
                        i -= (*iterator->GraphEvent)(65, i);
                    }
                }

                if (i < 35) {
                    break;
                }
            }

            Draw2D::SetColor(0.0f, 0.0f, 0.0f, 0.85f);
            Draw2D::Rect(5, app->GetScreenHeight() - 30, app->GetScreenWidth() - 10, 25);

            Draw2D::SetColor(1.0f, 1.0f, 1.0f);
            Draw2D::SetFont("basic", 12);
            Draw2D::Print(10, app->GetScreenHeight() - 22, (currentConsoleInput.str() + "_").c_str());
        }

#ifndef _PLATFORM_WIN32
#define KEY_CONSOLE 161
#else
#define KEY_CONSOLE 96
#endif

        void OnKeyPress(int key, int press, bool shift) {
            if (!Config::GetBoolean("core.debug.engineUI")) {
                return;
            }

            Application* app = GetAppSingilton();

			if (key == KEY_CONSOLE && press == GLFW_PRESS) { // `
                ToggleConsole();
			} else if (key == GLFW_KEY_F10 && press == GLFW_PRESS) { // f10
				app->DumpProfile();
            }

            if (!_showConsole) {
                return;
            }

			if (key < 256 && (press == GLFW_PRESS || press == GLFW_REPEAT) && key != KEY_CONSOLE && key != GLFW_KEY_ENTER) {
#ifndef _PLATFORM_WIN32
				currentConsoleInput << (char) (shift ? getSpecialChars(key) : (char) std::tolower(key));
#else
				currentConsoleInput << (char) (shift ? getSpecialChars(key) : tolower(key));
#endif
            } else if (key == GLFW_KEY_BACKSPACE && (press == GLFW_PRESS || press == GLFW_REPEAT)) {
                std::string str = currentConsoleInput.str();
                if (str.length() > 0) {
                    str.resize(str.length() - 1);
                    currentConsoleInput.str(str);
					if (str.length() != 0) {
						currentConsoleInput.seekp(str.length());
					}
                }
            } else if (key == GLFW_KEY_UP && press == GLFW_PRESS) {
                if (currentHistoryLine > 0) {
                    currentHistoryLine--;
                    currentConsoleInput.str(commandHistory[currentHistoryLine]);
                    if (currentConsoleInput.str().length() != 0) {
                        currentConsoleInput.seekp(currentConsoleInput.str().length());
                    }
                }
            } else if (key == GLFW_KEY_DOWN && press == GLFW_PRESS) {
                if (commandHistory.size() > 0 && currentHistoryLine < commandHistory.size() - 1) {
                    currentHistoryLine++;
                    currentConsoleInput.str(commandHistory[currentHistoryLine]);
                    if (currentConsoleInput.str().length() != 0) {
                        currentConsoleInput.seekp(currentConsoleInput.str().length());
                    }
                }
            } else if (key == GLFW_KEY_ENTER && press == GLFW_PRESS) {
                std::string command = currentConsoleInput.str();
                app->RunCommand(command);
                if (commandHistory.size() == 0 || commandHistory[commandHistory.size() - 1] != command) {
                    commandHistory.push_back(command);
                }
                currentHistoryLine = commandHistory.size();
                currentConsoleInput.str("");
            }
        }

        void SetActive(bool active) {
            _active = active;
        }

        void ToggleConsole() {
            _showConsole = !_showConsole;
        }

        void ClearConsole() {
            Logger::HideAllEvents();
        }

        bool ConsoleActive() {
            return _showConsole;
        }
    }
}<commit_msg>Fixed EngineUI crashing the Engine if the profiler is disabled<commit_after>#include "EngineUI.hpp"

#include "Application.hpp"

namespace Engine {
    namespace EngineUI {
        std::stringstream ss;

        std::stringstream currentConsoleInput;

        bool _active = true;
        bool _showConsole = false;

        char getSpecialChars(int key) {
            switch (key) {
                case '[':       return '{';
                case ']':       return '}';
                case '-':       return '_';
                case '=':       return '+';
                case '\\':      return '|';
                case '`':       return '~';
                case '1':       return '!';
                case '2':       return '@';
                case '3':       return '#';
                case '4':       return '$';
                case '5':       return '%';
                case '6':       return '^';
                case '7':       return '&';
                case '8':       return '*';
                case '9':       return '(';
                case '0':       return ')';
                case ',':       return '<';
                case '.':       return '>';
                case ';':       return ':';
                case '\'':      return '"';
                case '/':       return '?';
                default:        return key;
            }
        }

        // just temporey until the profiler has this built in
        float lastDrawTimes[100];
        int currentLastDrawTimePos = 0;

        float fpsTimer = 0.0f;
        float currentFPS = 0;

        std::vector<std::string> commandHistory;
        size_t currentHistoryLine = 0;

        void Draw() {
            if (!Config::GetBoolean("core.debug.engineUI")) {
                return;
            }

            Application* app = GetAppSingilton();

            if (!_showConsole) {
                Draw2D::SetColor(25 / 255.0f, 25 / 255.0f, 25 / 255.0f);
            } else {
                Draw2D::SetColor(40 / 255.0f, 40 / 255.0f, 40 / 255.0f, 0.95f);
            }

            Draw2D::Rect(0.0f, 0.0f, app->GetScreenWidth(), _showConsole ? app->GetScreenHeight() : 14);

            Draw2D::SetFont("basic", 10);
            if (!_showConsole) {
                Draw2D::SetColor(220 / 255.0f, 220 / 255.0f, 220 / 255.0f);
            } else {
                Draw2D::SetColor(1.0f, 1.0f, 1.0f);
            }

            if (Config::GetBoolean("core.debug.profiler")) {
                double drawTime = Profiler::GetTime("Draw");
                lastDrawTimes[currentLastDrawTimePos++] = drawTime;
                if (currentLastDrawTimePos > 100) {
                    currentLastDrawTimePos = 0;
                }

                float fps = 1000 / (Profiler::GetTime("Frame") * 1000);

                fpsTimer += Profiler::GetTime("Frame");

                if (fpsTimer > 0.1f) {
                    currentFPS = glm::floor(fps);
                    fpsTimer = 0;
                }

                ss.str("");
                ss.precision(4);
                ss << "FPS: " << currentFPS;
                ss << " | DrawTime: " << drawTime;
                Draw2D::Print(app->GetScreenWidth() - 220, 4, ss.str().c_str());

                Draw2D::DisableSmooth();

                Draw2D::LineGraph(app->GetScreenWidth() - 430, 14, 2, 200, lastDrawTimes, 100);

                Draw2D::EnableSmooth();
            }

            Draw2D::Print(10, 4, "-- Engine2D --");

            if (!_showConsole) {
                return;
            }

            std::vector<Logger::LogEvent>* logEvents = Logger::GetEvents();

            bool showVerbose = Config::GetBoolean("core.debug.engineUI.showVerboseLog"); // pretty cheap

            int i = app->GetScreenHeight() - 40;

            for (auto iterator = logEvents->rbegin(); iterator < logEvents->rend(); iterator++) {
                if (iterator->Hidden) {
                    continue; // don't show it if it's hidden
                }

                if (iterator->Type == Logger::LogType_Text) {
                    if (iterator->Level == Logger::LogLevel_Verbose && !showVerbose) {
                        i -= 6; // add some padding to show that a message is there, just hidden
                        Draw2D::SetColor(80 / 255.0f, 80 / 255.0f, 80 / 255.0f);
                        Draw2D::Rect(0, i + 2, app->GetScreenWidth(), 2);
                    } else {
                        i -= 22;
                        Draw2D::SetColor(30 / 255.0f, 30 / 255.0f, 30 / 255.0f, 0.9f);
                        Draw2D::Rect(60, i + 1, app->GetScreenWidth() - 60, 20);
                    }
                }

                switch (iterator->Level) {
                    case Logger::LogLevel_Verbose:
                        Draw2D::SetColor(205 / 255.0f, 205 / 255.0f, 205 / 255.0f);
                        break;
                    case Logger::LogLevel_User:
                        Draw2D::SetColor(255 / 255.0f, 0 / 255.0f, 255 / 255.0f);
                        break;
                    case Logger::LogLevel_ConsoleInput:
                        Draw2D::SetColor(0 / 255.0f, 191 / 255.0f, 255 / 255.0f);
                        break;
                    case Logger::LogLevel_Log:
                        Draw2D::SetColor(250 / 255.0f, 250 / 255.0f, 250 / 255.0f);
                        break;
                    case Logger::LogLevel_Warning:
                        Draw2D::SetColor(255 / 255.0f, 165 / 255.0f, 0 / 255.0f);
                        break;
                    case Logger::LogLevel_Error:
                        Draw2D::SetColor(178 / 255.0f, 34 / 255.0f, 34 / 255.0f);
                        break;
                    case Logger::LogLevel_TestLog:
                        Draw2D::SetColor(250 / 255.0f, 250 / 255.0f, 250 / 255.0f);
                        break;
                    case Logger::LogLevel_TestError:
                        Draw2D::SetColor(178 / 255.0f, 34 / 255.0f, 34 / 255.0f);
                        break;
                }

                std::string time = std::to_string(iterator->time);
                time.resize(6, '0');

                if (iterator->Level != Logger::LogLevel_Verbose || showVerbose) {
                    Draw2D::Print(5, i + 7, (time + "s").c_str());
                }

                if (iterator->Level != Logger::LogLevel_Verbose || showVerbose) {
                    if (iterator->Type == Logger::LogType_Text) {
                        Draw2D::Print(65, i + 7, iterator->Event.c_str());
                    } else if (iterator->Type == Logger::LogType_Graphical) {
                        i -= (*iterator->GraphEvent)(65, i);
                    }
                }

                if (i < 35) {
                    break;
                }
            }

            Draw2D::SetColor(0.0f, 0.0f, 0.0f, 0.85f);
            Draw2D::Rect(5, app->GetScreenHeight() - 30, app->GetScreenWidth() - 10, 25);

            Draw2D::SetColor(1.0f, 1.0f, 1.0f);
            Draw2D::SetFont("basic", 12);
            Draw2D::Print(10, app->GetScreenHeight() - 22, (currentConsoleInput.str() + "_").c_str());
        }

#ifndef _PLATFORM_WIN32
#define KEY_CONSOLE 161
#else
#define KEY_CONSOLE 96
#endif

        void OnKeyPress(int key, int press, bool shift) {
            if (!Config::GetBoolean("core.debug.engineUI")) {
                return;
            }

            Application* app = GetAppSingilton();

			if (key == KEY_CONSOLE && press == GLFW_PRESS) { // `
                ToggleConsole();
			} else if (key == GLFW_KEY_F10 && press == GLFW_PRESS) { // f10
				app->DumpProfile();
            }

            if (!_showConsole) {
                return;
            }

			if (key < 256 && (press == GLFW_PRESS || press == GLFW_REPEAT) && key != KEY_CONSOLE && key != GLFW_KEY_ENTER) {
#ifndef _PLATFORM_WIN32
				currentConsoleInput << (char) (shift ? getSpecialChars(key) : (char) std::tolower(key));
#else
				currentConsoleInput << (char) (shift ? getSpecialChars(key) : tolower(key));
#endif
            } else if (key == GLFW_KEY_BACKSPACE && (press == GLFW_PRESS || press == GLFW_REPEAT)) {
                std::string str = currentConsoleInput.str();
                if (str.length() > 0) {
                    str.resize(str.length() - 1);
                    currentConsoleInput.str(str);
					if (str.length() != 0) {
						currentConsoleInput.seekp(str.length());
					}
                }
            } else if (key == GLFW_KEY_UP && press == GLFW_PRESS) {
                if (currentHistoryLine > 0) {
                    currentHistoryLine--;
                    currentConsoleInput.str(commandHistory[currentHistoryLine]);
                    if (currentConsoleInput.str().length() != 0) {
                        currentConsoleInput.seekp(currentConsoleInput.str().length());
                    }
                }
            } else if (key == GLFW_KEY_DOWN && press == GLFW_PRESS) {
                if (commandHistory.size() > 0 && currentHistoryLine < commandHistory.size() - 1) {
                    currentHistoryLine++;
                    currentConsoleInput.str(commandHistory[currentHistoryLine]);
                    if (currentConsoleInput.str().length() != 0) {
                        currentConsoleInput.seekp(currentConsoleInput.str().length());
                    }
                }
            } else if (key == GLFW_KEY_ENTER && press == GLFW_PRESS) {
                std::string command = currentConsoleInput.str();
                app->RunCommand(command);
                if (commandHistory.size() == 0 || commandHistory[commandHistory.size() - 1] != command) {
                    commandHistory.push_back(command);
                }
                currentHistoryLine = commandHistory.size();
                currentConsoleInput.str("");
            }
        }

        void SetActive(bool active) {
            _active = active;
        }

        void ToggleConsole() {
            _showConsole = !_showConsole;
        }

        void ClearConsole() {
            Logger::HideAllEvents();
        }

        bool ConsoleActive() {
            return _showConsole;
        }
    }
}<|endoftext|>