the whole game

This commit is contained in:
Kolyah35
2026-03-02 22:04:18 +03:00
parent 816e9060b4
commit f0617a5d22
2069 changed files with 581500 additions and 0 deletions

17
src/util/CollectionUtils.h Executable file
View File

@@ -0,0 +1,17 @@
#ifndef COLLECTIONUTILS_H__
#define COLLECTIONUTILS_H__
struct PairKeyFunctor {
template <typename T>
typename T::first_type operator()(T& pair) const {
return pair.first;
}
};
struct PairValueFunctor {
template <typename T>
typename T::second_type operator()(T& pair) const {
return pair.second;
}
};
#endif /*COLLECTIONUTILS_H__*/

29
src/util/DataIO.cpp Executable file
View File

@@ -0,0 +1,29 @@
#include "DataIO.h"
//
// BytesDataOutput
//
void BytesDataOutput::writeString( const std::string& v )
{
int length = v.length() & 0x7fff;
writeShort(length);
writeBytes(v.c_str(), length);
//LOGI("Writing: %d bytes as String: %s\n", v.length(), v.c_str());
}
//
// BytesDataInput
//
std::string BytesDataInput::readString() {
int len = readShort();
if (len > MAX_STRING_LENGTH - 1)
len = MAX_STRING_LENGTH - 1;
char* buffer = new char[len + 1];
readBytes(buffer, len);
buffer[len] = 0;
std::string out(buffer);
delete[] buffer;
return out;
}

320
src/util/DataIO.h Executable file
View File

@@ -0,0 +1,320 @@
#ifndef DATAIO_H__
#define DATAIO_H__
#include <cstring>
#include <string>
#include <climits>
#include "../platform/log.h"
// Interface for writing primitives to a stream
class IDataOutput {
public:
virtual ~IDataOutput() {}
// Write a "Pascal" string [Len(Short)][Characters, len={strlen()-1,s.length()}]
//virtual void writePStr(const char* v, int len = -1) = 0;
//virtual void writeCStr(const char* v, int len = -1) = 0;
virtual void writeString(const std::string& v) = 0;
virtual void writeFloat(float v) = 0;
virtual void writeDouble(double v) = 0;
virtual void writeByte(char v) = 0;
virtual void writeShort(short v) = 0;
virtual void writeInt(int v) = 0;
virtual void writeLongLong(long long v) = 0;
virtual void writeBytes(const void* data, int bytes) = 0;
};
// Interface for reading primitives from a stream
class IDataInput {
public:
virtual ~IDataInput() {}
virtual std::string readString() = 0;
//virtual void readPStr(char**) = 0;
//virtual void readCStr(char** s, int len = -1) = 0;
virtual float readFloat() = 0;
virtual double readDouble() = 0;
virtual char readByte() = 0;
virtual short readShort() = 0;
virtual int readInt() = 0;
virtual long long readLongLong() = 0;
virtual void readBytes(void* data, int bytes) = 0;
};
/**
* Redirects all calls to writeBytes
*/
class BytesDataOutput: public IDataOutput {
public:
//virtual void writePStr(const char* v, int len = -1);
//virtual void writeCStr(const char* v, int len = -1);
virtual void writeString(const std::string& v);
virtual void writeFloat(float v) {
writeBytes(&v, 4);
}
virtual void writeDouble(double v) {
writeBytes(&v, 8);
}
virtual void writeByte(char v) {
writeBytes(&v, 1);
}
virtual void writeShort(short v) {
writeBytes(&v, 2);
}
virtual void writeInt(int v) {
writeBytes(&v, 4);
}
virtual void writeLongLong(long long v) {
writeBytes(&v, 8);
}
virtual void writeBytes(const void* data, int bytes) = 0;
};
/**
* Redirects all calls to readBytes
*/
class BytesDataInput: public IDataInput {
public:
//virtual void readPStr(char** s);
//virtual void readCStr(char* s, int len = -1);
virtual std::string readString();
virtual float readFloat() {
float o;
readBytes(&o, 4);
return o;
}
virtual double readDouble() {
double o;
readBytes(&o, 8);
return o;
}
virtual char readByte() {
char o;
readBytes(&o, 1);
return o;
}
virtual short readShort() {
short o;
readBytes(&o, 2);
return o;
}
virtual int readInt() {
int o;
readBytes(&o, 4);
return o;
}
virtual long long readLongLong() {
long long o;
readBytes(&o, 8);
return o;
}
virtual void readBytes(void* data, int bytes) = 0;
private:
static const int MAX_STRING_LENGTH = SHRT_MAX;
static char _charBuffer[MAX_STRING_LENGTH];
};
//class MemoryDataInput: public BytesDataInput {
//public:
// MemoryDataInput(const char* data, int size)
// : _buffer(data),
// _size(size),
// _index(0)
// {}
// MemoryDataInput(const unsigned char* data, int size)
// : _buffer((const char*)data),
// _size(size),
// _index(0)
// {}
//
// void readBytes(void* data, int bytes) {
// if (bytes <= 0) {
// if (bytes < 0) LOGE("Error: %d bytes NOT read @ MemoryDataInput::readBytes!\n", bytes);
// return;
// }
// int left = _size - _index;
// if (bytes > left) {
// LOGE("ERROR: Not enough bytes left in buffer @ MemoryDataInput::readBytes (%d/%d).\n", bytes, left);
// _index = _size;
// return;
// }
// memcpy((char*)data, &_buffer[_index], bytes);
// _index += bytes;
// }
//
//private:
// int _index;
// int _size;
// const char* _buffer;
//};
//
//
//class MemoryDataOutput: public BytesDataOutput {
//public:
// MemoryDataOutput(char* data, int size)
// : _buffer(data),
// _size(size),
// _index(0)
// {}
// MemoryDataOutput(unsigned char* data, int size)
// : _buffer((char*)data),
// _size(size),
// _index(0)
// {}
//
// void writeBytes(const void* data, int bytes) {
// if (bytes <= 0) {
// LOGW("Warning: %d bytes read @ MemoryDataOutput::writeBytes!\n", bytes);
// return;
// }
// int left = _size - _index;
// if (bytes > left) {
// LOGE("ERROR: Not enough bytes left in buffer @ MemoryDataOutput::writeBytes (%d/%d).\n", bytes, left);
// _index = _size;
// return;
// }
// memcpy(&_buffer[_index], (const char*)data, bytes);
// _index += bytes;
// }
//
//private:
// int _index;
// int _size;
// char* _buffer;
//};
class PrintStream {
public:
void print(const std::string& s) {
}
void println(const std::string& s) {
print(s); print("\n");
}
};
class FileError {
public:
static const int NOT_OPENED = 1;
static const int NOT_FULLY_HANDLED = 2;
};
//
//class FileIO {
//public:
// FileIO(const std::string& filePath, const char* mode)
// : _filePath(filePath),
// _opened(false),
// _errCode(0),
// _fp(0),
// _doClose(true)
// {
// if (mode)
// openWithMode(mode);
// }
// FileIO(FILE* fp)
// : _filePath("<fp>"),
// _opened(fp != NULL),
// _errCode(0),
// _fp(fp),
// _doClose(false)
// {}
//
// ~FileIO() {
// if (_doClose)
// close();
// }
//
// bool isValid() {
// return _opened;
// }
//
// int getError() {
// int err = _errCode;
// _errCode = 0;
// return err;
// }
//
// bool close() {
// if (!_fp)
// return false;
//
// fclose(_fp);
// _fp = NULL;
// _opened = false;
// return true;
// }
//
//protected:
// void openWithMode(const char* mode) {
// if (_fp) return;
// _fp = fopen(_filePath.c_str(), mode);
// _opened = (_fp != NULL);
// }
//
// std::string _filePath;
// int _errCode;
// bool _opened;
// bool _doClose;
//
// FILE* _fp;
//};
//
//class FileDataOutput: public BytesDataOutput, public FileIO
//{
//public:
// FileDataOutput(const std::string& filePath)
// : FileIO(filePath, "wb"),
// bytesWritten(0)
// {
// }
// FileDataOutput(FILE* fp)
// : FileIO(fp),
// bytesWritten(0)
// {}
//
// virtual void writeBytes(const void* data, int bytes) {
// if (!_fp) {
// _errCode |= FileError::NOT_OPENED;
// return;
// }
//
// int bytesWritten = fwrite(data, 1, bytes, _fp);
// if (bytesWritten != bytes)
// _errCode |= FileError::NOT_FULLY_HANDLED;
//
// this->bytesWritten += bytesWritten;
// }
//
// int bytesWritten;
//};
//
//class FileDataInput: public BytesDataInput, public FileIO
//{
//public:
// FileDataInput(const std::string& filePath)
// : FileIO(filePath, "rb")
// {
// }
// FileDataInput(FILE* fp)
// : FileIO(fp)
// {}
//
// virtual void readBytes(void* data, int bytes) {
// if (!_fp) {
// _errCode |= FileError::NOT_OPENED;
// return;
// }
//
// if (fread(data, 1, bytes, _fp) != bytes)
// _errCode |= FileError::NOT_FULLY_HANDLED;
// }
//};
#endif /*DATAIO_H__*/

226
src/util/IntHashMap.h Executable file
View File

@@ -0,0 +1,226 @@
#ifndef UTIL__IntHashMap_H__
#define UTIL__IntHashMap_H__
template <class V>
class IntHashMap
{
static const int DEFAULT_INITIAL_CAPACITY = 16;
static const int MAXIMUM_CAPACITY = 1 << 30;
//static const float DEFAULT_LOAD_FACTOR = 0.75f;
Entry<V>** table;
int tableCapacity;
int size;
int threshold;
const float loadFactor;
volatile int modCount;
public:
IntHashMap()
: loadFactor(0.75f)
{
threshold = (int) (DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
table = new Entry[DEFAULT_INITIAL_CAPACITY];
}
~IntHashMap() {
delete[] table;
}
/*public*/ int size() {
return size;
}
/*public*/ bool isEmpty() {
return size == 0;
}
/*public*/ V get(int key) {
int hash = hash(key);
for (Entry<V> e = table[indexFor(hash, table.length)]; e != NULL; e = e.next) {
if (e.key == key) return e.value;
}
return NULL;
}
/*public*/ bool containsKey(int key) {
return getEntry(key) != NULL;
}
const Entry<V> getEntry(int key) {
int hash = hash(key);
for (Entry<V> e = table[indexFor(hash, table.length)]; e != NULL; e = e.next) {
if (e.key == key) return e;
}
return NULL;
}
/*public*/ void put(int key, V value) {
int hash = hash(key);
int i = indexFor(hash, table.length);
for (Entry<V> e = table[i]; e != NULL; e = e.next) {
if (e.key == key) {
e.value = value;
}
}
modCount++;
addEntry(hash, key, value, i);
}
//@SuppressWarnings("unchecked")
/*private*/ void resize(int newCapacity) {
Entry<V>[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = INT_MAX;//Integer.MAX_VALUE;
return;
}
Entry<V>[] newTable = /*new*/ Entry[newCapacity];
transfer(newTable);
table = newTable;
threshold = (int) (newCapacity * loadFactor);
}
/*private*/ void transfer(Entry<V>[] newTable) {
Entry<V>[] src = table;
int newCapacity = newTable.length;
for (int j = 0; j < src.length; j++) {
Entry<V> e = src[j];
if (e != NULL) {
src[j] = NULL;
do {
Entry<V> next = e.next;
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} while (e != NULL);
}
}
}
/*public*/ V remove(int key) {
Entry<V> e = removeEntryForKey(key);
return (e == NULL ? NULL : e.value);
}
const Entry<V> removeEntryForKey(int key) {
int hash = hash(key);
int i = indexFor(hash, table.length);
Entry<V> prev = table[i];
Entry<V> e = prev;
while (e != NULL) {
Entry<V> next = e.next;
if (e.key == key) {
modCount++;
size--;
if (prev == e) table[i] = next;
else prev.next = next;
return e;
}
prev = e;
e = next;
}
return e;
}
/*public*/ void clear() {
modCount++;
Entry<V>[] tab = table;
for (int i = 0; i < tab.length; i++)
tab[i] = NULL;
size = 0;
}
/**
* Returns <tt>true</tt> if this map maps one or more keys to the specified
* value.
*
* @param value value whose presence in this map is to be tested
* @return <tt>true</tt> if this map maps one or more keys to the specified
* value
*/
/*public*/ bool containsValue(Object value) {
if (value == NULL) return containsNullValue();
Entry<V>[] tab = table;
for (int i = 0; i < tab.length; i++)
for (Entry<V> e = tab[i]; e != NULL; e = e.next)
if (value.equals(e.value)) return true;
return false;
}
/*private*/ bool containsNullValue() {
Entry<V>[] tab = table;
for (int i = 0; i < tab.length; i++)
for (Entry<V> e = tab[i]; e != NULL; e = e.next)
if (e.value == NULL) return true;
return false;
}
/*private*/
template <class V>
class Entry<V> {
const int key;
V value;
Entry<V>* next;
const int hash;
/**
* Creates new entry.
*/
Entry(int h, int k, V v, Entry<V>* n)
: value(v),
next(n),
key(k),
hash(h)
{
}
const int getKey() {
return key;
}
const V getValue() {
return value;
}
//@SuppressWarnings("unchecked")
bool operator==(const Entry<V>& rhs) {
return key == rhs.key && value == rhs.value;
}
const int hashCode() {
return hash(key);
}
const std::string toString() {
std::stringstream ss;
ss << getKey() << "=" << getValue();
return ss.str();
}
}
private:
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
static int indexFor(int h, int length) {
return h & (length - 1);
}
void addEntry(int hash, int key, V value, int bucketIndex) {
Entry<V> e = table[bucketIndex];
table[bucketIndex] = /*new*/ Entry<V>(hash, key, value, e);
if (size++ >= threshold) resize(2 * table.length);
}
};
#endif /*UTIL__IntHashMap_H__*/

35
src/util/MemUtils.h Executable file
View File

@@ -0,0 +1,35 @@
#ifndef MEMUTILS_H__
#define MEMUTILS_H__
template <class T>
class Ref {
public:
//~Ref() { //@todo: add this if the pointer is created externally
// dec();
//}
void inc() { ++_count; }
void dec() { if (--_count == 0 && _obj) delete _obj; }
__inline short refCount() { return _count; }
__inline bool isUnique() { return _count == 1; }
__inline T* obj() { return _obj; }
T& operator->() { return *_obj; }
void operator++() { inc(); }
void operator--() { dec(); }
static Ref* create(T* object) { return new Ref(object); }
private:
Ref(T* object)
: _obj(object),
_count(1) {}
Ref(const Ref& rhs);
Ref& operator=(const Ref& rhs);
T* _obj;
short _count;
};
#endif /*MEMUTILS_H__*/

134
src/util/Mth.cpp Executable file
View File

@@ -0,0 +1,134 @@
#include "Mth.h"
#include "Random.h"
#include <cmath>
#include <vector>
#include "../Performance.h"
static Random _rand;
namespace Mth
{
const float PI = 3.1415926535897932384626433832795028841971f; // exactly!
const float TWO_PI = 2.0f * PI; // exactly!
const float DEGRAD = PI / 180.0f;
const float RADDEG = 180.0f / PI;
static float _sin[65536];
static const float _sinScale = 65536.0f / (2.0f * PI);
void initMth() {
for (int i = 0; i < 65536; ++i)
_sin[i] = ::sin(i / _sinScale);
}
float sqrt(float x) {
//Stopwatch& w = Performance::watches.get("sqrt");
//w.start();
float ret = ::sqrt(x);
//w.stop();
return ret;
}
static __inline float fastInvSqrt(float x) {
float xhalf = 0.5f*x;
int i = *(int*)&x;
i = 0x5f3759df - (i>>1);
x = *(float*)&i;
x = x*(1.5f - xhalf*x*x);
return x;
}
float invSqrt(float x) {
//Stopwatch& w = Performance::watches.get("invSqrt");
//w.start();
float ret = fastInvSqrt(x);//1.0f / sqrt(x);
//w.stop();
return ret;
}
int floor(float v) {
int i = (int) v;
return v < i ? i - 1 : i;
}
float cos(float x) {
//Performance::watches.get("cos").start();
//float ret = ::cos(x);
float ret = _sin[(int) (x * _sinScale + 65536 / 4) & 65535];
//Performance::watches.get("cos").stop();
return ret;
}
float sin(float x) {
//Performance::watches.get("sin").start();
//float ret = ::sin(x);
float ret = _sin[(int) (x * _sinScale) & 65535];
//Performance::watches.get("sin").stop();
return ret;
}
float atan(float x) {
//Performance::watches.get("atan").start();
float ret = ::atan(x);
//Performance::watches.get("atan").stop();
return ret;
}
float atan2(float dy, float dx) {
//Performance::watches.get("atan2").start();
float ret = ::atan2(dy, dx);
//Performance::watches.get("atan2").stop();
return ret;
}
float random(){
return _rand.nextFloat();
}
int random(int n){
return _rand.nextInt(n);
}
int intFloorDiv(int a, int b) {
if (a < 0) return -((-a - 1) / b) - 1;
return a / b;
}
float abs(float a) { return a>=0? a : -a; }
float Min(float a, float b) { return a<=b? a : b; }
float Max(float a, float b) { return a>=b? a : b; }
int abs(int a) { return a>=0? a : -a; }
int Min(int a, int b) { return a<=b? a : b; }
int Max(int a, int b) { return a>=b? a : b; }
float absDecrease(float value, float with, float min) {
if (value > 0) return Max(min, value - with);
return Min(value + with, -min);
}
//float absIncrease(float value, float with, float max);
int clamp(int v, int low, int high) {
if (v > high) return high;
return v>low? v : low;
}
float clamp(float v, float low, float high) {
if (v > high) return high;
return v>low? v : low;
}
float lerp(float src, float dst, float alpha) {
return src + (dst - src) * alpha;
}
int lerp(int src, int dst, float alpha) {
return src + (int)((dst - src) * alpha);
}
float absMax(float a, float b) {
if (a < 0) a = -a;
if (b < 0) b = -b;
return a > b ? a : b;
}
float absMaxSigned(float a, float b) {
return abs(a) > abs(b)? a : b;
}
};

98
src/util/Mth.h Executable file
View File

@@ -0,0 +1,98 @@
#ifndef MTH_H__
#define MTH_H__
#include <vector>
#include <set>
#include <algorithm>
namespace Mth {
extern const float PI;
extern const float TWO_PI;
extern const float RADDEG;
extern const float DEGRAD;
void initMth();
float sqrt(float x);
float invSqrt(float x);
int floor(float x);
float sin(float x);
float cos(float x);
float atan(float x);
float atan2(float dy, float dx);
float random();
int random(int n);
float abs(float a);
float Min(float a, float b);
float Max(float a, float b);
int abs(int a);
int Min(int a, int b);
int Max(int a, int b);
int clamp(int v, int low, int high);
float clamp(float v, float low, float high);
float lerp(float src, float dst, float alpha);
int lerp(int src, int dst, float alpha);
///@param value The original signed value
///@param with The (possibly signed) value to "abs-decrease" <value> with
///@param min The minimum value
float absDecrease(float value, float with, float min);
//float absIncrease(float value, float with, float max);
float absMax(float a, float b);
float absMaxSigned(float a, float b);
int intFloorDiv(int a, int b);
};
namespace Util
{
template <class T>
int removeAll(std::vector<T>& superset, const std::vector<T>& toRemove) {
int subSize = (int)toRemove.size();
int removed = 0;
for (int i = 0; i < subSize; ++i) {
T elem = toRemove[i];
int size = (int)superset.size();
for (int j = 0; j < size; ++j) {
if (elem == superset[j]) {
superset.erase( superset.begin() + j, superset.begin() + j + 1);
++removed;
break;
}
}
}
return removed;
}
template <class T>
bool remove(std::vector<T>& list, const T& instance) {
typename std::vector<T>::iterator it = std::find(list.begin(), list.end(), instance);
if (it == list.end())
return false;
list.erase(it);
return true;
}
// Could perhaps do a template<template ..>
template <class T>
bool remove(std::set<T>& list, const T& instance) {
typename std::set<T>::iterator it = std::find(list.begin(), list.end(), instance);
if (it == list.end())
return false;
list.erase(it);
return true;
}
};
#endif // MTH_H__

227
src/util/PerfRenderer.cpp Executable file
View File

@@ -0,0 +1,227 @@
#include "PerfRenderer.h"
#include "PerfTimer.h"
#include "Mth.h"
#include "../client/gui/Font.h"
#include "../client/renderer/gles.h"
#include "../client/renderer/Tesselator.h"
#include "../client/Minecraft.h"
PerfRenderer::PerfRenderer( Minecraft* mc, Font* font )
: _mc(mc),
_font(font),
_debugPath("root"),
frameTimePos(0),
lastTimer(-1)
{
for (int i = 0; i < 512; ++i) {
frameTimes.push_back(0);
tickTimes.push_back(0);
}
}
void PerfRenderer::debugFpsMeterKeyPress( int key )
{
std::vector<PerfTimer::ResultField> list = PerfTimer::getLog(_debugPath);
if (list.empty()) return;
PerfTimer::ResultField node = list[0];
list.erase(list.begin());
if (key == 0) {
if (node.name.length() > 0) {
int pos = _debugPath.rfind(".");
if (pos != std::string::npos) _debugPath = _debugPath.substr(0, pos);
}
} else {
key--;
if (key < (int)list.size() && list[key].name != "unspecified") {
if (_debugPath.length() > 0) _debugPath += ".";
_debugPath += list[key].name;
}
}
}
void PerfRenderer::renderFpsMeter( float tickTime )
{
std::vector<PerfTimer::ResultField> list = PerfTimer::getLog(_debugPath);
if (list.empty())
return;
PerfTimer::ResultField node = list[0];
list.erase(list.begin());
long usPer60Fps = 1000000l / 60;
if (lastTimer == -1) {
lastTimer = getTimeS();
}
float now = getTimeS();
tickTimes[ frameTimePos ] = tickTime;
frameTimes[frameTimePos ] = now - lastTimer;
lastTimer = now;
if (++frameTimePos >= (int)frameTimes.size())
frameTimePos = 0;
glClear(GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glEnable2(GL_COLOR_MATERIAL);
glLoadIdentity2();
glOrthof(0, (GLfloat)_mc->width, (GLfloat)_mc->height, 0, 1000, 3000);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity2();
glTranslatef2(0, 0, -2000);
glLineWidth(1);
glDisable2(GL_TEXTURE_2D);
Tesselator& t = Tesselator::instance;
t.begin(GL_TRIANGLES);
int hh1 = (int) (usPer60Fps / 200);
float count = (float)frameTimes.size();
t.color(0x20000000);
t.vertex(0, (float)(_mc->height - hh1), 0);
t.vertex(0, (float)_mc->height, 0);
t.vertex(count, (float)_mc->height, 0);
t.vertex(count, (float)(_mc->height - hh1), 0);
t.color(0x20200000);
t.vertex(0, (float)(_mc->height - hh1 * 2), 0);
t.vertex(0, (float)(_mc->height - hh1), 0);
t.vertex(count, (float)(_mc->height - hh1), 0);
t.vertex(count, (float)(_mc->height - hh1 * 2), 0);
t.draw();
float totalTime = 0;
for (unsigned int i = 0; i < frameTimes.size(); i++) {
totalTime += frameTimes[i];
}
int hh = (int) (totalTime / 200 / frameTimes.size());
t.begin();
t.color(0x20400000);
t.vertex(0, (float)(_mc->height - hh), 0);
t.vertex(0, (float)_mc->height, 0);
t.vertex(count, (float)_mc->height, 0);
t.vertex(count, (float)(_mc->height - hh), 0);
t.draw();
t.begin(GL_LINES);
for (unsigned int i = 0; i < frameTimes.size(); i++) {
int col = ((i - frameTimePos) & (frameTimes.size() - 1)) * 255 / frameTimes.size();
int cc = col * col / 255;
cc = cc * cc / 255;
int cc2 = cc * cc / 255;
cc2 = cc2 * cc2 / 255;
if (frameTimes[i] > usPer60Fps) {
t.color(0xff000000 + cc * 65536);
} else {
t.color(0xff000000 + cc * 256);
}
float time = 10 * 1000 * frameTimes[i] / 200;
float time2 = 10 * 1000 * tickTimes[i] / 200;
t.vertex(i + 0.5f, _mc->height - time + 0.5f, 0);
t.vertex(i + 0.5f, _mc->height + 0.5f, 0);
// if (_mc->frameTimes[i]>nsPer60Fps) {
t.color(0xff000000 + cc * 65536 + cc * 256 + cc * 1);
// } else {
// t.color(0xff808080 + cc/2 * 256);
// }
t.vertex(i + 0.5f, _mc->height - time + 0.5f, 0);
t.vertex(i + 0.5f, _mc->height - (time - time2) + 0.5f, 0);
}
t.draw();
//t.end();
int r = 160;
int x = _mc->width - r - 10;
int y = _mc->height - r * 2;
glEnable(GL_BLEND);
t.begin();
t.color(0x000000, 200);
t.vertex(x - r * 1.1f, y - r * 0.6f - 16, 0);
t.vertex(x - r * 1.1f, y + r * 2.0f, 0);
t.vertex(x + r * 1.1f, y + r * 2.0f, 0);
t.vertex(x + r * 1.1f, y - r * 0.6f - 16, 0);
t.draw();
glDisable(GL_BLEND);
glDisable(GL_CULL_FACE);
float totalPercentage = 0;
for (unsigned int i = 0; i < list.size(); i++) {
PerfTimer::ResultField& result = list[i];
int steps = Mth::floor(result.percentage / 4) + 1;
t.begin(GL_TRIANGLE_FAN);
t.color(result.getColor());
t.vertex((float)x, (float)y, 0);
for (int j = steps; j >= 0; j--) {
float dir = (float) ((totalPercentage + (result.percentage * j / steps)) * Mth::PI * 2 / 100);
float xx = Mth::sin(dir) * r;
float yy = Mth::cos(dir) * r * 0.5f;
t.vertex(x + xx, y - yy, 0);
//LOGI("xy: %f, %f\n", x+xx, y - yy);
}
t.draw();
t.begin(GL_TRIANGLE_STRIP);
t.color((result.getColor() & 0xfefefe) >> 1);
for (int j = steps; j >= 0; j--) {
float dir = (float) ((totalPercentage + (result.percentage * j / steps)) * Mth::PI * 2 / 100);
float xx = Mth::sin(dir) * r;
float yy = Mth::cos(dir) * r * 0.5f;
t.vertex(x + xx, y - yy, 0);
t.vertex(x + xx, y - yy + 10, 0);
}
t.draw();
totalPercentage += result.percentage;
}
glEnable(GL_TEXTURE_2D);
{
std::stringstream msg;
if (node.name != "unspecified") {
msg << "[0] ";
}
if (node.name.length() == 0) {
msg << "ROOT ";
} else {
msg << node.name << " ";
}
int col = 0xffffff;
_font->drawShadow(msg.str(), (float)(x - r), (float)(y - r / 2 - 16), col);
std::string msg2 = toPercentString(node.globalPercentage);
_font->drawShadow(msg2, (float)(x + r - _font->width(msg2)), (float)(y - r / 2 - 16), col);
}
for (unsigned int i = 0; i < list.size(); i++) {
PerfTimer::ResultField& result = list[i];
std::stringstream msg;
if (result.name != "unspecified") {
msg << "[" << (i + 1) << "] ";
} else {
msg << "[?] ";
}
msg << result.name;
float xx = (float)(x - r);
float yy = (float)(y + r/2 + i * 8 + 20);
_font->drawShadow(msg.str(), xx, yy, result.getColor());
std::string msg2 = toPercentString(result.percentage);
//LOGI("name: %s: perc: %f == %s @ %d, %d\n", msg.str().c_str(), result.percentage, msg2.c_str(), xx, yy);
_font->drawShadow(msg2, xx - 50 - _font->width(msg2), yy, result.getColor());
msg2 = toPercentString(result.globalPercentage);
_font->drawShadow(msg2, xx - _font->width(msg2), yy, result.getColor());
}
}
std::string PerfRenderer::toPercentString( float percentage )
{
char buf[32] = {0};
sprintf(buf, "%3.2f%%", percentage);
return buf;
}

34
src/util/PerfRenderer.h Executable file
View File

@@ -0,0 +1,34 @@
#ifndef NET_UTIL__PerfRenderer_H__
#define NET_UTIL__PerfRenderer_H__
#include <vector>
#include <string>
#include <sstream>
class Minecraft;
class Font;
//package net.minecraft.client;
class PerfRenderer
{
public:
PerfRenderer( Minecraft* mc, Font* font);
void debugFpsMeterKeyPress(int key);
void renderFpsMeter(float tickTime);
private:
std::string toPercentString(float percentage);
Minecraft* _mc;
Font* _font;
std::string _debugPath;
std::vector<float> frameTimes;
std::vector<float> tickTimes;
int frameTimePos;
float lastTimer;
};
#endif /*NET_UTIL__PerfRenderer_H__*/

123
src/util/PerfTimer.cpp Executable file
View File

@@ -0,0 +1,123 @@
#include "PerfTimer.h"
#include "../platform/time.h"
#include <algorithm>
/*static*/
bool
PerfTimer::enabled = false;
std::vector<std::string>
PerfTimer::paths;
std::vector<float>
PerfTimer::startTimes;
std::string
PerfTimer::path;
PerfTimer::TimeMap
PerfTimer::times;
/*static*/
void PerfTimer::reset()
{
times.clear();
}
/*static*/
void PerfTimer::push( const std::string& name )
{
if (!enabled) return;
if (path.length() > 0) path += ".";
path += name;
paths.push_back(path);
startTimes.push_back(getTimeS());
}
/*static*/
void PerfTimer::pop()
{
if (!enabled) return;
float endTime = getTimeS();
float startTime = startTimes.back();
paths.pop_back();
startTimes.pop_back();
float time = endTime - startTime;
TimeMap::iterator it = times.find(path);
if (it != times.end()) {
it->second += time;
} else {
times.insert(std::make_pair(path, time));
}
path = paths.size() > 0 ? paths.back() : "";
//if (paths.size() == 0) {
// for (TimeMap::iterator it = times.begin(); it != times.end(); ++it) {
// LOGI("p: %s t: %f\n", it->first.c_str(), it->second);
// }
//}
}
/*static*/
void PerfTimer::popPush( const std::string& name )
{
pop();
push(name);
}
/*static*/
std::vector<PerfTimer::ResultField> PerfTimer::getLog(const std::string& rawPath) {
if (!enabled) return std::vector<ResultField>();
std::string path = rawPath;
TimeMap::const_iterator itRoot = times.find("root");
float globalTime = (itRoot != times.end())? itRoot->second : 0;
TimeMap::const_iterator itPath = times.find(path);
float totalTime2 = (itRoot != times.end())? itRoot->second : -1;
std::vector<ResultField> result;
if (path.length() > 0) path += ".";
float totalTime = 0;
for (TimeMap::const_iterator cit = times.begin(); cit != times.end(); ++cit) {
const std::string& key = cit->first;
const float& time = cit->second;
if (key.length() > path.length() && Util::startsWith(key, path) && key.find(".", path.length() + 1) == std::string::npos) {
totalTime += time;
}
}
float oldTime = totalTime;
if (totalTime < totalTime2) totalTime = totalTime2;
if (globalTime < totalTime) globalTime = totalTime;
for (TimeMap::const_iterator cit = times.begin(); cit != times.end(); ++cit) {
const std::string& key = cit->first;
//const float& time = cit->second;
if (key.length() > path.length() && Util::startsWith(key, path) && key.find(".", path.length() + 1) == std::string::npos) {
float time = times.find(key)->second;
float timePercentage = time * 100.0f / totalTime;
float globalPercentage = time * 100.0f / globalTime;
std::string name = key.substr(path.length());
result.push_back(ResultField(name, timePercentage, globalPercentage));
}
}
for (TimeMap::iterator it = times.begin(); it != times.end(); ++it)
it->second *= 0.999f;
if (totalTime > oldTime)
result.push_back(ResultField("unspecified", (totalTime - oldTime) * 100.0f / totalTime, (totalTime - oldTime) * 100.0f / globalTime));
std::sort(result.begin(), result.end());
result.insert(result.begin(), ResultField(rawPath, 100, totalTime * 100.0f / globalTime));
return result;
}

62
src/util/PerfTimer.h Executable file
View File

@@ -0,0 +1,62 @@
#ifndef NET_UTIL__PerfTimer_H__
#define NET_UTIL__PerfTimer_H__
#include <map>
#include <vector>
#include "StringUtils.h"
//package util;
#ifdef PROFILER
#define TIMER_PUSH(x) PerfTimer::push(x)
#define TIMER_POP() PerfTimer::pop()
#define TIMER_POP_PUSH(x) PerfTimer::popPush(x)
#else
#define TIMER_PUSH(x) ((void*)0)
#define TIMER_POP() ((void*)0)
#define TIMER_POP_PUSH(x) ((void*)0)
#endif
class PerfTimer
{
typedef std::map<std::string, float> TimeMap;
public:
class ResultField {
public:
float percentage;
float globalPercentage;
std::string name;
ResultField(const std::string& name, float percentage, float globalPercentage)
: name(name),
percentage(percentage),
globalPercentage(globalPercentage)
{}
bool operator<(const ResultField& rf) const {
if (percentage != rf.percentage)
return percentage > rf.percentage;
return name > rf.name;
}
int getColor() const {
return (Util::hashCode(name) & 0xaaaaaa) + 0x444444;
}
};
static void reset();
static void push(const std::string& name);
static void pop();
static void popPush(const std::string& name);
static std::vector<ResultField> getLog(const std::string& path);
static bool enabled;
private:
static std::vector<std::string> paths;
static std::vector<float> startTimes;
static std::string path;
static TimeMap times;
};
#endif /*NET_UTIL__PerfTimer_H__*/

49
src/util/RakDataIO.h Executable file
View File

@@ -0,0 +1,49 @@
#ifndef RAKDATAIO_H__
#define RAKDATAIO_H__
#include <cstring>
#include <string>
#include "DataIO.h"
// Uses BitStream as a growing buffer
class RakDataOutput: public BytesDataOutput {
public:
//RakDataOutput() {}
RakDataOutput(RakNet::BitStream& bitstream)
: _bitStream(bitstream)
{}
virtual void writeBytes(const void* data, int bytes) {
_bitStream.WriteBits((const unsigned char*)data, bytes * 8);
}
RakNet::BitStream& getBitStream() {
return _bitStream;
}
private:
RakNet::BitStream& _bitStream;
};
class RakDataInput: public BytesDataInput {
public:
//RakDataOutput() {}
RakDataInput(RakNet::BitStream& bitstream)
: _bitStream(bitstream)
{}
virtual void readBytes(void* data, int bytes) {
_bitStream.ReadBits((unsigned char*) data, bytes * 8);
}
RakNet::BitStream& getBitStream() {
return _bitStream;
}
private:
RakNet::BitStream& _bitStream;
};
#endif /*RAKDATAIO_H__*/

254
src/util/Random.h Executable file
View File

@@ -0,0 +1,254 @@
#ifndef RANDOM_H__
#define RANDOM_H__
/*
A random generator class based on Mersenne-Twister.
"UPDATE"
http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/elicense.html
---------------------------------------------------------------------
Commercial Use of Mersenne Twister
2001/4/6
Until 2001/4/6, MT had been distributed under GNU Public License, but
after 2001/4/6, we decided to let MT be used for any purpose, including
commercial use. 2002-versions mt19937ar.c, mt19937ar-cok.c are considered
to be usable freely.
*/
#include "../platform/time.h"
#include <cmath>
class Random
{
public:
Random() {
setSeed( getTimeMs() );
}
Random( long seed ) {
setSeed( seed );
}
void setSeed( long seed ) {
_seed = seed;
_mti = N + 1;
haveNextNextGaussian = false;
nextNextGaussian = 0;
init_genrand(seed);
}
long getSeed() {
return _seed;
}
bool nextBoolean() {
return (genrand_int32() & 0x8000000) > 0;
}
float nextFloat() {
return (float)genrand_real2();
}
double nextDouble() {
return genrand_real2();
}
int nextInt() {
return (int)(genrand_int32()>>1);
}
int nextInt(int n) {
return genrand_int32() % n;
}
int /* long long */ nextLong() {
return (int)(genrand_int32()>>1);
}
int /* long long */ nextLong(int /*long long*/ n) {
return genrand_int32() % n;
}
float nextGaussian()
{
if (haveNextNextGaussian) {
haveNextNextGaussian = false;
return nextNextGaussian;
} else {
float v1, v2, s;
do {
v1 = 2 * nextFloat() - 1; // between -1.0 and 1.0
v2 = 2 * nextFloat() - 1; // between -1.0 and 1.0
s = v1 * v1 + v2 * v2;
} while (s >= 1 || s == 0);
float multiplier = std::sqrt(-2 * std::log(s)/s);
nextNextGaussian = v2 * multiplier;
haveNextNextGaussian = true;
return v1 * multiplier;
}
}
private:
long _seed;
/* Period parameters */
static const int N = 624;
static const int M = 397;
static const unsigned int MATRIX_A = 0x9908b0dfUL; /* constant vector a */
static const unsigned int UPPER_MASK = 0x80000000UL; /* most significant w-r bits */
static const unsigned int LOWER_MASK = 0x7fffffffUL; /* least significant r bits */
unsigned long _mt[N]; /* the array for the state vector */
int _mti; /* _mti==N+1 means _mt[N] is not initialized */
bool haveNextNextGaussian;
float nextNextGaussian;
/* initializes _mt[N] with a seed */
void init_genrand(unsigned long s)
{
_mt[0] = s & 0xffffffffUL;
for (_mti=1; _mti < N; _mti++) {
_mt[_mti] =
(1812433253UL * (_mt[_mti-1] ^ (_mt[_mti-1] >> 30)) + _mti);
/* See Knuth TAOCP Vol2. 3rd Ed. P.106 for multiplier. */
/* In the previous versions, MSBs of the seed affect */
/* only MSBs of the array _mt[]. */
/* 2002/01/09 modified by Makoto Matsumoto */
_mt[_mti] &= 0xffffffffUL;
/* for >32 bit machines */
}
}
/* initialize by an array with array-length */
/* init_key is the array for initializing keys */
/* key_length is its length */
/* slight change for C++, 2004/2/26 */
void init_by_array(unsigned long init_key[], int key_length)
{
int i, j, k;
init_genrand(19650218UL);
i=1; j=0;
k = (N>key_length ? N : key_length);
for (; k; k--) {
_mt[i] = (_mt[i] ^ ((_mt[i-1] ^ (_mt[i-1] >> 30)) * 1664525UL))
+ init_key[j] + j; /* non linear */
_mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
i++; j++;
if (i>=N) { _mt[0] = _mt[N-1]; i=1; }
if (j>=key_length) j=0;
}
for (k=N-1; k; k--) {
_mt[i] = (_mt[i] ^ ((_mt[i-1] ^ (_mt[i-1] >> 30)) * 1566083941UL))
- i; /* non linear */
_mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */
i++;
if (i>=N) { _mt[0] = _mt[N-1]; i=1; }
}
_mt[0] = 0x80000000UL; /* MSB is 1; assuring non-zero initial array */
}
/* generates a random number on [0,0xffffffff]-interval */
unsigned long genrand_int32(void)
{
unsigned long y;
static unsigned long mag01[2]={0x0UL, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */
if (_mti >= N) { /* generate N words at one time */
//static Stopwatch sw;
//sw.start();
int kk;
if (_mti == N+1) /* if init_genrand() has not been called, */
init_genrand(5489UL); /* a default initial seed is used */
for (kk=0;kk<N-M;kk++) {
y = (_mt[kk]&UPPER_MASK)|(_mt[kk+1]&LOWER_MASK);
_mt[kk] = _mt[kk+M] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
for (;kk<N-1;kk++) {
y = (_mt[kk]&UPPER_MASK)|(_mt[kk+1]&LOWER_MASK);
_mt[kk] = _mt[kk+(M-N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
y = (_mt[N-1]&UPPER_MASK)|(_mt[0]&LOWER_MASK);
_mt[N-1] = _mt[M-1] ^ (y >> 1) ^ mag01[y & 0x1UL];
_mti = 0;
//sw.stop();
//sw.printEvery(100, "genrand:");
}
y = _mt[_mti++];
/* Tempering */
y ^= (y >> 11);
y ^= (y << 7) & 0x9d2c5680UL;
y ^= (y << 15) & 0xefc60000UL;
y ^= (y >> 18);
return y;
}
/* generates a random number on [0,0x7fffffff]-interval */
long genrand_int31(void)
{
return (long)(genrand_int32()>>1);
}
/* generates a random number on [0,1]-real-interval */
double genrand_real1(void)
{
return genrand_int32()*(1.0/4294967295.0);
/* divided by 2^32-1 */
}
/* generates a random number on [0,1)-real-interval */
double genrand_real2(void)
{
return genrand_int32()*(1.0/4294967296.0);
/* divided by 2^32 */
}
/* generates a random number on (0,1)-real-interval */
double genrand_real3(void)
{
return (((double)genrand_int32()) + 0.5)*(1.0/4294967296.0);
/* divided by 2^32 */
}
/* generates a random number on [0,1) with 53-bit resolution*/
double genrand_res53(void)
{
unsigned long a=genrand_int32()>>5, b=genrand_int32()>>6;
return(a*67108864.0+b)*(1.0/9007199254740992.0);
}
/* These real versions are due to Isaku Wada, 2002/01/09 added */
//
// Added helper (and quicker) functions
//
void rrDiff(float &x) {
unsigned long u = genrand_int32();
const float xx0 = ( u & 0xffff) / 65536.0f; // 2 x 16 bits
const float xx1 = ((u >> 16) & 0xffff) / 65536.0f;
x = xx0 - xx1;
}
void rrDiff(float& x, float& y) {
unsigned long u = genrand_int32();
const float xx0 = ((u ) & 0xff) / 256.0f; // 4 x 8 bits
const float xx1 = ((u >> 8) & 0xff) / 256.0f;
const float yy0 = ((u >> 16)& 0xff) / 256.0f;
const float yy1 = ((u >> 24)& 0xff) / 256.0f;
x = xx0 - xx1;
y = yy0 - yy1;
}
void rrDiff(float& x, float& y, float& z) {
unsigned long u = genrand_int32();
const float xx0 = ((u ) & 0x1f) / 32.0f; // 6 x 5 bits
const float xx1 = ((u >> 5) & 0x1f) / 32.0f;
const float yy0 = ((u >> 10)& 0x1f) / 32.0f;
const float yy1 = ((u >> 15)& 0x1f) / 32.0f;
const float zz0 = ((u >> 20)& 0x1f) / 32.0f;
const float zz1 = ((u >> 25)& 0x1f) / 32.0f;
x = xx0 - xx1;
y = yy0 - yy1;
z = zz0 - zz1;
}
};
#endif /*RANDOM_H__*/

37
src/util/SmoothFloat.h Executable file
View File

@@ -0,0 +1,37 @@
#ifndef UTIL__SmoothFloat_H__
#define UTIL__SmoothFloat_H__
//package util;
class SmoothFloat
{
float targetValue;
float remainingValue;
float lastAmount;
public:
SmoothFloat()
: targetValue(0),
remainingValue(0),
lastAmount(0)
{}
float getNewDeltaValue(float deltaValue, float accelerationAmount) {
targetValue += deltaValue;
deltaValue = (targetValue - remainingValue) * accelerationAmount;
lastAmount = lastAmount + (deltaValue - lastAmount) * .5f;
if ((deltaValue > 0 && deltaValue > lastAmount) || (deltaValue < 0 && deltaValue < lastAmount)) {
deltaValue = lastAmount;
}
remainingValue += deltaValue;
return deltaValue;
}
float getTargetValue() {
return targetValue;
}
};
#endif /*UTIL__SmoothFloat_H__*/

73
src/util/StringUtils.cpp Executable file
View File

@@ -0,0 +1,73 @@
#include "StringUtils.h"
#include <algorithm>
#include "../platform/log.h"
namespace Util
{
/// @return true if <s> starts with <start>, false if not
bool startsWith(const std::string& s, const std::string& start) {
const unsigned int len = start.length();
return len <= s.length()
&& s.substr(0, len) == start;
}
// Naive (e.g. slow and stupid) implementation. @todo: fix
/// @return A reference to s
std::string& stringReplace(std::string& s, const std::string& src, const std::string& dst, int maxCount /*= -1*/) {
int srcLength = src.length();
while(maxCount--) {
std::string::size_type pos = s.find(src);
if (pos == std::string::npos)
break;
s.replace(pos, srcLength, dst);
}
return s;
}
/// @return A string trimmed from white space characters on both ends
std::string stringTrim(const std::string& s) {
return stringTrim(s, " \t\n\r", true, true);
}
/// @return A string trimmed from given characters on any end
std::string stringTrim(const std::string& s, const std::string& chars, bool left, bool right) {
const int len = s.length();
const int lenChars = chars.length();
if (len == 0 || lenChars == 0 || ((left || right) == false))
return "";
int i = 0, j = len-1;
if (left) {
for (; i < len; ++i)
if (std::find(chars.begin(), chars.end(), s[i]) == chars.end())
break;
}
if (right) {
for (; j >= i; --j)
if (std::find(chars.begin(), chars.end(), s[j]) == chars.end())
break;
}
return s.substr(i, j - i + 1);
}
/// @return The "Java" implementation for string hash codes
int hashCode(const std::string& s) {
const int len = s.length();
int hash = 0;
for (int i = 0; i < len; i++) {
hash = ((hash << 5) - hash) + s[i];
}
return hash;
}
void removeAll(std::string& s, const char** rep, int repCount) {
for (int i = 0; i < repCount; ++i)
stringReplace(s, rep[i], "");
}
}; // end namespace Util

27
src/util/StringUtils.h Executable file
View File

@@ -0,0 +1,27 @@
#ifndef STRINGUTILS_H__
#define STRINGUTILS_H__
#include <string>
namespace Util {
/// @return true if <s> starts with <start>, false if not
bool startsWith(const std::string& s, const std::string& start);
/// @return A reference to s
std::string& stringReplace(std::string& s, const std::string& src, const std::string& dst, int maxCount = -1);
/// @return A string trimmed from white space characters on both ends
std::string stringTrim(const std::string& S);
/// @return A string trimmed from given characters on any end
std::string stringTrim(const std::string& S, const std::string& chars, bool left = true, bool right = true);
void removeAll(std::string& s, const char** rep, int repCount);
/// @return The "Java" implementation for string hash codes
int hashCode(const std::string& s);
}; // end namespace Util
#endif /*STRINGUTILS_H__*/

103
src/util/WeighedRandom.h Executable file
View File

@@ -0,0 +1,103 @@
#ifndef UTIL__WeighedRandom_H__
#define UTIL__WeighedRandom_H__
//package util;
#include "Random.h"
class WeighedRandom
{
public:
class WeighedRandomItem {
public:
int randomWeight;
WeighedRandomItem()
: randomWeight(-128)
{}
WeighedRandomItem(int randomWeight)
: randomWeight(randomWeight)
{}
bool isValid() {
return randomWeight >= 0;
}
};
template <typename T>
static int getTotalWeight(const T& items) {
int totalWeight = 0;
for (typename T::const_iterator it = items.begin(); it != items.end(); ++it)
totalWeight += it->randomWeight;
return totalWeight;
}
template <typename T>
static const WeighedRandomItem* getRandomItem(Random* random, const T& items, int totalWeight) {
int selection = random->nextInt(totalWeight);
for (typename T::const_iterator it = items.begin(); it != items.end(); ++it) {
selection -= it->randomWeight;
if (selection < 0) {
return &(*it);
}
}
return NULL;
}
template<typename T>
static const WeighedRandomItem* getRandomItem(Random* random, const T& items) {
return getRandomItem(random, items, getTotalWeight(items));
}
template <typename T>
static int getRandomItemIndex(Random* random, const T& items, int totalWeight) {
int selection = random->nextInt(totalWeight);
for (unsigned int i = 0; i < items.size(); ++i) {
selection -= items[i].randomWeight;
if (selection < 0) {
return i;
}
}
return -1;
}
template<typename T>
static int getRandomItemIndex(Random* random, const T& items) {
return getRandomItemIndex(random, items, getTotalWeight(items));
}
// static int getTotalWeight(WeighedRandomItem items) {
// int totalWeight = 0;
//
// for (unsigned int i = 0; i < items.size(); ++i) {
// WeighedRandomItem& item = items[i];
// totalWeight += item.randomWeight;
// }
// return totalWeight;
// }
// static WeighedRandomItem getRandomItem(Random* random, WeighedRandomItem[] items, int totalWeight) {
//
// if (totalWeight <= 0) {
// throw /*new*/ IllegalArgumentException();
// }
//
// int selection = random->nextInt(totalWeight);
// for (unsigned int i = 0; i < items.size(); ++i) {
// WeighedRandomItem& item = items[i];
// //for (WeighedRandomItem item : items) {
// selection -= item.randomWeight;
// if (selection < 0) {
// return item;
// }
// }
// return NULL;
// }
// static WeighedRandomItem getRandomItem(Random* random, WeighedRandomItem[] items) {
// return getRandomItem(random, items, getTotalWeight(items));
// }
};
#endif /*UTIL__WeighedRandom_H__*/