mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-05 05:07:48 +00:00
fahhh
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
//#include "Util/SoundWorld.h"
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Action
|
||||
{
|
||||
public:
|
||||
enum ActionType { NO_ACTION = 0,
|
||||
PAUSE_ACTION,
|
||||
LOSE_ACTION,
|
||||
DRAW_ACTION,
|
||||
WIN_ACTION,
|
||||
NUM_ACTION_TYPES };
|
||||
private:
|
||||
Action();
|
||||
|
||||
};
|
||||
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,203 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <rapidjson/document.h>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include "FastLog.h"
|
||||
#include "RbxFormat.h"
|
||||
|
||||
DYNAMIC_FASTFLAG(InfluxDb09Enabled)
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace Analytics {
|
||||
|
||||
void setUserId(int id);
|
||||
void setPlaceId(int id);
|
||||
void setAppVersion(const std::string& version);
|
||||
void setLocation(const std::string& loc);
|
||||
void setReporter(const std::string& rep);
|
||||
|
||||
namespace EphemeralCounter
|
||||
{
|
||||
void reportStats(const std::string& category, float value, bool blocking = false);
|
||||
void reportCountersCSV(const std::string& counterNamesCSV, bool blocking = false);
|
||||
void reportCounter(const std::string& counterName, int amount, bool blocking = false);
|
||||
}
|
||||
|
||||
namespace GoogleAnalytics
|
||||
{
|
||||
// Allow for easy initialization based on a lottery number.
|
||||
// Calls setCanUseAnalytics and init.
|
||||
void lotteryInit(const std::string &accountPropertyID, int lotteryThreshold, const std::string& productName = "", int robloxAnalyticsLottery = -1, const std::string &sessionKey = "sessionID=");
|
||||
|
||||
// Must be called before using the singleton.
|
||||
void init(const std::string &accountPropertyID, const std::string& productName = "");
|
||||
|
||||
bool getCanUse();
|
||||
void setCanUse();
|
||||
|
||||
void sendEventRoblox(const char* category, const char* action = "custom", const char* label = "none", int value = 0, bool sync = false);
|
||||
|
||||
void trackEvent(const char *category, const char *action = "custom", const char *label = "none", int value = 0, bool sync = false);
|
||||
void trackEventWithoutThrottling(const char *category, const char *action = "custom", const char *label = "none", int value = 0, bool sync = false);
|
||||
void trackUserTiming(const char *category, const char *variable, int milliseconds, const char *label = "none", bool sync = false);
|
||||
|
||||
const std::string& getSessionId();
|
||||
|
||||
} // namespace GoogleAnalytics
|
||||
|
||||
|
||||
namespace InfluxDb {
|
||||
|
||||
struct Point
|
||||
{
|
||||
std::string name;
|
||||
std::string json;
|
||||
|
||||
Point(const std::string& name_, const rapidjson::Value& value) : name(name_)
|
||||
{
|
||||
using namespace rapidjson;
|
||||
|
||||
switch (value.GetType())
|
||||
{
|
||||
case kNullType:
|
||||
json = "null";
|
||||
break;
|
||||
case kFalseType:
|
||||
json = "false";
|
||||
break;
|
||||
case kTrueType:
|
||||
json = "true";
|
||||
break;
|
||||
case kObjectType:
|
||||
case kArrayType:
|
||||
throw std::runtime_error("Arrays and objects are not valid value types.");
|
||||
break;
|
||||
case kStringType:
|
||||
if (DFFlag::InfluxDb09Enabled)
|
||||
{
|
||||
// we must escape double quotes
|
||||
std::string sval = value.GetString();
|
||||
boost::replace_all(sval, "\"", "\\\"");
|
||||
json = std::string("\"") + sval + "\"";
|
||||
}
|
||||
else
|
||||
{
|
||||
json = std::string("\"") + value.GetString() + "\"";
|
||||
}
|
||||
break;
|
||||
case kNumberType:
|
||||
{
|
||||
const rapidjson::Value& v = value;
|
||||
|
||||
std::stringstream ss;
|
||||
if (v.IsDouble())
|
||||
{
|
||||
ss << v.GetDouble();
|
||||
}
|
||||
else if (v.IsInt())
|
||||
{
|
||||
ss << v.GetInt();
|
||||
if (DFFlag::InfluxDb09Enabled)
|
||||
{
|
||||
ss << 'i'; // signals integer type
|
||||
}
|
||||
}
|
||||
else if (v.IsInt64())
|
||||
{
|
||||
ss << v.GetInt64();
|
||||
if (DFFlag::InfluxDb09Enabled)
|
||||
{
|
||||
ss << 'i'; // signals integer type
|
||||
}
|
||||
}
|
||||
else if (v.IsUint())
|
||||
{
|
||||
ss << v.GetUint();
|
||||
if (DFFlag::InfluxDb09Enabled)
|
||||
{
|
||||
ss << 'i'; // signals integer type
|
||||
}
|
||||
}
|
||||
else if (v.IsUint64())
|
||||
{
|
||||
ss << v.GetUint64();
|
||||
if (DFFlag::InfluxDb09Enabled)
|
||||
{
|
||||
ss << 'i'; // signals integer type
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("Unknown number type.");
|
||||
}
|
||||
|
||||
ss >> json;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unknown rapidjson value type.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const Point& other) const {
|
||||
return this->name == other.name;
|
||||
}
|
||||
};
|
||||
std::size_t hash_value(const Point& p);
|
||||
|
||||
void init();
|
||||
void reportPoints(const std::string& resource, const boost::unordered_set<Point>& points, int throttleHundredthsPercentage, bool blocking = false, const std::string& userIdOverride = "");
|
||||
void reportPointsV2(const std::string& resource, const boost::unordered_set<Point>& points, int throttleHundredthsPercentage, bool blocking = false, const std::string& userIdOverride = "");
|
||||
|
||||
class Points
|
||||
{
|
||||
boost::unordered_set<Point> pointList;
|
||||
std::string userIdOverride;
|
||||
|
||||
public:
|
||||
Points() {}
|
||||
~Points() {}
|
||||
|
||||
void setUserIdOverride(const int id)
|
||||
{
|
||||
userIdOverride = RBX::format("%d", id);
|
||||
}
|
||||
|
||||
void addPoint(const std::string& name, const rapidjson::Value& value, bool override = false)
|
||||
{
|
||||
Point newPoint = Point(name, value);
|
||||
std::pair<boost::unordered_set<Point>::iterator, bool> res = pointList.insert(newPoint);
|
||||
|
||||
if (override && !res.second)
|
||||
{
|
||||
pointList.erase(res.first);
|
||||
pointList.insert(newPoint);
|
||||
}
|
||||
}
|
||||
|
||||
void report(const std::string& resource, int throttleHundredthsPercentage, bool blocking = false)
|
||||
{
|
||||
if (!pointList.empty())
|
||||
{
|
||||
if (DFFlag::InfluxDb09Enabled)
|
||||
reportPointsV2(resource, pointList, throttleHundredthsPercentage, blocking, userIdOverride);
|
||||
else
|
||||
reportPoints(resource, pointList, throttleHundredthsPercentage, blocking, userIdOverride);
|
||||
pointList.clear();
|
||||
}
|
||||
}
|
||||
|
||||
const boost::unordered_set<Point>& getPoints() { return pointList; }
|
||||
};
|
||||
|
||||
|
||||
} // namespace InfluxDb
|
||||
|
||||
} // namespace Analytics
|
||||
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/ContentId.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class AnimationId : public ContentId
|
||||
{
|
||||
public:
|
||||
AnimationId(const ContentId& id):ContentId(id) {}
|
||||
AnimationId(const char* id):ContentId(id) {}
|
||||
AnimationId(const std::string& id):ContentId(id) {}
|
||||
AnimationId() {}
|
||||
|
||||
bool isActive() const { return toString().substr(0, 9)=="active://"; }
|
||||
|
||||
static AnimationId nullAnimation() {
|
||||
static AnimationId t; // note - the name in the contentId will get a boost call_once
|
||||
return t;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
#include "FastLog.h"
|
||||
#include "Util/AsyncHttpQueue.h"
|
||||
#include "rbx/make_shared.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
template<typename CachedContent, bool Log=false>
|
||||
class AsyncHttpCache
|
||||
:public AsyncHttpQueue
|
||||
{
|
||||
public:
|
||||
AsyncHttpCache(Instance* owner, boost::function<bool(const std::string&, std::string*)> getLocalFile, int threadCount, int cacheSize)
|
||||
:AsyncHttpQueue(owner, getLocalFile, threadCount)
|
||||
,contentCache(cacheSize)
|
||||
{}
|
||||
shared_ptr<const Reflection::ValueArray> getRequestedUrls()
|
||||
{
|
||||
shared_ptr<Reflection::ValueArray> result(rbx::make_shared<Reflection::ValueArray>());
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lock(contentCacheMutex);
|
||||
for (typename ContentCache::List_Iter iter = contentCache.begin(); iter != contentCache.end(); ++iter)
|
||||
{
|
||||
ContentId id(iter->first);
|
||||
if (id.isHttp())
|
||||
result->push_back(id.toString());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock lock(requestSync);
|
||||
std::list< FailedUrl >::const_iterator end = failedUrls.end();
|
||||
for (std::list< FailedUrl >::const_iterator iter = failedUrls.begin(); iter!=end; ++iter)
|
||||
{
|
||||
result->push_back(iter->url);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void setCacheSize(int count)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(contentCacheMutex);
|
||||
contentCache.resize(count);
|
||||
}
|
||||
|
||||
bool findCacheItem(const std::string& id, CachedContent* result)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(contentCacheMutex);
|
||||
return contentCache.fetch(id, result);
|
||||
}
|
||||
void removeCacheItem(const std::string& id)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(contentCacheMutex);
|
||||
contentCache.remove(id);
|
||||
}
|
||||
void invalidateCacheItemOrFailure(const std::string& id)
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lock(contentCacheMutex);
|
||||
contentCache.remove(id);
|
||||
}
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock lock(requestSync);
|
||||
std::list<FailedUrl>::iterator found = failedUrls.end();
|
||||
for (std::list<FailedUrl>::iterator itr = failedUrls.begin();
|
||||
itr != failedUrls.end() && found == failedUrls.end(); ++itr)
|
||||
{
|
||||
if (itr->url == id)
|
||||
{
|
||||
found = itr;
|
||||
}
|
||||
}
|
||||
if (found != failedUrls.end())
|
||||
failedUrls.erase(found);
|
||||
}
|
||||
}
|
||||
void insertCacheItem(const std::string& id, const CachedContent& result)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(contentCacheMutex);
|
||||
contentCache.insert(id, result);
|
||||
}
|
||||
void renameCacheItem(const std::string& id, const std::string& newId)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(contentCacheMutex);
|
||||
CachedContent content;
|
||||
if (contentCache.fetch(id, &content))
|
||||
{
|
||||
//"rename" the entry.
|
||||
contentCache.remove(id);
|
||||
contentCache.insert(newId, content);
|
||||
}
|
||||
}
|
||||
|
||||
void clearCache()
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lock(contentCacheMutex);
|
||||
contentCache.clear();
|
||||
}
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock lock(requestSync);
|
||||
failedUrls.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void printContentNames()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(contentCacheMutex);
|
||||
contentCache.printContentNames();
|
||||
}
|
||||
|
||||
protected:
|
||||
/*override*/ void registerContent(const std::string& url, shared_ptr<const std::string> response, shared_ptr<const std::string> filename)
|
||||
{
|
||||
if(Log) FASTLOGS(FLog::HttpQueue, "URL(%s)", url.c_str());
|
||||
boost::mutex::scoped_lock lock(contentCacheMutex);
|
||||
contentCache.insert(url, CachedContent(response, filename));
|
||||
}
|
||||
typedef SizeEnforcedLRUCache<std::string, CachedContent> ContentCache;
|
||||
|
||||
boost::mutex contentCacheMutex; //synchronizes the contentCache
|
||||
ContentCache contentCache;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "util/name.h"
|
||||
#include "rbx/boost.hpp"
|
||||
#include "rbx/rbxTime.h"
|
||||
#include "Util/contentid.h"
|
||||
#include "Util/HeartbeatInstance.h"
|
||||
#include "Util/LRUCache.h"
|
||||
#include "Util/ThreadPool.h"
|
||||
#include "Util/Http.h"
|
||||
#include "V8Tree/Service.h"
|
||||
|
||||
LOGGROUP(HttpQueue)
|
||||
|
||||
namespace RBX {
|
||||
class DataModel;
|
||||
class HttpQueueStatsItem;
|
||||
|
||||
class AsyncHttpQueue
|
||||
: public boost::enable_shared_from_this<AsyncHttpQueue>
|
||||
, public boost::noncopyable
|
||||
{
|
||||
shared_ptr<HttpQueueStatsItem> statsItem;
|
||||
|
||||
public:
|
||||
typedef enum { Waiting, Succeeded, Failed } RequestResult;
|
||||
typedef enum { AsyncInline, AsyncNone, AsyncRead, AsyncWrite} ResultJob;
|
||||
|
||||
typedef boost::function<void(RequestResult, std::istream*, shared_ptr<const std::string> response, shared_ptr<std::exception> exception)> RequestCallback;
|
||||
|
||||
struct CallbackWrapper
|
||||
{
|
||||
RequestCallback callback;
|
||||
ResultJob jobType;
|
||||
CallbackWrapper(RequestCallback callback, ResultJob jobType)
|
||||
:callback(callback)
|
||||
,jobType(jobType)
|
||||
{}
|
||||
};
|
||||
|
||||
void setThreadPool(int count);
|
||||
void setCachePolicy(const HttpCache::Policy policy) { cachePolicy = policy; }
|
||||
|
||||
bool isRequestQueueEmpty();
|
||||
bool isUrlBad(const std::string& id);
|
||||
|
||||
void asyncRequest(const std::string& id, float priority, RequestCallback* callback, ResultJob jobType, bool ignoreBadRequests=false, const std::string& expectedType = "");
|
||||
bool syncRequest(const std::string& id, const std::string& expectedType = "");
|
||||
|
||||
|
||||
static void dispatchGenericCallback(boost::function<void(DataModel*)> theCallback, Instance* instance, ResultJob jobType);
|
||||
static void dispatchCallback(RequestCallback theCallback, Instance* instance,
|
||||
RequestResult result, boost::shared_ptr<const std::string> data, ResultJob jobType, shared_ptr<std::exception> exception);
|
||||
|
||||
AsyncHttpQueue(Instance* owner,boost::function<bool(const std::string& url, std::string* result)> getLocalFile, int threadCount);
|
||||
virtual ~AsyncHttpQueue();
|
||||
void onHeartbeat(const Heartbeat& heartbeatEvent);
|
||||
|
||||
int getRequestQueueSize() const;
|
||||
shared_ptr<const Reflection::ValueArray> getFailedUrls();
|
||||
shared_ptr<const Reflection::ValueArray> getRequestQueueUrls();
|
||||
|
||||
void resetStatsItem(ServiceProvider* provider);
|
||||
double getAvgTimeInQueue() { return avgTimeInQueue.value(); }
|
||||
double getAvgRequestCompleteTime() { return avgRequestCompleteTime.value(); }
|
||||
int getNumSlowRequests() {return numSlowRequests;}
|
||||
|
||||
protected:
|
||||
virtual void registerContent(const std::string& url, shared_ptr<const std::string> response, shared_ptr<const std::string> filename)
|
||||
{}
|
||||
struct Request
|
||||
{
|
||||
std::string url;
|
||||
std::vector<CallbackWrapper> callbacks;
|
||||
float priority;
|
||||
std::string expectedType; // used in header
|
||||
boost::shared_ptr<Http> http; // keep a handle so we can cancel.
|
||||
RBX::Time startTime; // the time when this request was issued
|
||||
bool operator==(const std::string& url) const { return this->url==url; }
|
||||
};
|
||||
|
||||
RunningAverage<double> avgTimeInQueue; // in msec
|
||||
RunningAverage<double> avgRequestCompleteTime; // in msec
|
||||
int numSlowRequests;
|
||||
|
||||
struct FailedUrl
|
||||
{
|
||||
std::string url;
|
||||
RBX::Time expiration;
|
||||
FailedUrl(const char* url);
|
||||
bool expired() const;
|
||||
};
|
||||
|
||||
typedef std::list< Request > RequestList;
|
||||
typedef RequestList::iterator RequestHandle;
|
||||
|
||||
struct AsyncRetryTask
|
||||
{
|
||||
double retryTime;
|
||||
RequestHandle request;
|
||||
AsyncRetryTask(RequestHandle request , double retryTime)
|
||||
:request(request), retryTime(retryTime)
|
||||
{}
|
||||
};
|
||||
|
||||
mutable boost::recursive_mutex requestSync; // synchronizes the requestQueue and failedUrls queue, and threadPool
|
||||
// also used to protect modification of the http shared pointer.
|
||||
|
||||
|
||||
RequestList requestQueue; // queue of requested URLs
|
||||
std::list< FailedUrl > failedUrls; // List of bad URLs
|
||||
|
||||
boost::scoped_ptr<PriorityThreadPool> threadPool;
|
||||
|
||||
boost::recursive_mutex asyncRetrySync;
|
||||
std::queue<AsyncRetryTask> asyncRetryTasks;
|
||||
|
||||
double currentWallTime;
|
||||
|
||||
static void processRequests(boost::weak_ptr<AsyncHttpQueue> httpQueue, RequestHandle request, boost::shared_ptr<rbx::spin_mutex> lock);
|
||||
void addAsyncRetryTask(RequestHandle request);
|
||||
|
||||
Instance* owner;
|
||||
boost::function<bool(const std::string& url, std::string* result)> getLocalFile;
|
||||
|
||||
HttpCache::Policy cachePolicy;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
// Class that can average 512 prior values using only 9 floats for storage
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
template<typename T>
|
||||
class Average {
|
||||
private:
|
||||
size_t samples;
|
||||
size_t tag;
|
||||
std::vector<T> history;
|
||||
|
||||
public:
|
||||
Average(size_t samples, T initValue) : samples(samples), tag(0)
|
||||
{
|
||||
history.resize(samples, initValue);
|
||||
}
|
||||
|
||||
void sample(T value, bool advanceBuffer = true)
|
||||
{
|
||||
history[tag] = value;
|
||||
if (advanceBuffer) {
|
||||
tag = (tag + 1) % samples;
|
||||
}
|
||||
}
|
||||
|
||||
T getAverage() const
|
||||
{
|
||||
T answer = T();
|
||||
for (size_t i = 0; i < samples; ++i) {
|
||||
answer += history[i];
|
||||
}
|
||||
return answer / static_cast<float>(samples);
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return samples;
|
||||
}
|
||||
|
||||
const T& getValue(size_t index) const {
|
||||
return history[index];
|
||||
}
|
||||
|
||||
void resetValues(const T& value) {
|
||||
for (size_t i = 0; i < samples; ++i) {
|
||||
history[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void resetValues(size_t samplesNew, const T& value) {
|
||||
for (size_t i = 0; i < samples; ++i) {
|
||||
history[i] = value;
|
||||
}
|
||||
history.resize(samplesNew, value);
|
||||
samples = samplesNew;
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Copyright 2003-2009 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Util/NormalId.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
//A utility class for holding a set of "Faces" associated with an object (top, bottom, left, right, front, back)
|
||||
class Axes
|
||||
{
|
||||
public:
|
||||
static int axisToMask(Vector3::Axis axis);
|
||||
static Vector3::Axis normalIdToAxis(NormalId normalId);
|
||||
static NormalId axisToNormalId(Vector3::Axis axis);
|
||||
|
||||
public:
|
||||
Axes(int axisMask = 0);
|
||||
void clear() { axisMask = 0; }
|
||||
void setAxisByNormalId(NormalId normalId, bool value);
|
||||
bool getAxisByNormalId(NormalId normalId) const;
|
||||
void setAxis(Vector3::Axis axis, bool value);
|
||||
bool getAxis(Vector3::Axis axis) const;
|
||||
|
||||
|
||||
|
||||
bool operator==(const Axes& other) const {
|
||||
return axisMask == other.axisMask;
|
||||
}
|
||||
bool operator!=(const Axes& other) const {
|
||||
return axisMask != other.axisMask;
|
||||
}
|
||||
|
||||
|
||||
int axisMask;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "boost/cstdint.hpp"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
struct Base64BinaryInputStream {
|
||||
private:
|
||||
const char* source;
|
||||
boost::uint16_t buffer;
|
||||
size_t readableBitsInBuffer;
|
||||
static unsigned char decode(unsigned char charFromString);
|
||||
|
||||
public:
|
||||
Base64BinaryInputStream(const char* source);
|
||||
|
||||
// numBitsToRead needs to be >= 1 and <= 8.
|
||||
void ReadBits(unsigned char* out, size_t numBitsToRead);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
struct Base64BinaryOutputStream {
|
||||
private:
|
||||
static const char* kTranslateToBase64;
|
||||
|
||||
std::ostringstream result;
|
||||
unsigned char buffer;
|
||||
size_t bitsUsed;
|
||||
|
||||
public:
|
||||
|
||||
Base64BinaryOutputStream();
|
||||
|
||||
// NOT A REAL IMPLEMENTATION -- ONLY PRESENT TO SATISFY TEMPLATES
|
||||
size_t GetNumberOfBytesUsed() const;
|
||||
|
||||
// numBitsToAdd must be >= 0 and <= 8. Only the character immediately
|
||||
// pointed to by data will be read
|
||||
void WriteBits(const unsigned char* data, size_t numBitsToAdd);
|
||||
|
||||
// make sure to call this method exactly once: when you will no longer
|
||||
// call WriteBits again on this object.
|
||||
void done(std::string* out);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include "rbx/Debug.h"
|
||||
#include <map>
|
||||
|
||||
// Poor man's version of a Bi-MultiMap. Restriction is that each "pair" can only be here once
|
||||
// Assumes we can have many A's, many B's
|
||||
// Need to re-write with dual indexed multi-set or some other data structure
|
||||
|
||||
namespace RBX {
|
||||
|
||||
template <typename Left, typename Right>
|
||||
class BiMultiMap {
|
||||
public:
|
||||
typedef std::multimap<Left, Right> InternalMap;
|
||||
typedef typename InternalMap::iterator InternalMapIt;
|
||||
InternalMap internalMap;
|
||||
|
||||
bool pairInMap(const Left& left, const Right& right) {
|
||||
InternalMapIt it;
|
||||
for (it = internalMap.lower_bound(left); it != internalMap.upper_bound(left); ++it) {
|
||||
if (it->second == right) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void insertPair(const Left& left, const Right& right) {
|
||||
RBXASSERT_SLOW(!pairInMap(left, right));
|
||||
internalMap.insert(std::make_pair(left, right));
|
||||
}
|
||||
|
||||
void removePair(const Left& left, const Right& right) {
|
||||
RBXASSERT_SLOW(pairInMap(left, right));
|
||||
typename InternalMap::iterator it;
|
||||
for (it = internalMap.lower_bound(left); it != internalMap.upper_bound(left); ++it) {
|
||||
if (it->second == right) {
|
||||
internalMap.erase(it);
|
||||
RBXASSERT(!pairInMap(left, right));
|
||||
return;
|
||||
}
|
||||
}
|
||||
RBXASSERT(0);
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return internalMap.empty();
|
||||
}
|
||||
|
||||
bool emptyLeft(const Left& left) const {
|
||||
return (internalMap.lower_bound(left) == internalMap.upper_bound(left));
|
||||
}
|
||||
|
||||
template<class Func>
|
||||
inline void visitEachLeft(const Left& left, const Func& func) const {
|
||||
typename InternalMap::const_iterator it;
|
||||
for (it = internalMap.lower_bound(left); it != internalMap.upper_bound(left); ++it) {
|
||||
const Right& right = it->second;
|
||||
func(left, right);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
// use this for properties that contain binary data so that they're serialized to XML without roundtrip issues
|
||||
class BinaryString
|
||||
{
|
||||
public:
|
||||
BinaryString()
|
||||
{
|
||||
}
|
||||
|
||||
explicit BinaryString(const std::string& value)
|
||||
: internalValue(value)
|
||||
{
|
||||
}
|
||||
|
||||
const std::string& value() const
|
||||
{
|
||||
return internalValue;
|
||||
}
|
||||
|
||||
void set(const char* buffer, unsigned int size)
|
||||
{
|
||||
internalValue.assign(buffer, size);
|
||||
}
|
||||
|
||||
bool operator==(const BinaryString& other) const
|
||||
{
|
||||
return internalValue == other.internalValue;
|
||||
}
|
||||
|
||||
bool operator!=(const BinaryString& other) const
|
||||
{
|
||||
return internalValue != other.internalValue;
|
||||
}
|
||||
|
||||
bool operator<(const BinaryString& other) const
|
||||
{
|
||||
return internalValue < other.internalValue;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string internalValue;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,335 @@
|
||||
/* Copyright 2003-2006 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "G3D/Color3.h"
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/Color3uint8.h"
|
||||
#include "G3D/Color4uint8.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
// A collection of official ROBLOX colors
|
||||
class BrickColor
|
||||
{
|
||||
class BrickMap;
|
||||
public:
|
||||
enum Number {
|
||||
brick_1 = 1,
|
||||
brick_2 = 2,
|
||||
brick_3 = 3,
|
||||
brick_5 = 5,
|
||||
brick_6 = 6,
|
||||
brick_9 = 9,
|
||||
brick_11 = 11,
|
||||
brick_12 = 12,
|
||||
brick_18 = 18,
|
||||
brick_21 = 21,
|
||||
brick_22 = 22,
|
||||
brick_23 = 23,
|
||||
brick_24 = 24,
|
||||
brick_25 = 25,
|
||||
brick_26 = 26,
|
||||
brick_27 = 27,
|
||||
brick_28 = 28,
|
||||
brick_29 = 29,
|
||||
brick_36 = 36,
|
||||
brick_37 = 37,
|
||||
brick_38 = 38,
|
||||
brick_39 = 39,
|
||||
brick_40 = 40,
|
||||
brick_41 = 41,
|
||||
brick_42 = 42,
|
||||
brick_43 = 43,
|
||||
brick_44 = 44,
|
||||
brick_45 = 45,
|
||||
brick_47 = 47,
|
||||
brick_48 = 48,
|
||||
brick_49 = 49,
|
||||
brick_50 = 50,
|
||||
brick_100 = 100,
|
||||
brick_101 = 101,
|
||||
brick_102 = 102,
|
||||
brick_103 = 103,
|
||||
brick_104 = 104,
|
||||
brick_105 = 105,
|
||||
brick_106 = 106,
|
||||
brick_107 = 107,
|
||||
brick_108 = 108,
|
||||
brick_110 = 110,
|
||||
brick_111 = 111,
|
||||
brick_112 = 112,
|
||||
brick_113 = 113,
|
||||
brick_115 = 115,
|
||||
brick_116 = 116,
|
||||
brick_118 = 118,
|
||||
brick_119 = 119,
|
||||
brick_120 = 120,
|
||||
brick_121 = 121,
|
||||
brick_123 = 123,
|
||||
brick_124 = 124,
|
||||
brick_125 = 125,
|
||||
brick_126 = 126,
|
||||
brick_127 = 127,
|
||||
brick_128 = 128,
|
||||
brick_131 = 131,
|
||||
brick_133 = 133,
|
||||
brick_134 = 134,
|
||||
brick_135 = 135,
|
||||
brick_136 = 136,
|
||||
brick_137 = 137,
|
||||
brick_138 = 138,
|
||||
brick_140 = 140,
|
||||
brick_141 = 141,
|
||||
brick_143 = 143,
|
||||
brick_145 = 145,
|
||||
brick_146 = 146,
|
||||
brick_147 = 147,
|
||||
brick_148 = 148,
|
||||
brick_149 = 149,
|
||||
brick_150 = 150,
|
||||
brick_151 = 151,
|
||||
brick_153 = 153,
|
||||
brick_154 = 154,
|
||||
brick_157 = 157,
|
||||
brick_158 = 158,
|
||||
brick_168 = 168,
|
||||
brick_176 = 176,
|
||||
brick_178 = 178,
|
||||
brick_179 = 179,
|
||||
brick_180 = 180,
|
||||
brick_190 = 190,
|
||||
brick_191 = 191,
|
||||
brick_192 = 192,
|
||||
brick_193 = 193,
|
||||
brick_194 = 194,
|
||||
brick_195 = 195,
|
||||
brick_196 = 196,
|
||||
brick_198 = 198,
|
||||
brick_199 = 199,
|
||||
brick_200 = 200,
|
||||
brick_208 = 208,
|
||||
brick_209 = 209,
|
||||
brick_210 = 210,
|
||||
brick_211 = 211,
|
||||
brick_212 = 212,
|
||||
brick_213 = 213,
|
||||
brick_216 = 216,
|
||||
brick_217 = 217,
|
||||
brick_218 = 218,
|
||||
brick_219 = 219,
|
||||
brick_220 = 220,
|
||||
brick_221 = 221,
|
||||
brick_222 = 222,
|
||||
brick_223 = 223,
|
||||
brick_224 = 224,
|
||||
brick_225 = 225,
|
||||
brick_226 = 226,
|
||||
brick_232 = 232,
|
||||
brick_268 = 268,
|
||||
brick_301 = 301,
|
||||
brick_302 = 302,
|
||||
brick_303 = 303,
|
||||
brick_304 = 304,
|
||||
brick_305 = 305,
|
||||
brick_306 = 306,
|
||||
brick_307 = 307,
|
||||
brick_308 = 308,
|
||||
brick_309 = 309,
|
||||
brick_310 = 310,
|
||||
brick_311 = 311,
|
||||
brick_312 = 312,
|
||||
brick_313 = 313,
|
||||
brick_314 = 314,
|
||||
brick_315 = 315,
|
||||
brick_316 = 316,
|
||||
brick_317 = 317,
|
||||
brick_318 = 318,
|
||||
brick_319 = 319,
|
||||
brick_320 = 320,
|
||||
brick_321 = 321,
|
||||
brick_322 = 322,
|
||||
brick_323 = 323,
|
||||
brick_324 = 324,
|
||||
brick_325 = 325,
|
||||
//brick_326 = 326,
|
||||
brick_327 = 327,
|
||||
brick_328 = 328,
|
||||
brick_329 = 329,
|
||||
brick_330 = 330,
|
||||
brick_331 = 331,
|
||||
brick_332 = 332,
|
||||
brick_333 = 333,
|
||||
brick_334 = 334,
|
||||
brick_335 = 335,
|
||||
brick_336 = 336,
|
||||
brick_337 = 337,
|
||||
brick_338 = 338,
|
||||
brick_339 = 339,
|
||||
brick_340 = 340,
|
||||
brick_341 = 341,
|
||||
brick_342 = 342,
|
||||
brick_343 = 343,
|
||||
brick_344 = 344,
|
||||
brick_345 = 345,
|
||||
brick_346 = 346,
|
||||
brick_347 = 347,
|
||||
brick_348 = 348,
|
||||
brick_349 = 349,
|
||||
brick_350 = 350,
|
||||
brick_351 = 351,
|
||||
brick_352 = 352,
|
||||
brick_353 = 353,
|
||||
brick_354 = 354,
|
||||
brick_355 = 355,
|
||||
brick_356 = 356,
|
||||
brick_357 = 357,
|
||||
brick_358 = 358,
|
||||
brick_359 = 359,
|
||||
brick_360 = 360,
|
||||
brick_361 = 361,
|
||||
brick_362 = 362,
|
||||
brick_363 = 363,
|
||||
brick_364 = 364,
|
||||
brick_365 = 365,
|
||||
roblox_1001 = 1001,
|
||||
roblox_1002 = 1002,
|
||||
roblox_1003 = 1003,
|
||||
roblox_1004 = 1004,
|
||||
roblox_1005 = 1005,
|
||||
roblox_1006 = 1006,
|
||||
roblox_1007 = 1007,
|
||||
roblox_1008 = 1008,
|
||||
roblox_1009 = 1009,
|
||||
roblox_1010 = 1010,
|
||||
roblox_1011 = 1011,
|
||||
roblox_1012 = 1012,
|
||||
roblox_1013 = 1013,
|
||||
roblox_1014 = 1014,
|
||||
roblox_1015 = 1015,
|
||||
roblox_1016 = 1016,
|
||||
roblox_1017 = 1017,
|
||||
roblox_1018 = 1018,
|
||||
roblox_1019 = 1019,
|
||||
roblox_1020 = 1020,
|
||||
roblox_1021 = 1021,
|
||||
roblox_1022 = 1022,
|
||||
roblox_1023 = 1023,
|
||||
roblox_1024 = 1024,
|
||||
roblox_1025 = 1025,
|
||||
roblox_1026 = 1026,
|
||||
roblox_1027 = 1027,
|
||||
roblox_1028 = 1028,
|
||||
roblox_1029 = 1029,
|
||||
roblox_1030 = 1030,
|
||||
roblox_1031 = 1031,
|
||||
roblox_1032 = 1032
|
||||
};
|
||||
Number number;
|
||||
typedef std::vector< BrickColor > Colors;
|
||||
static const Colors& colorPalette(); // colors shown in UI
|
||||
static const Colors& renderingPalette(); // colors supported by renderer
|
||||
static const Colors& allColors(); // all known colors
|
||||
|
||||
// returns the 0-based index of the color
|
||||
size_t getClosestRenderingPaletteIndex() const; // closest "supported" palette index by the GFX engine.
|
||||
size_t getClosestPaletteIndex() const; // closest palette index from the _whole_ palette list.
|
||||
static const size_t paletteSize = 128; // supported by UI and data model.
|
||||
static const size_t paletteSizeMSB = 7; // == log2(paletteSize)
|
||||
|
||||
static void setRenderingSupportedPaletteSize(size_t maxSupportedColors);
|
||||
|
||||
// Constructor/Factory
|
||||
BrickColor(Number number):number(number) {
|
||||
}
|
||||
BrickColor():number(brick_194) {
|
||||
}
|
||||
explicit BrickColor(int number);
|
||||
static BrickColor closest(G3D::Color3uint8 color);
|
||||
static BrickColor closest(G3D::Color4uint8 color);
|
||||
static BrickColor closest(G3D::Color3 color);
|
||||
static BrickColor closest(G3D::Color4 color);
|
||||
static BrickColor parse(const char* name);
|
||||
static BrickColor random();
|
||||
inline static BrickColor brickWhite()
|
||||
{
|
||||
return brick_1;
|
||||
}
|
||||
inline static BrickColor brickGray()
|
||||
{
|
||||
return brick_194;
|
||||
}
|
||||
inline static BrickColor brickDarkGray()
|
||||
{
|
||||
return brick_199;
|
||||
}
|
||||
inline static BrickColor brickBlack()
|
||||
{
|
||||
return brick_26;
|
||||
}
|
||||
inline static BrickColor brickRed()
|
||||
{
|
||||
return brick_21;
|
||||
}
|
||||
inline static BrickColor brickYellow()
|
||||
{
|
||||
return brick_24;
|
||||
}
|
||||
inline static BrickColor brickGreen()
|
||||
{
|
||||
return brick_28;
|
||||
}
|
||||
inline static BrickColor baseplateGreen()
|
||||
{
|
||||
return brick_37;
|
||||
}
|
||||
inline static BrickColor brickBlue()
|
||||
{
|
||||
return brick_23;
|
||||
}
|
||||
inline static BrickColor defaultColor()
|
||||
{
|
||||
return BrickColor();
|
||||
}
|
||||
|
||||
// Assignment
|
||||
BrickColor& operator=(const BrickColor& other)
|
||||
{
|
||||
number = other.number;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//Query
|
||||
G3D::Color4uint8 color4uint8() const;
|
||||
G3D::Color3uint8 color3uint8() const;
|
||||
G3D::Color4 color4() const;
|
||||
G3D::Color3 color3() const;
|
||||
const std::string& name() const;
|
||||
|
||||
// returns the number as an int, not an ARGB
|
||||
int asInt() const { return number; }
|
||||
|
||||
// Comparison
|
||||
bool operator==(const BrickColor& other) const {
|
||||
return number==other.number;
|
||||
}
|
||||
bool operator!=(const BrickColor& other) const {
|
||||
return number!=other.number;
|
||||
}
|
||||
bool operator>(const BrickColor& other) const {
|
||||
return number>other.number;
|
||||
}
|
||||
bool operator<(const BrickColor& other) const {
|
||||
return number<other.number;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
std::size_t hash_value(const BrickColor& c);
|
||||
|
||||
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,35 @@
|
||||
/* Copyright 2003-2006 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
// TODO - move to datamodel, out of UTIL
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
#include "Util/IHasLocation.h"
|
||||
#include <vector>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Primitive;
|
||||
class Camera;
|
||||
|
||||
class RBXBaseClass CameraSubject : public virtual IHasLocation
|
||||
{
|
||||
public:
|
||||
CameraSubject() {}
|
||||
|
||||
virtual ~CameraSubject() {}
|
||||
|
||||
// Old Camera Subject Stuff
|
||||
/*implement*/ virtual void onCameraHeartbeat(const Vector3& cameraLocation, const Vector3& focusPoint) {}
|
||||
/*implement*/ virtual const CoordinateFrame getRenderLocation() = 0; // goes to the rendering location, not the regular location
|
||||
/*implement*/ virtual const Vector3 getRenderSize() = 0;
|
||||
/*implement*/ virtual void onCameraNear(float distance) {}
|
||||
/*implement*/ virtual void getCameraIgnorePrimitives(std::vector<const Primitive*>& primitives) {}
|
||||
/*implement*/ virtual void getSelectionIgnorePrimitives(std::vector<const Primitive*>& primitives) {}
|
||||
/*implement*/ virtual void stepRotationalVelocity(Vector3& cameraLocation, Vector3& focusLocation) {}
|
||||
|
||||
protected:
|
||||
class ContactManager* getContactManager();
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,48 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
#pragma once
|
||||
|
||||
#include "G3D/Vector3.h"
|
||||
#include "V8Tree/Instance.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class CellID
|
||||
{
|
||||
private:
|
||||
bool isNil;
|
||||
RBX::Vector3 location;
|
||||
shared_ptr<Instance> terrainPart;
|
||||
public:
|
||||
CellID();
|
||||
CellID( bool isNil, const RBX::Vector3& location, shared_ptr<Instance> terrainPart )
|
||||
:isNil(isNil)
|
||||
,location(location)
|
||||
,terrainPart(terrainPart)
|
||||
{
|
||||
}
|
||||
CellID( bool newIsNil, float newLocation[3], shared_ptr<Instance> newTerrainPart );
|
||||
~CellID();
|
||||
|
||||
bool operator ==(const CellID& other) const
|
||||
{
|
||||
if (isNil != other.isNil)
|
||||
return false;
|
||||
if (location != other.location)
|
||||
return false;
|
||||
if (terrainPart != other.terrainPart)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getIsNil() const { return isNil; }
|
||||
void setIsNil( bool newIsNil ) { isNil = newIsNil; }
|
||||
|
||||
G3D::Vector3 getLocation() const { return location; }
|
||||
void setLocation( RBX::Vector3 newLocation ) { location = newLocation; }
|
||||
|
||||
shared_ptr<Instance> getTerrainPart() const { return terrainPart; }
|
||||
void setTerrainPart( shared_ptr<Instance> newTerrainPart ) { terrainPart = newTerrainPart; }
|
||||
|
||||
static CellID fromParameters( bool newIsNil, float newLocation[3], shared_ptr<Instance> newTerrainPart ) { return CellID( newIsNil, newLocation, newTerrainPart ); }
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
|
||||
#include <ctime>
|
||||
#include "rbx/TaskScheduler.Job.h"
|
||||
#include <util/HeapValue.h>
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
bool vmProtectedDetectCheatEngineIcon();
|
||||
|
||||
class HwndScanner
|
||||
{
|
||||
struct fullWindowInfo {
|
||||
DWORD winWidth;
|
||||
DWORD winHeight;
|
||||
DWORD pid;
|
||||
DWORD active;
|
||||
std::string title;
|
||||
bool kickEarly;
|
||||
static size_t compareByPid ( fullWindowInfo lhs, fullWindowInfo rhs);
|
||||
};
|
||||
std::vector<fullWindowInfo> hwndScanResults;
|
||||
static BOOL CALLBACK makeHwndVector(HWND hwnd, LPARAM lParam);
|
||||
|
||||
public:
|
||||
HwndScanner();
|
||||
|
||||
int scan();
|
||||
|
||||
bool detectTitle() const;
|
||||
|
||||
// This method will always return false on Windows8.
|
||||
bool detectFakeAttach() const;
|
||||
bool detectEarlyKick() const;
|
||||
|
||||
};
|
||||
|
||||
class FileScanner
|
||||
{
|
||||
std::time_t baseTime;
|
||||
std::string tempFolder;
|
||||
public:
|
||||
FileScanner();
|
||||
|
||||
bool detectLogUpdate() const;
|
||||
};
|
||||
|
||||
extern bool ceDetected;
|
||||
extern bool ceHwndChecks;
|
||||
static const unsigned int kCeStructKey = 0x23A7F;
|
||||
static const unsigned char kCeCharKey = 0x55;
|
||||
|
||||
HANDLE setupCeLogWatcher();
|
||||
|
||||
// A job to profile this detection method and optionally enable it.
|
||||
class VerifyConnectionJob : public RBX::TaskScheduler::Job
|
||||
{
|
||||
public:
|
||||
VerifyConnectionJob();
|
||||
/*override*/ RBX::Time::Interval sleepTime(const Stats& stats);
|
||||
/*override*/ Job::Error error(const Stats& stats);
|
||||
/*override*/ TaskScheduler::StepResult step(const Stats& stats);
|
||||
/*override*/ double getPriorityFactor();
|
||||
|
||||
};
|
||||
|
||||
bool isSandboxie();
|
||||
bool isCeBadDll();
|
||||
|
||||
// This class does dbvm detection and also breaks on certain dll injection methods.
|
||||
class DbvmCanary
|
||||
{
|
||||
private:
|
||||
HANDLE canaryCage;
|
||||
HANDLE canaryHandle;
|
||||
CONTEXT ctx;
|
||||
size_t hashValue;
|
||||
static void canary(HANDLE* mutex);
|
||||
inline size_t hashDbgRegs(CONTEXT& ctx)
|
||||
{
|
||||
return (ctx.Dr0*54321) + (ctx.Dr1*98765) ^ (ctx.Dr2*6543) - (ctx.Dr3*987);
|
||||
}
|
||||
public:
|
||||
DbvmCanary();
|
||||
void checkAndLocalUpdate();
|
||||
void kernelUpdate();
|
||||
};
|
||||
|
||||
class SpeedhackDetect
|
||||
{
|
||||
private:
|
||||
DWORD k32base;
|
||||
DWORD k32size;
|
||||
public:
|
||||
SpeedhackDetect();
|
||||
bool isSpeedhack();
|
||||
};
|
||||
|
||||
extern HeapValue<uintptr_t> vehHookLocationHv;
|
||||
extern HeapValue<uintptr_t> vehStubLocationHv;
|
||||
extern void* vehHookContinue;
|
||||
|
||||
void addWriteBreakpoint(uintptr_t addr);
|
||||
void removeWriteBreakpoint(uintptr_t addr);
|
||||
|
||||
__declspec(align(4096)) extern int writecopyTrap[4096];
|
||||
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,136 @@
|
||||
#pragma once
|
||||
|
||||
#include "G3DCore.h"
|
||||
#include "rbx/Debug.h"
|
||||
#include "Voxel/Cell.h"
|
||||
#include "Voxel/Util.h"
|
||||
#include "Util/StreamRegion.h"
|
||||
#include "Util/SpatialRegion.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class ClusterChunksIterator
|
||||
{
|
||||
public:
|
||||
ClusterChunksIterator()
|
||||
: indexOfNextCellToIssue(0)
|
||||
, internalSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit ClusterChunksIterator(const std::vector<SpatialRegion::Id>& chunks)
|
||||
: chunks(chunks)
|
||||
, indexOfNextCellToIssue(0)
|
||||
, internalSize(chunks.size() * kChunkSize)
|
||||
{
|
||||
}
|
||||
|
||||
// single chunk
|
||||
explicit ClusterChunksIterator(const SpatialRegion::Id& chunk)
|
||||
: indexOfNextCellToIssue(0)
|
||||
, internalSize(kChunkSize)
|
||||
{
|
||||
chunks.push_back(chunk);
|
||||
}
|
||||
|
||||
static inline void nextCellInIterationOrder(const Vector3int16& cellpos, Vector3int16* out)
|
||||
{
|
||||
unsigned int index = (cellpos.x & 0x1f) | ((cellpos.z & 0x1f) << 5) | ((cellpos.y & 0x0f) << 10);
|
||||
|
||||
if (index == kChunkSize - 1)
|
||||
{
|
||||
// last cell in a chunk, it does not matter what we return except that it has to be a different chunk
|
||||
*out = cellpos + Vector3int16(1, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int next = index + 1;
|
||||
Vector3int16 local = Vector3int16((next & 0x1f), ((next >> 10) & 0xf), ((next >> 5) & 0x1f));
|
||||
|
||||
*out = SpatialRegion::globalVoxelCoordinateFromRegionAndRelativeCoordinate(SpatialRegion::regionContainingVoxel(cellpos), local);
|
||||
}
|
||||
}
|
||||
|
||||
inline void pop(Vector3int16* out)
|
||||
{
|
||||
RBXASSERT(internalSize > 0);
|
||||
|
||||
Vector3int16 local = Vector3int16((indexOfNextCellToIssue & 0x1f), ((indexOfNextCellToIssue >> 10) & 0xf), ((indexOfNextCellToIssue >> 5) & 0x1f));
|
||||
|
||||
*out = SpatialRegion::globalVoxelCoordinateFromRegionAndRelativeCoordinate(chunks[indexOfNextCellToIssue / kChunkSize], local);
|
||||
|
||||
indexOfNextCellToIssue++;
|
||||
internalSize--;
|
||||
}
|
||||
|
||||
inline bool chk(const Vector3int16& pos) const
|
||||
{
|
||||
return internalSize > 0;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return internalSize;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<SpatialRegion::Id> chunks;
|
||||
size_t indexOfNextCellToIssue;
|
||||
size_t internalSize;
|
||||
|
||||
enum { kChunkSize = Voxel::kXZ_CHUNK_SIZE * Voxel::kXZ_CHUNK_SIZE * Voxel::kY_CHUNK_SIZE };
|
||||
};
|
||||
|
||||
// Cell iterator for 1/4 of a chunk.
|
||||
struct OneQuarterClusterChunkCellIterator
|
||||
{
|
||||
Vector3int16 cellOffset;
|
||||
unsigned short internalCell;
|
||||
unsigned short internalSize;
|
||||
StreamRegion::Id regionId;
|
||||
|
||||
OneQuarterClusterChunkCellIterator()
|
||||
{
|
||||
setToStartOfStreamRegion(StreamRegion::Id(0,0,0));
|
||||
}
|
||||
|
||||
void setToStartOfStreamRegion(const StreamRegion::Id &_regionId)
|
||||
{
|
||||
regionId = _regionId;
|
||||
internalSize = StreamRegion::getTotalVoxelVolumeOfARegion();
|
||||
internalCell = 0;
|
||||
cellOffset = StreamRegion::getMinVoxelCoordinateInsideRegion(regionId);
|
||||
}
|
||||
|
||||
static inline void cellFromIndex(const Vector3int16 &cellOffset, unsigned int index, Vector3int16* out) {
|
||||
(*out) = cellOffset + Vector3int16(
|
||||
(index & 0xf),
|
||||
((index >> 8) & 0xf),
|
||||
((index >> 4) & 0xf));
|
||||
}
|
||||
static inline void nextCellInIterationOrder(const Vector3int16& cellpos, Vector3int16* out)
|
||||
{
|
||||
Vector3int16 offset = StreamRegion::getMinVoxelCoordinateInsideRegion(StreamRegion::regionContainingVoxel(cellpos));
|
||||
Vector3int16 delta = cellpos - offset;
|
||||
int index = delta.x | (delta.y << 8) | (delta.z << 4);
|
||||
//RBXASSERT(index+1 < (int)StreamRegion::getTotalVoxelVolumeOfARegion());
|
||||
cellFromIndex(offset, index+1, out);
|
||||
}
|
||||
|
||||
inline void pop(Vector3int16* out) {
|
||||
RBXASSERT(internalSize);
|
||||
cellFromIndex(cellOffset, internalCell, out);
|
||||
++internalCell;
|
||||
--internalSize;
|
||||
}
|
||||
|
||||
inline bool chk(const Vector3int16 &cellPos) const
|
||||
{
|
||||
return (internalSize > 0) && (StreamRegion::regionContainingVoxel(cellPos) == regionId);
|
||||
}
|
||||
inline size_t size() const {
|
||||
return internalSize;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
|
||||
/*
|
||||
see http://web.media.mit.edu/~wad/color/palette.html
|
||||
|
||||
This is an optimal 16 color palette
|
||||
|
||||
Black RGB: 0, 0, 0
|
||||
Dk. Gray RGB: 87, 87, 87
|
||||
Red RGB: 173, 35, 35
|
||||
Blue RGB: 42, 75, 215
|
||||
Green RGB: 29, 105, 20
|
||||
Brown RGB: 129, 74, 25
|
||||
Purple RGB: 129, 38, 192
|
||||
Lt. Gray RGB: 160, 160, 160
|
||||
Lt. Green RGB: 129, 197, 122
|
||||
Lt. Blue RGB: 157, 175, 255
|
||||
Cyan RGB: 41, 208, 208
|
||||
Orange RGB: 255, 146, 51
|
||||
Yellow RGB: 255, 238, 51
|
||||
Tan RGB: 233, 222, 187
|
||||
Pink RGB: 255, 205, 243
|
||||
White RGB: 255, 255, 255
|
||||
|
||||
*/
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Color {
|
||||
private:
|
||||
G3D::Color3 rgb;
|
||||
Color() {}
|
||||
Color(unsigned char r, unsigned char g, unsigned char b) : rgb(static_cast<float>(r)/255.0f, static_cast<float>(g)/255.0f, static_cast<float>(b)/255.0f) {}
|
||||
const G3D::Color3& color3() {return rgb;}
|
||||
public:
|
||||
static const G3D::Color3& getColorByIndex(int i);
|
||||
|
||||
inline static const G3D::Color3& black() {return getColorByIndex(0);}
|
||||
inline static const G3D::Color3& darkGray() {return getColorByIndex(1);}
|
||||
inline static const G3D::Color3& red() {return getColorByIndex(2);}
|
||||
inline static const G3D::Color3& blue() {return getColorByIndex(3);}
|
||||
inline static const G3D::Color3& green() {return getColorByIndex(4);}
|
||||
inline static const G3D::Color3& brown() {return getColorByIndex(5);}
|
||||
inline static const G3D::Color3& purple() {return getColorByIndex(6);}
|
||||
inline static const G3D::Color3& lightGray() {return getColorByIndex(7);}
|
||||
inline static const G3D::Color3& lightGreen() {return getColorByIndex(8);}
|
||||
inline static const G3D::Color3& lightBlue() {return getColorByIndex(9);}
|
||||
inline static const G3D::Color3& cyan() {return getColorByIndex(10);}
|
||||
inline static const G3D::Color3& orange() {return getColorByIndex(11);}
|
||||
inline static const G3D::Color3& yellow() {return getColorByIndex(12);}
|
||||
inline static const G3D::Color3& tan() {return getColorByIndex(13);}
|
||||
inline static const G3D::Color3& pink() {return getColorByIndex(14);}
|
||||
inline static const G3D::Color3& white() {return getColorByIndex(15);}
|
||||
|
||||
static const G3D::Color3& colorFromIndex8(int index);
|
||||
|
||||
static const G3D::Color3 colorFromInt(unsigned int i);
|
||||
|
||||
static const G3D::Color3 colorFromString(const std::string& s);
|
||||
|
||||
static const G3D::Color3 colorFromPointer(void* pointer);
|
||||
|
||||
static const G3D::Color3 colorFromTemperature(float temperature); // 0.0 = cold, 1.0 = hot
|
||||
|
||||
static const G3D::Color3 colorFromError(double value); // 0.0 == not important, 10.0 == very important;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
namespace RBX {
|
||||
|
||||
template <typename Enum, typename Storage> class CompactEnum
|
||||
{
|
||||
public:
|
||||
CompactEnum()
|
||||
{
|
||||
}
|
||||
|
||||
CompactEnum(Enum value): data(value)
|
||||
{
|
||||
}
|
||||
|
||||
operator Enum() const
|
||||
{
|
||||
return static_cast<Enum>(data);
|
||||
}
|
||||
|
||||
private:
|
||||
Storage data;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
//#include "Util/SoundWorld.h"
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
// A property that computes and caches its value
|
||||
template <class Type, class O>
|
||||
class ComputeProp
|
||||
{
|
||||
private:
|
||||
Type val;
|
||||
bool dirty;
|
||||
O* object;
|
||||
typedef Type (O::*GetFunc)();
|
||||
GetFunc getFunc;
|
||||
|
||||
public:
|
||||
ComputeProp(O* object, GetFunc getFunc) :
|
||||
dirty(true),
|
||||
object(object),
|
||||
getFunc(getFunc)
|
||||
{}
|
||||
inline Type getValue()
|
||||
{
|
||||
if (dirty) {
|
||||
val = (object->*getFunc)();
|
||||
dirty = false;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
inline Type getLastComputedValue() const
|
||||
{
|
||||
RBXASSERT(!dirty);
|
||||
return val;
|
||||
}
|
||||
|
||||
inline operator Type()
|
||||
{
|
||||
return getValue();
|
||||
}
|
||||
inline Type* getValuePointer()
|
||||
{
|
||||
getValue();
|
||||
return &val;
|
||||
}
|
||||
inline Type& getValueRef()
|
||||
{
|
||||
getValue();
|
||||
return val;
|
||||
}
|
||||
bool setDirty()
|
||||
{
|
||||
bool didSomething = !dirty;
|
||||
dirty = true;
|
||||
return didSomething;
|
||||
}
|
||||
bool getDirty() const
|
||||
{
|
||||
return dirty;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,134 @@
|
||||
#pragma once
|
||||
|
||||
#include "rbx/Debug.h"
|
||||
#include "rbx/atomic.h"
|
||||
|
||||
|
||||
#ifdef __RBX_NOT_RELEASE
|
||||
#define RBX_USE_CONCURRENCY_VALIDATOR(expr) (expr)
|
||||
#else
|
||||
#define RBX_USE_CONCURRENCY_VALIDATOR(expr) ((void)0)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class ConcurrencyValidator
|
||||
{
|
||||
private:
|
||||
rbx::atomic<int> writing;
|
||||
std::string writeLocation;
|
||||
mutable rbx::atomic<int> reading;
|
||||
|
||||
public:
|
||||
ConcurrencyValidator() : writing(0), reading(0)
|
||||
{
|
||||
}
|
||||
|
||||
~ConcurrencyValidator() {
|
||||
RBXASSERT(writing == 0);
|
||||
RBXASSERT(reading == 0);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class WriteValidator;
|
||||
friend class ReadOnlyValidator;
|
||||
|
||||
bool preRead() const {
|
||||
++reading;
|
||||
|
||||
long wasWriting = writing;
|
||||
if (wasWriting != 0) {RBXASSERT(false && "writing check failed in preRead");}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool postRead() const {
|
||||
long wasWriting = writing;
|
||||
if (wasWriting != 0) {RBXASSERT(false && "wasWriting check failed in postRead");}
|
||||
if (writing != 0) {RBXASSERT(false && "writing check failed in postRead");}
|
||||
|
||||
--reading;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool preWrite() {
|
||||
long wasWriting = writing;
|
||||
long wasReading = reading;
|
||||
|
||||
if (wasReading != 0) {RBXASSERT(false && "wasReading check failed in preWrite");}
|
||||
if (wasWriting != 0) {RBXASSERT(false && "wasWriting check failed in preWrite");}
|
||||
if (writing != 0) {RBXASSERT(false && "writing check failed in preWrite");}
|
||||
|
||||
long result = ++writing;
|
||||
|
||||
if (result != 1) {RBXASSERT(false && "InterlocedIncrement returned not -1 in preWrite");}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool preWrite(const std::string& writeWhere) {
|
||||
bool okWrite = preWrite();
|
||||
if (okWrite) {
|
||||
writeLocation = writeWhere;
|
||||
}
|
||||
return okWrite;
|
||||
}
|
||||
|
||||
bool postWrite() {
|
||||
long wasWriting = writing;
|
||||
long wasReading = reading;
|
||||
|
||||
if (wasWriting != 1) {RBXASSERT(false && "wasWriting check failed in postWrite");}
|
||||
if (writing != 1) {RBXASSERT(false && "writing check failed in postWrite");}
|
||||
if (wasReading != 0) {RBXASSERT(false && "wasReading check failed in postWrite");}
|
||||
if (reading != 0) {RBXASSERT(false && "reading check failed in postWrite");}
|
||||
|
||||
long result = --writing;
|
||||
if (result != 0) {RBXASSERT(false && "InterlocedIncrement returned not 0 in postWrite");}
|
||||
if (reading != 0) {RBXASSERT(false && "reading check failed in postWrite");}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class ReadOnlyValidator
|
||||
{
|
||||
private:
|
||||
const ConcurrencyValidator& concurrencyValidator;
|
||||
|
||||
public:
|
||||
ReadOnlyValidator(const ConcurrencyValidator& c) : concurrencyValidator(c) {
|
||||
RBX_USE_CONCURRENCY_VALIDATOR(concurrencyValidator.preRead());
|
||||
}
|
||||
|
||||
~ReadOnlyValidator() {
|
||||
RBX_USE_CONCURRENCY_VALIDATOR(concurrencyValidator.postRead());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class WriteValidator
|
||||
{
|
||||
private:
|
||||
ConcurrencyValidator& concurrencyValidator;
|
||||
|
||||
public:
|
||||
WriteValidator(ConcurrencyValidator& c) : concurrencyValidator(c) {
|
||||
RBX_USE_CONCURRENCY_VALIDATOR(concurrencyValidator.preWrite());
|
||||
}
|
||||
|
||||
WriteValidator(ConcurrencyValidator& c, const std::string& writeWhere) : concurrencyValidator(c) {
|
||||
RBX_USE_CONCURRENCY_VALIDATOR(concurrencyValidator.preWrite(writeWhere));
|
||||
}
|
||||
|
||||
WriteValidator(ConcurrencyValidator& c, const char* writeWhere) : concurrencyValidator(c) {
|
||||
RBX_USE_CONCURRENCY_VALIDATOR(concurrencyValidator.preWrite(writeWhere));
|
||||
}
|
||||
|
||||
~WriteValidator() {
|
||||
RBX_USE_CONCURRENCY_VALIDATOR(concurrencyValidator.postWrite());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
#include "V8Tree/Instance.h"
|
||||
#include "V8Tree/Service.h"
|
||||
namespace RBX {
|
||||
|
||||
extern const char* const sContentFilter;
|
||||
class ContentFilter
|
||||
: public DescribedNonCreatable<ContentFilter, Instance, sContentFilter, Reflection::ClassDescriptor::RUNTIME_LOCAL>
|
||||
, public Service
|
||||
|
||||
{
|
||||
public:
|
||||
typedef enum { Waiting, Succeeded, Failed } FilterResult;
|
||||
static const unsigned MAX_CONTENT_FILTER_SIZE;
|
||||
private:
|
||||
struct ResultEntry
|
||||
{
|
||||
bool result;
|
||||
int usageCount;
|
||||
ResultEntry(bool result=false)
|
||||
:result(result),usageCount(0)
|
||||
{}
|
||||
};
|
||||
typedef std::map<std::string, ResultEntry> ResultsDictionary;
|
||||
typedef std::set<std::string> RequestSet;
|
||||
|
||||
ResultsDictionary resultsDictionary;
|
||||
RequestSet requestSet;
|
||||
|
||||
std::string url;
|
||||
unsigned maxOutstandingRequests;
|
||||
unsigned maxTableSize;
|
||||
|
||||
static void truncateString(std::string& text);
|
||||
|
||||
//Returns false if it doesn't know yet, may truncate the string
|
||||
bool isContentFilterReady(const std::string& value);
|
||||
bool isStringSafe(std::string& value);
|
||||
|
||||
void cleanTable();
|
||||
public:
|
||||
ContentFilter();
|
||||
~ContentFilter();
|
||||
|
||||
|
||||
FilterResult getStringState(std::string& value);
|
||||
|
||||
void setFilterUrl(std::string);
|
||||
void setFilterLimits(int,int);
|
||||
|
||||
void doFilterRequest(std::string value);
|
||||
void saveFilterResult(std::string value, bool result);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -195,7 +195,7 @@ namespace RBX
|
||||
std::string host = parsed.host();
|
||||
std::string path = parsed.path();
|
||||
|
||||
static const std::string testsite_domain = "pizzaboxer.fun";
|
||||
static const std::string testsite_domain = "robloxlabs.com";
|
||||
|
||||
const RBX::Url baseUrlParsed = RBX::Url::fromString(baseUrl);
|
||||
|
||||
@@ -278,7 +278,7 @@ namespace RBX
|
||||
|
||||
if (boost::istarts_with(path, paths[i]) && (path.size() == pathLength || path[pathLength] == '?'))
|
||||
{
|
||||
static const char* domain = ".pizzaboxer.fun";
|
||||
static const char* domain = ".robloxlabs.com";
|
||||
|
||||
if (DFFlag::UrlReconstructToAssetGame)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#ifndef _4B0F5828DADB441bA2D2FDCBCB5538A6
|
||||
#define _4B0F5828DADB441bA2D2FDCBCB5538A6
|
||||
|
||||
#include "stdio.h"
|
||||
#include "util/name.h"
|
||||
#include <string>
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "rbx/boost.hpp"
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
using boost::shared_ptr;
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class ContentId
|
||||
{
|
||||
public:
|
||||
static ContentId fromUrl(const std::string& url);
|
||||
static ContentId fromAssets(const char* filePath); // filePath is a relative pathname within the "Content" directory
|
||||
static ContentId fromGameAssetName(const std::string& gameAssetName);
|
||||
|
||||
// Constructors are explicit to encourage you to use static constructors above if the string isn't a fully qualified URL
|
||||
explicit ContentId(const char* id)
|
||||
:id(id) { CorrectBackslash(this->id); }
|
||||
explicit ContentId(const std::string& id)
|
||||
:id(id) { CorrectBackslash(this->id); }
|
||||
ContentId() {}
|
||||
|
||||
void clear()
|
||||
{
|
||||
id.clear();
|
||||
}
|
||||
|
||||
const char* c_str() const {
|
||||
return id.c_str();
|
||||
}
|
||||
const std::string& toString() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
void convertToLegacyContent(const std::string& baseUrl);
|
||||
void convertAssetId(const std::string& baseUrl, int universeId);
|
||||
bool reconstructUrl(const std::string& baseUrl, const char* const paths[], const int pathCount);
|
||||
bool reconstructAssetUrl(const std::string& baseUrl);
|
||||
|
||||
std::string getAssetId() const;
|
||||
std::string getAssetName() const;
|
||||
std::string getUnConvertedAssetName() const;
|
||||
|
||||
bool isNull() const { return id.size()==0; }
|
||||
bool isAsset() const { return id.compare(0, 11, "rbxasset://") == 0; }
|
||||
bool isAssetId() const { return id.compare(0, 13, "rbxassetid://") == 0; }
|
||||
bool isHttp() const { return id.compare(0, 4, "http") == 0; }
|
||||
bool isFile() const { return id.compare(0, 7, "file://") == 0; }
|
||||
bool isRbxHttp() const { return id.compare(0, 10, "rbxhttp://") == 0; }
|
||||
bool isAppContent() const { return id.compare(0, 9, "rbxapp://") == 0; }
|
||||
bool isNamedAsset() const;
|
||||
bool isConvertedNamedAsset() const;
|
||||
|
||||
friend bool operator<(const ContentId& a, const ContentId& b);
|
||||
friend bool operator==(const ContentId& a, const ContentId& b);
|
||||
friend bool operator!=(const ContentId& a, const ContentId& b);
|
||||
|
||||
private:
|
||||
static void CorrectBackslash(std::string& id);
|
||||
|
||||
std::string id;
|
||||
};
|
||||
|
||||
std::size_t hash_value(const ContentId& id);
|
||||
|
||||
}// namespace
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/AsyncHttpQueue.h"
|
||||
#include "v8datamodel/DataModelJob.h"
|
||||
#include "rbx/threadsafe.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class DataModel;
|
||||
|
||||
class ContentProviderJob : public DataModelJob
|
||||
{
|
||||
public:
|
||||
enum ExecutionMode
|
||||
{
|
||||
JobMode,
|
||||
ImmediateMode
|
||||
};
|
||||
|
||||
private:
|
||||
boost::function<TaskScheduler::StepResult(std::string,shared_ptr<const std::string>)> processFunc;
|
||||
boost::function<void(std::string)> errorFunc;
|
||||
|
||||
struct ContentProviderTask
|
||||
{
|
||||
std::string id;
|
||||
shared_ptr<const std::string> data;
|
||||
};
|
||||
bool aborted;
|
||||
rbx::safe_queue<ContentProviderTask> tasks;
|
||||
ExecutionMode execMode;
|
||||
|
||||
TaskScheduler::StepResult processTask(const ContentProviderTask& task);
|
||||
public:
|
||||
|
||||
ContentProviderJob(shared_ptr<DataModel> dataModel, const char* name,
|
||||
boost::function<TaskScheduler::StepResult(std::string,shared_ptr<const std::string>)> processFunc,
|
||||
boost::function<void(std::string)> errorFunc);
|
||||
|
||||
/*override*/ Time::Interval sleepTime(const Stats& stats);
|
||||
/*override*/ Job::Error error(const Stats& stats);
|
||||
/*override*/ TaskScheduler::StepResult stepDataModelJob(const Stats& stats);
|
||||
|
||||
|
||||
void abort();
|
||||
void addTask(const std::string& id, AsyncHttpQueue::RequestResult result, std::istream* filestream, shared_ptr<const std::string> data);
|
||||
void setExecutionMode(ExecutionMode execMode);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/LRUCache.h"
|
||||
namespace RBX
|
||||
{
|
||||
enum CacheSizeEnforceMethod { CACHE_ENFORCE_MEMORY_SIZE, CACHE_ENFORCE_OBJECT_COUNT };
|
||||
|
||||
template<class Key,class Data>
|
||||
class ControlledLRUCache
|
||||
{
|
||||
private:
|
||||
unsigned long maxSize;
|
||||
CacheSizeEnforceMethod enforceMethod;
|
||||
boost::scoped_ptr< LRUCache<Key,Data> > evictableCache; // items that are processed and ok to delete from cache
|
||||
boost::scoped_ptr< LRUCache<Key,Data> > pinnedCache; // items that are pending processing/use
|
||||
public:
|
||||
public:
|
||||
ControlledLRUCache( const unsigned long maxSize, CacheSizeEnforceMethod method = CACHE_ENFORCE_OBJECT_COUNT) : maxSize(maxSize), enforceMethod(method)
|
||||
{
|
||||
if (method == CACHE_ENFORCE_OBJECT_COUNT)
|
||||
evictableCache.reset(new SizeEnforcedLRUCache<Key, Data>(maxSize));
|
||||
else if (method == CACHE_ENFORCE_MEMORY_SIZE)
|
||||
evictableCache.reset(new MemEnforcedLRUCache<Key, Data>(maxSize));
|
||||
else
|
||||
RBXASSERT(false);
|
||||
|
||||
pinnedCache.reset(new LRUCache<Key, Data>());
|
||||
}
|
||||
|
||||
~ControlledLRUCache()
|
||||
{}
|
||||
|
||||
inline const unsigned long size()
|
||||
{
|
||||
return evictableCache->size() + pinnedCache->size();
|
||||
}
|
||||
|
||||
inline const unsigned long memSize()
|
||||
{
|
||||
return evictableCache->memSize() + pinnedCache->memSize();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
evictableCache.clear();
|
||||
pinnedCache.clear();
|
||||
}
|
||||
|
||||
inline bool exists( const Key &key ) const
|
||||
{
|
||||
return (evictableCache->exists(key) || pinnedCache->exists(key));
|
||||
}
|
||||
inline bool remove( const Key &key )
|
||||
{
|
||||
bool result = false;
|
||||
result = evictableCache->remove(key) || result;
|
||||
result = pinnedCache->remove(key) || result;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void markEvictable(const Key& key)
|
||||
{
|
||||
Data data;
|
||||
unsigned long size;
|
||||
if(pinnedCache->fetch(key, &data, &size)){
|
||||
internalMakeEvictable(key, data, size);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool fetch( const Key &key, Data* result, bool makeEvictable)
|
||||
{
|
||||
if(evictableCache->fetch(key, result))
|
||||
return true;
|
||||
|
||||
unsigned long size;
|
||||
|
||||
if(pinnedCache->fetch(key, result, &size)){
|
||||
if(!makeEvictable)
|
||||
return true;
|
||||
|
||||
//Make it evictable by moving it into the evictableCache
|
||||
internalMakeEvictable(key, *result, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
//Didn't find it, return false
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void resize( unsigned long newSize)
|
||||
{
|
||||
maxSize = newSize;
|
||||
evictableCache->resize(newSize);
|
||||
pinnedCache->resize(newSize);
|
||||
|
||||
unsigned long curSize = (enforceMethod == CACHE_ENFORCE_MEMORY_SIZE) ? memSize() : size();
|
||||
while((curSize > newSize) && (evictableCache->size() > 0))
|
||||
{
|
||||
evictableCache->removeLeastRecentlyUsed();
|
||||
curSize = (enforceMethod == CACHE_ENFORCE_MEMORY_SIZE) ? memSize() : size();
|
||||
}
|
||||
|
||||
RBXASSERT((enforceMethod == CACHE_ENFORCE_MEMORY_SIZE ? memSize() : size()) <= newSize);
|
||||
}
|
||||
|
||||
inline void insert( const Key &key, const Data &data, unsigned long dataSize = 0 )
|
||||
{
|
||||
//First remove it from evictableCache, since it will go into pinnedCache now
|
||||
evictableCache->remove(key);
|
||||
pinnedCache->remove(key);
|
||||
|
||||
unsigned int new_size = (enforceMethod == CACHE_ENFORCE_MEMORY_SIZE) ? (this->memSize() + dataSize) : (this->size() + 1);
|
||||
if(new_size > maxSize) {
|
||||
//We are full, see if we have evictable space
|
||||
if(evictableCache->size() > 0){
|
||||
//Something is evictable, kick it out
|
||||
evictableCache->removeLeastRecentlyUsed();
|
||||
}
|
||||
}
|
||||
|
||||
pinnedCache->insert(key, data, dataSize);
|
||||
}
|
||||
inline bool isFull()
|
||||
{
|
||||
return pinnedCache->size() >= maxSize;
|
||||
}
|
||||
|
||||
|
||||
inline bool evictAll()
|
||||
{
|
||||
if(!pinnedCache->empty()){
|
||||
evictableCache->insert(pinnedCache->begin(), pinnedCache->end());
|
||||
pinnedCache->clear();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
void internalMakeEvictable(const Key& key, const Data& data, unsigned long dataSize)
|
||||
{
|
||||
evictableCache->insert(key,data, dataSize);
|
||||
pinnedCache->remove(key);
|
||||
|
||||
RBXASSERT(size() <= maxSize);
|
||||
}
|
||||
};
|
||||
|
||||
template<class Key,class Data>
|
||||
class ConcurrentControlledLRUCache
|
||||
{
|
||||
private:
|
||||
RBX::ControlledLRUCache<Key, Data> cache;
|
||||
boost::mutex mutex;
|
||||
|
||||
unsigned long resetCounter;
|
||||
unsigned long heartbeatCounter;
|
||||
public:
|
||||
ConcurrentControlledLRUCache(unsigned long size, unsigned long resetCounter, CacheSizeEnforceMethod enforceMethod = CACHE_ENFORCE_OBJECT_COUNT)
|
||||
:cache(size, enforceMethod)
|
||||
,resetCounter(resetCounter)
|
||||
,heartbeatCounter(0)
|
||||
{}
|
||||
|
||||
inline bool fetch( const Key &key, Data* result, bool makeEvictable)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
return cache.fetch(key, result, makeEvictable);
|
||||
}
|
||||
|
||||
inline void resize( unsigned long newSize)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
cache.resize(newSize);
|
||||
}
|
||||
|
||||
inline void insert( const Key &key, const Data &data, unsigned long dataSize = 0)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
return cache.insert(key, data, dataSize);
|
||||
}
|
||||
|
||||
inline bool remove( const Key &key )
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
return cache.remove(key);
|
||||
}
|
||||
|
||||
inline void markEvictable(const Key& key)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
cache.markEvictable(key);
|
||||
}
|
||||
|
||||
inline bool isFull()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
return cache.isFull();
|
||||
}
|
||||
|
||||
inline bool evictAll()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
return cache.evictAll();
|
||||
}
|
||||
|
||||
inline void onHeartbeat()
|
||||
{
|
||||
if(++heartbeatCounter >= resetCounter){
|
||||
heartbeatCounter = 0;
|
||||
evictAll();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
|
||||
@@ -303,7 +303,7 @@ static NSString* kHttpRunLoopMode = @"RobloxHttpController";
|
||||
if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber10_8)
|
||||
{
|
||||
if ([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
|
||||
return [protectionSpace.host rangeOfString:@".pizzaboxer.fun"].location != NSNotFound;
|
||||
return [protectionSpace.host rangeOfString:@".robloxlabs.com"].location != NSNotFound;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
@@ -313,7 +313,7 @@ static NSString* kHttpRunLoopMode = @"RobloxHttpController";
|
||||
if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber10_8)
|
||||
{
|
||||
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust] &&
|
||||
([challenge.protectionSpace.host rangeOfString:@".pizzaboxer.fun"].location != NSNotFound))
|
||||
([challenge.protectionSpace.host rangeOfString:@".robloxlabs.com"].location != NSNotFound))
|
||||
{
|
||||
// trust the credentials...
|
||||
[challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
|
||||
@@ -353,7 +353,7 @@ int rbx_isRobloxSite(const char* url)
|
||||
|
||||
if (!isRobloxUrl)
|
||||
{
|
||||
textRange =[host rangeOfString:@".pizzaboxer.fun"];
|
||||
textRange =[host rangeOfString:@".robloxlabs.com"];
|
||||
isRobloxUrl = textRange.location != NSNotFound;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
#include "rbx/Debug.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
/**
|
||||
* Wrapper around std::vector that allows for quick insert and pop from both
|
||||
* front and back. This container never attempts to reduce the amount of
|
||||
* memory it uses, so it may not be suitable for queues that do not have a
|
||||
* reasonable upper bound in size.
|
||||
*/
|
||||
template<class T>
|
||||
struct DoubleEndedVector {
|
||||
private:
|
||||
size_t head;
|
||||
size_t internalSize;
|
||||
std::vector<T> data;
|
||||
size_t dataSizeMask;
|
||||
|
||||
void grow() {
|
||||
if (internalSize == data.size()) {
|
||||
std::vector<T> replacement(std::max((size_t)32, internalSize * 2));
|
||||
|
||||
if (data.size() > 0) {
|
||||
size_t firstSegment = data.size() - head;
|
||||
size_t secondSegment = internalSize - firstSegment;
|
||||
|
||||
RBXASSERT(firstSegment + secondSegment == data.size());
|
||||
std::copy(&data[head], &data[head] + firstSegment, &replacement[0]);
|
||||
std::copy(&data[0], &data[0] + secondSegment, &replacement[firstSegment]);
|
||||
}
|
||||
|
||||
head = 0;
|
||||
data.swap(replacement);
|
||||
RBXASSERT((data.size() & (data.size() - 1)) == 0);
|
||||
dataSizeMask = data.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DoubleEndedVector() : head(0), internalSize(0), data(), dataSizeMask(0) {}
|
||||
|
||||
size_t size() const {
|
||||
return internalSize;
|
||||
}
|
||||
|
||||
bool push_back(const T& inputData) {
|
||||
grow();
|
||||
data[(head + internalSize) & dataSizeMask] = inputData;
|
||||
internalSize++;
|
||||
return true;
|
||||
}
|
||||
bool push_front(const T& inputData) {
|
||||
grow();
|
||||
|
||||
size_t newHead = (head - 1) & dataSizeMask;
|
||||
|
||||
data[newHead] = inputData;
|
||||
head = newHead;
|
||||
internalSize++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void pop_front(T* out) {
|
||||
RBXASSERT(internalSize > 0);
|
||||
(*out) = data[head];
|
||||
head = (head + 1) & dataSizeMask;
|
||||
internalSize--;
|
||||
}
|
||||
|
||||
inline T& operator[](const unsigned int& idx) {
|
||||
return data[(head + idx) & dataSizeMask];
|
||||
}
|
||||
inline const T& operator[](const unsigned int& idx) const {
|
||||
return data[(head + idx) & dataSizeMask];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
// ToDo - templatize this
|
||||
class floatERA {
|
||||
private:
|
||||
float weight;
|
||||
float avg;
|
||||
public:
|
||||
floatERA()
|
||||
: weight(.5f)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
floatERA(float weight)
|
||||
: weight(weight)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
avg = 0.0f;
|
||||
}
|
||||
|
||||
float pushAndGetAverage(float value) {
|
||||
avg = (weight * (value - avg)) + avg;
|
||||
return avg;
|
||||
}
|
||||
|
||||
float getAverage() {return avg;}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class Vector3ERA {
|
||||
private:
|
||||
float weight;
|
||||
Vector3 avg;
|
||||
public:
|
||||
Vector3ERA()
|
||||
:weight(.5f)
|
||||
{} // Vector inits to zeros
|
||||
|
||||
Vector3ERA(float weight)
|
||||
: weight(weight)
|
||||
{} // Vector3 inits to zeros;
|
||||
|
||||
void reset(const Vector3& value) {
|
||||
avg = value;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
reset(Vector3::zero());
|
||||
}
|
||||
|
||||
void push(const Vector3& value) {
|
||||
avg += weight * (value - avg);
|
||||
}
|
||||
|
||||
const Vector3& getAverage() {return avg;}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/NormalId.h"
|
||||
#include "Util/G3DCore.h"
|
||||
#include "rbx/Debug.h"
|
||||
#include "Util/Math.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Extents {
|
||||
private:
|
||||
Vector3 low;
|
||||
Vector3 high;
|
||||
|
||||
public:
|
||||
Extents() // initialize to negativeInfiniteExtents;
|
||||
: low(Vector3::maxFinite())
|
||||
, high(-Vector3::maxFinite())
|
||||
{}
|
||||
|
||||
Extents(const Vector3& _min, const Vector3& _max)
|
||||
: low(_min)
|
||||
, high(_max)
|
||||
{
|
||||
RBXASSERT_SLOW(low == low.min(high));
|
||||
RBXASSERT_SLOW(high == high.max(low));
|
||||
}
|
||||
|
||||
bool isNanInf() const
|
||||
{
|
||||
return (Math::isNanInfVector3(low) || Math::isNanInfVector3(high));
|
||||
}
|
||||
|
||||
static Extents fromCenterCorner(const Vector3& center, const Vector3& corner) {
|
||||
return Extents(center-corner, center+corner);
|
||||
}
|
||||
|
||||
static Extents fromCenterRadius(const Vector3& center, float radius) {
|
||||
return fromCenterCorner(center, Vector3(radius, radius, radius));
|
||||
}
|
||||
|
||||
bool operator==(const Extents& other) const {
|
||||
return ((low == other.low) && (high == other.high));
|
||||
}
|
||||
|
||||
bool operator!=(const Extents& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
static Extents vv(const Vector3& v0, const Vector3& v1) {
|
||||
Extents e;
|
||||
e.low = v0.min(v1);
|
||||
e.high = v0.max(v1);
|
||||
return e;
|
||||
}
|
||||
|
||||
const Vector3& min() const {return low;}
|
||||
const Vector3& max() const {return high;}
|
||||
|
||||
Vector3int16 getCornerIndex(int i) const;
|
||||
Vector3 getCorner(int i) const;
|
||||
|
||||
Vector3 size() const {
|
||||
return high - low;
|
||||
}
|
||||
|
||||
Vector3 center() const {
|
||||
return 0.5 * (low + high);
|
||||
}
|
||||
|
||||
Vector3 bottomCenter() const {
|
||||
Vector3 answer = center();
|
||||
answer.y = low.y;
|
||||
return answer;
|
||||
}
|
||||
|
||||
Vector3 topCenter() const {
|
||||
Vector3 answer = center();
|
||||
answer.y = high.y;
|
||||
return answer;
|
||||
}
|
||||
|
||||
float longestSide() const {
|
||||
Vector3 s = size();
|
||||
return G3D::max(G3D::max(s.x, s.y), s.z);
|
||||
}
|
||||
|
||||
float volume() const {
|
||||
Vector3 s = size();
|
||||
return s.x * s.y * s.z;
|
||||
}
|
||||
|
||||
float areaXZ() const {
|
||||
Vector3 s = size();
|
||||
return s.x * s.z;
|
||||
}
|
||||
|
||||
bool isNull() const {
|
||||
return low.x > high.x || low.y > high.y || low.z > high.z;
|
||||
}
|
||||
|
||||
Extents toWorldSpace(const CoordinateFrame& offset) const;
|
||||
|
||||
Extents express(const CoordinateFrame& myFrame, const CoordinateFrame& expressInFrame) const;
|
||||
|
||||
// faceId's are in order of x, y, z, -x, -y, -z
|
||||
Vector3 faceCenter(NormalId faceId) const;
|
||||
|
||||
/**
|
||||
Returns the four corners of a face (0 <= f < 6).
|
||||
The corners are returned to form a counter clockwise quad facing outwards.
|
||||
*/
|
||||
void getFaceCorners(
|
||||
NormalId faceId,
|
||||
Vector3& v0,
|
||||
Vector3& v1,
|
||||
Vector3& v2,
|
||||
Vector3& v3) const;
|
||||
|
||||
Plane getPlane(NormalId normalId) const;
|
||||
|
||||
// clip the vector to be inside the Extents
|
||||
Vector3 clip(const Vector3& clipVector) const {
|
||||
return clipVector.clamp(low, high);
|
||||
}
|
||||
|
||||
|
||||
float computeClosestSqDistanceToPoint(const Vector3& point) const;
|
||||
|
||||
// minimum amount to move innerExtents and keep them within Extents
|
||||
Vector3 clamp(const Extents& innerExtents) const;
|
||||
|
||||
NormalId closestFace(const Vector3& point);
|
||||
|
||||
void unionWith(const Extents& other) { // Extents& operator&= (const Extents& other) {
|
||||
low = low.min(other.low);
|
||||
high = high.max(other.high);
|
||||
}
|
||||
|
||||
Extents clampInsideOf(const Extents& other) const; // Extents& operator&= (const Extents& other) {
|
||||
|
||||
void shift(const Vector3& shiftVector) {// Extents& operator+= (const Vector3& shiftVector) {
|
||||
low += shiftVector;
|
||||
high += shiftVector;
|
||||
}
|
||||
|
||||
void scale(float x) { // Extents& operator*= (float x) {
|
||||
low *= x;
|
||||
high *= x;
|
||||
}
|
||||
|
||||
void expand(float x) {
|
||||
low -= Vector3(x,x,x);
|
||||
high += Vector3(x,x,x);
|
||||
}
|
||||
|
||||
void expand(const Vector3& p) {
|
||||
low -= p;
|
||||
high += p;
|
||||
}
|
||||
|
||||
void expandToContain(const Vector3& p) {
|
||||
low = low.min(p);
|
||||
high = high.max(p);
|
||||
}
|
||||
|
||||
void expandToContain(const Extents& e) {
|
||||
low = low.min(e.low);
|
||||
high = high.max(e.high);
|
||||
}
|
||||
|
||||
bool contains(const Vector3& point) const {
|
||||
return ( (point.x >= low.x)
|
||||
&& (point.y >= low.y)
|
||||
&& (point.z >= low.z)
|
||||
&& (point.x <= high.x)
|
||||
&& (point.y <= high.y)
|
||||
&& (point.z <= high.z) );
|
||||
}
|
||||
|
||||
bool fuzzyContains(const Vector3& point, float slop) const {
|
||||
return ( (point.x >= (low.x - slop))
|
||||
&& (point.y >= (low.y - slop))
|
||||
&& (point.z >= (low.z - slop))
|
||||
&& (point.x <= (high.x + slop))
|
||||
&& (point.y <= (high.y + slop))
|
||||
&& (point.z <= (high.z + slop)) );
|
||||
}
|
||||
|
||||
|
||||
bool overlapsOrTouches(const Extents& other) const { // true if sides are exactly equal (touching)
|
||||
return ( (this->low.x > other.high.x)
|
||||
|| (this->low.y > other.high.y)
|
||||
|| (this->low.z > other.high.z)
|
||||
|| (this->high.y < other.low.y)
|
||||
|| (this->high.x < other.low.x)
|
||||
|| (this->high.z < other.low.z)) ? false : true;
|
||||
}
|
||||
|
||||
static bool overlapsOrTouches(const Extents& e0, const Extents& e1) {return e0.overlapsOrTouches(e1);}
|
||||
|
||||
bool clampToOverlap(const Extents& other) {
|
||||
if ( (this->low.x >= other.high.x)
|
||||
|| (this->low.y >= other.high.y)
|
||||
|| (this->low.z >= other.high.z)
|
||||
|| (this->high.y <= other.low.y)
|
||||
|| (this->high.x <= other.low.x)
|
||||
|| (this->high.z <= other.low.z))
|
||||
return false; // not overlap
|
||||
low = low.clamp(other.low, other.high);
|
||||
high = high.clamp(other.low, other.high);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool separatedByMoreThan(const Extents& other, float distance) const;
|
||||
|
||||
|
||||
static const Extents& zero() {
|
||||
static Extents e(Vector3::zero(), Vector3::zero());
|
||||
return e;
|
||||
}
|
||||
|
||||
static const Extents& unit() {
|
||||
static Extents e(Vector3(-1,-1,-1), Vector3(1,1,1));
|
||||
return e;
|
||||
}
|
||||
|
||||
static const Extents& negativeMaxExtents() {
|
||||
static Extents e; // default constructor builds this;
|
||||
return e;
|
||||
}
|
||||
|
||||
static const Extents& maxExtents() {
|
||||
static Extents e(-Vector3::maxFinite(), Vector3::maxFinite());
|
||||
return e;
|
||||
}
|
||||
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,173 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/Vector3int32.h"
|
||||
#include "Util/Extents.h"
|
||||
#include "rbx/Debug.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class ExtentsInt32 {
|
||||
public:
|
||||
Vector3int32 low;
|
||||
Vector3int32 high;
|
||||
|
||||
ExtentsInt32()
|
||||
: low(Vector3int32::maxInt())
|
||||
, high(Vector3int32::minInt())
|
||||
{}
|
||||
|
||||
ExtentsInt32(const Vector3int32& _min, const Vector3int32& _max)
|
||||
: low(_min)
|
||||
, high(_max)
|
||||
{
|
||||
RBXASSERT_SLOW(low == low.min(high));
|
||||
RBXASSERT_SLOW(high == high.max(low));
|
||||
}
|
||||
|
||||
bool operator==(const ExtentsInt32& other) const {
|
||||
return ((low == other.low) && (high == other.high));
|
||||
}
|
||||
|
||||
bool operator!=(const ExtentsInt32& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
ExtentsInt32& operator= (const ExtentsInt32& other) {
|
||||
low = other.low;
|
||||
high = other.high;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ExtentsInt32 shiftRight(int shift) const {
|
||||
RBXASSERT_SLOW(shift >= 0);
|
||||
RBXASSERT_SLOW(shift <= 32);
|
||||
return ExtentsInt32(low >> shift, high >> shift);
|
||||
}
|
||||
|
||||
ExtentsInt32 shiftRight(const Vector3int32& shift) const {
|
||||
return ExtentsInt32(low >> shift, high >> shift);
|
||||
}
|
||||
|
||||
ExtentsInt32 shiftLeft(int shift) const {
|
||||
RBXASSERT_SLOW(shift >= 0);
|
||||
RBXASSERT_SLOW(shift <= 32);
|
||||
return ExtentsInt32(low << shift, high << shift);
|
||||
}
|
||||
|
||||
ExtentsInt32 shiftLeft(const Vector3int32& shift) const {
|
||||
return ExtentsInt32(low << shift, high << shift);
|
||||
}
|
||||
|
||||
static ExtentsInt32 vv(const Vector3int32& v0, const Vector3int32& v1) {
|
||||
ExtentsInt32 e;
|
||||
e.low = v0.min(v1);
|
||||
e.high = v0.max(v1);
|
||||
return e;
|
||||
}
|
||||
|
||||
const Vector3int32& min() const {return low;}
|
||||
const Vector3int32& max() const {return high;}
|
||||
|
||||
Vector3int32 getCorner(int i) const;
|
||||
|
||||
Vector3int32 size() const {
|
||||
return high - low;
|
||||
}
|
||||
|
||||
Vector3int32 center() const {
|
||||
return ((low + high) >> 1);
|
||||
}
|
||||
|
||||
Vector3int32 bottomCenter() const {
|
||||
Vector3int32 answer = center();
|
||||
answer.y = low.y;
|
||||
return answer;
|
||||
}
|
||||
|
||||
Vector3int32 topCenter() const {
|
||||
Vector3int32 answer = center();
|
||||
answer.y = high.y;
|
||||
return answer;
|
||||
}
|
||||
|
||||
int longestSide() const {
|
||||
Vector3int32 s = size();
|
||||
return std::max(std::max(s.x, s.y), s.z);
|
||||
}
|
||||
|
||||
int volume() const {
|
||||
Vector3int32 s = size();
|
||||
long long int answer = s.x * s.y * s.z;
|
||||
RBXASSERT(answer < INT_MAX);
|
||||
return static_cast<int>(answer);
|
||||
}
|
||||
|
||||
static ExtentsInt32 unionExtents(const ExtentsInt32& a, const ExtentsInt32& b) {
|
||||
return ExtentsInt32(a.low.min(b.low), a.high.max(b.high));
|
||||
}
|
||||
|
||||
void shift(const Vector3int32& shiftVector) {
|
||||
low = low + shiftVector;
|
||||
high = high + shiftVector;
|
||||
}
|
||||
|
||||
void expand(int x) {
|
||||
low = low - Vector3int32(x,x,x);
|
||||
high = high + Vector3int32(x,x,x);
|
||||
}
|
||||
|
||||
const Vector3int32& operator[] (int i) const {
|
||||
return ((Vector3int32*)this)[i];
|
||||
}
|
||||
|
||||
Vector3int32& operator[] (int i) {
|
||||
return ((Vector3int32*)this)[i];
|
||||
}
|
||||
|
||||
operator Vector3int32* () {
|
||||
return (Vector3int32*)this;
|
||||
}
|
||||
operator const Vector3int32* () const {
|
||||
return (Vector3int32*)this;
|
||||
}
|
||||
|
||||
bool contains(int x, int y, int z) const {
|
||||
return ( (x >= low.x)
|
||||
&& (y >= low.y)
|
||||
&& (z >= low.z)
|
||||
&& (x <= high.x)
|
||||
&& (y <= high.y)
|
||||
&& (z <= high.z) );
|
||||
}
|
||||
|
||||
bool contains(const Vector3int32& point) const {
|
||||
return contains(point.x, point.y, point.z);
|
||||
}
|
||||
|
||||
bool overlapsOrTouches(const ExtentsInt32& other) const { // true if sides are exactly equal (touching)
|
||||
return ( (this->low.x > other.high.x)
|
||||
|| (this->low.y > other.high.y)
|
||||
|| (this->low.z > other.high.z)
|
||||
|| (this->high.y < other.low.y)
|
||||
|| (this->high.x < other.low.x)
|
||||
|| (this->high.z < other.low.z)) ? false : true;
|
||||
}
|
||||
|
||||
static bool overlapsOrTouches(const ExtentsInt32& e0, const ExtentsInt32& e1) {return e0.overlapsOrTouches(e1);}
|
||||
|
||||
Extents toExtents() const {
|
||||
return Extents(low.toVector3(), high.toVector3());
|
||||
}
|
||||
|
||||
static const ExtentsInt32& zero() {
|
||||
static ExtentsInt32 e(Vector3int32::zero(), Vector3int32::zero());
|
||||
return e;
|
||||
}
|
||||
|
||||
static const ExtentsInt32& empty() {
|
||||
static ExtentsInt32 e; // constructor sets negatives
|
||||
return e;
|
||||
}
|
||||
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
#include "Util/NormalId.h"
|
||||
#include "rbx/Debug.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Extents;
|
||||
|
||||
class Face
|
||||
{
|
||||
private:
|
||||
Vector3 c0, c1, c2, c3;
|
||||
|
||||
Face(const Vector3& c0, const Vector3& c1, const Vector3& c2, const Vector3& c3)
|
||||
: c0(c0), c1(c1), c2(c2), c3(c3)
|
||||
{}
|
||||
|
||||
Vector3 getAxis(int i) const {
|
||||
RBXASSERT((i == 0) || (i==1));
|
||||
return i == 0 ? getU() : getV();
|
||||
}
|
||||
|
||||
void minMax(const Vector3& point, const Vector3& normal, float& min, float& max) const;
|
||||
|
||||
Face operator* (float fScalar) const {
|
||||
return Face(fScalar*c0, fScalar*c1, fScalar*c2, fScalar*c3);
|
||||
}
|
||||
|
||||
Face operator* (const Vector3& vector3) const {
|
||||
return Face(vector3*c0, vector3*c1, vector3*c2, vector3*c3);
|
||||
}
|
||||
|
||||
public:
|
||||
Face() {}
|
||||
|
||||
Face(const Face& other)
|
||||
: c0(other.c0), c1(other.c1), c2(other.c2), c3(other.c3)
|
||||
{}
|
||||
|
||||
static Face fromExtentsSide(const Extents& e, NormalId faceId);
|
||||
|
||||
void snapToGrid(float grid);
|
||||
|
||||
Vector3& operator[] (int i);
|
||||
|
||||
const Vector3& operator[] (int i) const;
|
||||
|
||||
Vector3 getU() const {return (c1 - c0).direction();}
|
||||
|
||||
Vector3 getV() const {return (c3 - c0).direction();}
|
||||
|
||||
Vector3 getNormal() const {return getU().cross(getV()).direction();}
|
||||
|
||||
Vector2 size() const {return Vector2((c1-c0).magnitude(), (c3-c0).magnitude());}
|
||||
|
||||
Vector3 center() const {return 0.5 * (c0 + c2);}
|
||||
|
||||
// Create new faces
|
||||
Face toWorldSpace(const CoordinateFrame& objectCoord) const;
|
||||
|
||||
Face toObjectSpace(const CoordinateFrame& objectCoord) const;
|
||||
|
||||
Face projectOverlapOnMe(const Face& other) const;
|
||||
|
||||
// Tests
|
||||
bool fuzzyContainsInExtrusion(const Vector3& point, float tolerance) const;
|
||||
|
||||
static bool cornersAligned(const Face& f0, const Face& f1, float tolerance);
|
||||
|
||||
static bool hasOverlap(const Face& f0, const Face& f1, float byAtLeast);
|
||||
|
||||
static bool overlapWithinPlanes(const Face& f0, const Face& f1, float tolerance);
|
||||
};
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,29 @@
|
||||
/* Copyright 2003-2009 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Util/NormalId.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
//A utility class for holding a set of "Faces" associated with an object (top, bottom, left, right, front, back)
|
||||
class Faces
|
||||
{
|
||||
public:
|
||||
Faces(int normalIdMask = 0);
|
||||
void clear() { normalIdMask = NORM_NONE_MASK; }
|
||||
void setNormalId(NormalId normalId, bool value);
|
||||
bool getNormalId(NormalId normalId) const;
|
||||
|
||||
|
||||
bool operator==(const Faces& other) const {
|
||||
return normalIdMask == other.normalIdMask;
|
||||
}
|
||||
bool operator!=(const Faces& other) const {
|
||||
return normalIdMask != other.normalIdMask;
|
||||
}
|
||||
|
||||
|
||||
int normalIdMask;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "FastLog.h"
|
||||
|
||||
#include <string>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
DYNAMIC_LOGGROUP(FileSystem)
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
|
||||
enum FileSystemDir
|
||||
{
|
||||
DirAppData = 0,
|
||||
DirPicture,
|
||||
DirVideo,
|
||||
DirExe
|
||||
};
|
||||
|
||||
namespace FileSystem
|
||||
{
|
||||
boost::filesystem::path getUserDirectory(bool create, FileSystemDir dir, const char *subDirectory = 0);
|
||||
boost::filesystem::path getCacheDirectory(bool create, const char* subDirectory);
|
||||
boost::filesystem::path getTempFilePath();
|
||||
boost::filesystem::path getLogsDirectory();
|
||||
|
||||
void clearCacheDirectory(const char* subDirectory);
|
||||
};
|
||||
} // namespace RBX
|
||||
@@ -81,7 +81,7 @@ boost::filesystem::path getBaseCacheDirectory(bool create)
|
||||
boost::filesystem::path path = boost::filesystem::temp_directory_path();
|
||||
|
||||
#ifndef RBX_PLATFORM_IOS
|
||||
path /= "watrbx";
|
||||
path /= "Roblox";
|
||||
#endif
|
||||
|
||||
#if defined(_DEBUG) || defined(_NOOPT)
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "boost/array.hpp"
|
||||
#include "rbx/Debug.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
/* USAGE
|
||||
|
||||
*/
|
||||
template<class T, std::size_t N>
|
||||
class FixedArray
|
||||
{
|
||||
private:
|
||||
boost::array<T, N> data;
|
||||
size_t num;
|
||||
|
||||
public:
|
||||
FixedArray()
|
||||
: num(0)
|
||||
{}
|
||||
|
||||
void push_back(const T& x) {
|
||||
RBXASSERT_VERY_FAST(num < N);
|
||||
data[num] = x;
|
||||
++num;
|
||||
}
|
||||
|
||||
void fastRemove(size_t i) {
|
||||
RBXASSERT_VERY_FAST(i < num);
|
||||
RBXASSERT_VERY_FAST(num <= N);
|
||||
data[i] = data[num - 1];
|
||||
--num;
|
||||
}
|
||||
|
||||
void replace(size_t i, const T& x) {
|
||||
RBXASSERT_VERY_FAST(i < num);
|
||||
RBXASSERT_VERY_FAST(num <= N);
|
||||
data[i] = x;
|
||||
}
|
||||
|
||||
void fastClear() {
|
||||
num = 0;
|
||||
}
|
||||
|
||||
T operator[](size_t i) {
|
||||
RBXASSERT_VERY_FAST(i < num);
|
||||
return data[i];
|
||||
}
|
||||
|
||||
const T operator[](size_t i) const {
|
||||
RBXASSERT_VERY_FAST(i < num);
|
||||
return data[i];
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return num;
|
||||
}
|
||||
|
||||
size_t capacity() const
|
||||
{
|
||||
return N;
|
||||
}
|
||||
};
|
||||
|
||||
}// namespace
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
namespace RBX {
|
||||
|
||||
template<class ElementType, int size=8>
|
||||
struct FixedSizeCircularBuffer {
|
||||
private:
|
||||
ElementType data[size];
|
||||
unsigned int head;
|
||||
unsigned int pushed;
|
||||
public:
|
||||
|
||||
FixedSizeCircularBuffer() : head(0), pushed(0) {}
|
||||
|
||||
void push(const ElementType& newData) {
|
||||
head = (head + size - 1) % size;
|
||||
data[head] = newData;
|
||||
if (pushed < size) { pushed++; }
|
||||
}
|
||||
|
||||
bool find(const ElementType& key, unsigned int* outIndex) {
|
||||
for (unsigned int i = 0; i < pushed; ++i) {
|
||||
if (data[(head + i) % size] == key) {
|
||||
(*outIndex) = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const ElementType& operator[](const unsigned int& index) const {
|
||||
return data[(head + index) % size];
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#ifndef _70F7A2EE1B6E4dd0AF07E4BFA609A3D1
|
||||
#define _70F7A2EE1B6E4dd0AF07E4BFA609A3D1
|
||||
|
||||
#include "G3D/Vector2.h"
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/Vector4.h"
|
||||
#include "G3D/Matrix3.h"
|
||||
#include "G3D/Matrix4.h"
|
||||
#include "G3D/Vector3int16.h"
|
||||
#include "G3D/Vector2int16.h"
|
||||
#include "G3D/Color4uint8.h"
|
||||
#include "G3D/Color3uint8.h"
|
||||
#include "G3D/CoordinateFrame.h"
|
||||
#include "G3D/Plane.h"
|
||||
#include "G3D/Line.h"
|
||||
#include "G3D/LineSegment.h"
|
||||
|
||||
#include "G3D/AABox.h"
|
||||
#include "G3D/Box.h"
|
||||
#include "RbxG3D/RbxCamera.h"
|
||||
#include "G3D/Color3.h"
|
||||
#include "G3D/Color4.h"
|
||||
#include "G3D/g3dmath.h"
|
||||
#include "G3D/Rect2D.h"
|
||||
#include "G3D/Sphere.h"
|
||||
|
||||
#include "G3D/vectorMath.h"
|
||||
#include "G3D/Debug.h"
|
||||
|
||||
// TODO: this can cause namespace collisions:
|
||||
//using G3D::Array;
|
||||
|
||||
namespace RBX {
|
||||
typedef G3D::Vector2 Vector2;
|
||||
typedef G3D::Vector3 Vector3;
|
||||
typedef G3D::Vector4 Vector4;
|
||||
typedef G3D::Vector2int16 Vector2int16;
|
||||
typedef G3D::Vector3int16 Vector3int16;
|
||||
typedef G3D::Color4uint8 Color4uint8;
|
||||
typedef G3D::Color3uint8 Color3uint8;
|
||||
typedef G3D::Matrix3 Matrix3;
|
||||
typedef G3D::Matrix4 Matrix4;
|
||||
typedef G3D::CoordinateFrame CoordinateFrame;
|
||||
typedef RBX::RbxRay Ray;
|
||||
typedef G3D::Plane Plane;
|
||||
typedef G3D::Line Line;
|
||||
typedef G3D::LineSegment LineSegment;
|
||||
typedef G3D::Color3 Color3;
|
||||
typedef G3D::Color4 Color4;
|
||||
typedef G3D::Rect2D Rect2D;
|
||||
typedef G3D::Box Box;
|
||||
typedef G3D::AABox AABox;
|
||||
typedef G3D::Sphere Sphere;
|
||||
|
||||
enum IntersectResult
|
||||
{
|
||||
irNone = 0,
|
||||
irPartial =1,
|
||||
irFull = 2
|
||||
};
|
||||
}
|
||||
|
||||
namespace G3D
|
||||
{
|
||||
std::size_t hash_value(const G3D::Vector3& v);
|
||||
std::size_t hash_value(const G3D::Vector3int16& v);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,12 @@
|
||||
/* Copyright 2003-2007 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace Network {
|
||||
|
||||
typedef enum {GAME_SERVER, DPHYS_GAME_SERVER, CLIENT, DPHYS_CLIENT, WATCH_ONLINE, VISIT_SOLO, EDIT, LOCAL_PLAY} GameMode;
|
||||
|
||||
}
|
||||
}
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "util/name.h"
|
||||
#include "util/Object.h"
|
||||
|
||||
#include "rbx/intrusive_ptr_target.h"
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
// A simple class that is a globally unique identifier
|
||||
class Guid : boost::noncopyable
|
||||
{
|
||||
public:
|
||||
struct Scope
|
||||
{
|
||||
public:
|
||||
Scope() { setNull(); }
|
||||
|
||||
void setNull() { name = &RBX::Name::getNullName(); }
|
||||
bool isNull() const {
|
||||
return *name == RBX::Name::getNullName();
|
||||
}
|
||||
void set( const std::string& s )
|
||||
{
|
||||
name = &RBX::Name::declare(s.c_str());
|
||||
}
|
||||
void set( const char* s )
|
||||
{
|
||||
name = &RBX::Name::declare(s);
|
||||
}
|
||||
|
||||
const RBX::Name* getName() const {
|
||||
return name;
|
||||
}
|
||||
|
||||
int compare(const Scope& other) const
|
||||
{
|
||||
return name->compare(*other.name);
|
||||
}
|
||||
bool operator ==(const Scope& other) const {
|
||||
return name->compare(*other.name) == 0;
|
||||
}
|
||||
bool operator <(const Scope& other) const {
|
||||
return name->compare(*other.name) < 0;
|
||||
}
|
||||
|
||||
static const Scope& null();
|
||||
|
||||
private:
|
||||
static Scope nullScope;
|
||||
|
||||
const RBX::Name* name;
|
||||
};
|
||||
|
||||
struct Data
|
||||
{
|
||||
Scope scope;
|
||||
int index;
|
||||
bool operator ==(const Data& other) const;
|
||||
bool operator <(const Data& other) const;
|
||||
// For debugging only. A string that is not guaranteed to be unique
|
||||
std::string readableString(int scopeLength = 4) const;
|
||||
};
|
||||
private:
|
||||
Data data;
|
||||
public:
|
||||
Guid();
|
||||
bool operator ==(const Guid& other) const { return data == other.data; }
|
||||
bool operator <(const Guid& other) const { return data < other.data; }
|
||||
|
||||
// Compare 2 pairs of Guids. a0-a1 and b0-b1 are commutativity. Any item may be NULL
|
||||
static int compare(const Guid* a, const Guid* b);
|
||||
static int compare(const Guid* a0, const Guid* a1, const Guid* b0, const Guid* b1);
|
||||
|
||||
// Used for serialization:
|
||||
void assign(Data data);
|
||||
void extract(Data &data) const { data = this->data; }
|
||||
|
||||
void copyDataFrom(const Guid& other) {
|
||||
Data data;
|
||||
other.extract(data);
|
||||
this->assign(data);
|
||||
}
|
||||
|
||||
// For debugging only. A string that is not guaranteed to be unique
|
||||
std::string readableString(int scopeLength = 4) const { return data.readableString(scopeLength); }
|
||||
|
||||
static const RBX::Guid::Scope& getLocalScope();
|
||||
|
||||
static void generateRBXGUID(RBX::Guid::Scope& result);
|
||||
|
||||
// Creates a string like this: RBXc200e36038c511ceae6208002b2b79ef
|
||||
static void generateRBXGUID(std::string& result);
|
||||
|
||||
// Creates a string like this: {c200e360-38c5-11ce-ae62-08002b2b79ef}
|
||||
static void generateStandardGUID(std::string& result);
|
||||
};
|
||||
|
||||
inline size_t hash_value(const Guid::Data& data)
|
||||
{
|
||||
size_t result = 0;
|
||||
boost::hash_combine(result, data.scope.getName());
|
||||
boost::hash_combine(result, data.index);
|
||||
return result;
|
||||
}
|
||||
|
||||
// A base class for objects that contain a Guid and that want lookup-by-Guid
|
||||
template<class T>
|
||||
class RBXBaseClass GuidItem
|
||||
{
|
||||
public:
|
||||
// A Registry maintains lookup information for Guids.
|
||||
// Each instance can belong to only one Registry.
|
||||
// Usually a Registry is associated with a DataModel
|
||||
class Registry
|
||||
: public rbx::quick_intrusive_ptr_target<Registry>
|
||||
{
|
||||
friend class GuidItem;
|
||||
typedef boost::unordered_map<Guid::Data, weak_ptr<T> > Map;
|
||||
Map map;
|
||||
RBX::mutex mutex;
|
||||
|
||||
Registry()
|
||||
{}
|
||||
public:
|
||||
static boost::intrusive_ptr<Registry> create()
|
||||
{
|
||||
return boost::intrusive_ptr<Registry>(new Registry());
|
||||
}
|
||||
|
||||
~Registry()
|
||||
{
|
||||
RBXASSERT(map.size() ==0);
|
||||
}
|
||||
|
||||
// Returns true for empty Guid data, false for unregistered Guid data
|
||||
bool lookupByGuid(const Guid::Data& data, shared_ptr<T> &result)
|
||||
{
|
||||
if(data.scope.isNull())
|
||||
{
|
||||
result.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
RBX::mutex::scoped_lock lock(mutex);
|
||||
typename Map::const_iterator iter = GuidItem::Registry::map.find(data);
|
||||
if (iter!=map.end())
|
||||
{
|
||||
result = iter->second.lock();
|
||||
}
|
||||
else
|
||||
{
|
||||
result.reset();
|
||||
}
|
||||
return !!result;
|
||||
}
|
||||
|
||||
shared_ptr<T> getByGuid(const Guid::Data& data)
|
||||
{
|
||||
shared_ptr<T> result;
|
||||
lookupByGuid(data, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Ensure that this Guid is in the registry (thread-safe)
|
||||
void registerGuid(const T* item)
|
||||
{
|
||||
reg(item);
|
||||
}
|
||||
|
||||
// Assigns a new guid to item. (not thread-safe)
|
||||
void assignGuid(T* item, const Guid::Data& guidData)
|
||||
{
|
||||
if (item->registry)
|
||||
item->registry->unregister(item);
|
||||
|
||||
item->guid.assign(guidData);
|
||||
|
||||
reg(item);
|
||||
|
||||
item->onGuidChanged();
|
||||
}
|
||||
|
||||
void tryUnregister(GuidItem* item)
|
||||
{
|
||||
// In ClientReplicator::streamOutInstance(), we are traverse all the part's descendants and unregister them
|
||||
// It is possible some descendants have been already GC'd and unregistered earlier from the same GC loop in GCJob::gcRegion()
|
||||
// Here we simply skip it if the item has already been unregistered.
|
||||
if (item->registry)
|
||||
{
|
||||
unregister(item);
|
||||
}
|
||||
}
|
||||
|
||||
void unregister(GuidItem* item)
|
||||
{
|
||||
RBXASSERT(item->registry.get()==this);
|
||||
Guid::Data data;
|
||||
item->guid.extract(data);
|
||||
{
|
||||
RBX::mutex::scoped_lock lock(mutex);
|
||||
int num = map.erase(data);
|
||||
RBXASSERT(num == 1);
|
||||
}
|
||||
item->registry.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
void reg(const T* item)
|
||||
{
|
||||
if (!item->registry)
|
||||
{
|
||||
Guid::Data data;
|
||||
item->guid.extract(data);
|
||||
RBX::mutex::scoped_lock lock(mutex);
|
||||
if (!item->registry) // thread-safe check
|
||||
{
|
||||
map[data] = weak_from(const_cast<T*>(item));
|
||||
item->registry = this;
|
||||
}
|
||||
}
|
||||
else
|
||||
RBXASSERT(item->registry.get()==this);
|
||||
}
|
||||
|
||||
};
|
||||
friend class Registry;
|
||||
|
||||
private:
|
||||
mutable boost::intrusive_ptr<Registry> registry;
|
||||
Guid guid;
|
||||
|
||||
public:
|
||||
GuidItem()
|
||||
{
|
||||
}
|
||||
|
||||
~GuidItem()
|
||||
{
|
||||
if (registry)
|
||||
registry->unregister(this);
|
||||
}
|
||||
|
||||
const Guid& getGuid() const
|
||||
{
|
||||
return guid;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
#ifndef _WIN32
|
||||
#include <wwwsys.h>
|
||||
#endif
|
||||
|
||||
#include <HTParse.h>
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
|
||||
#ifndef _28C82C86EA754d62AF934FA46C3698ED
|
||||
#define _28C82C86EA754d62AF934FA46C3698ED
|
||||
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "rbx/Debug.h"
|
||||
#include "Util/Object.h"
|
||||
#include "Util/Memory.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace Reflection
|
||||
{
|
||||
class DescribedBase;
|
||||
}
|
||||
|
||||
// Used to reference RBX::Reflection::DescribedBase in the XmlElement class
|
||||
class InstanceHandle {
|
||||
shared_ptr<Reflection::DescribedBase> target;
|
||||
public:
|
||||
InstanceHandle() {}
|
||||
InstanceHandle(Reflection::DescribedBase* target);
|
||||
InstanceHandle(shared_ptr<Reflection::DescribedBase> target):target(target) {}
|
||||
InstanceHandle(const InstanceHandle& other):target(other.target) {}
|
||||
|
||||
InstanceHandle& operator=(const InstanceHandle& value) {
|
||||
target = value.target;
|
||||
return *this;
|
||||
}
|
||||
InstanceHandle& operator=(shared_ptr<Reflection::DescribedBase> value) {
|
||||
target = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool empty() const;
|
||||
|
||||
shared_ptr<Reflection::DescribedBase> getTarget() const { return target; }
|
||||
|
||||
void linkTo(shared_ptr<Reflection::DescribedBase> target);
|
||||
|
||||
bool operator==(const InstanceHandle& other) const { return operatorEqual(other); }
|
||||
bool operator!=(const InstanceHandle& other) const { return !operatorEqual(other); }
|
||||
bool operator<(const InstanceHandle& other) const{ return operatorLess(other); }
|
||||
bool operator>(const InstanceHandle& other) const{ return operatorGreater(other); }
|
||||
|
||||
protected:
|
||||
bool operatorEqual(const InstanceHandle& other) const;
|
||||
bool operatorLess(const InstanceHandle& other) const;
|
||||
bool operatorGreater(const InstanceHandle& other) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
// A simple hash function from Robert Sedgwicks Algorithms in C book.
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Hash {
|
||||
public:
|
||||
static unsigned int hash(const void* data, size_t bytes);
|
||||
static unsigned int hash(const std::string& str);
|
||||
|
||||
static void hashAppend(unsigned int& currentHash, const void* data, size_t bytes);
|
||||
static void hashAppend(unsigned int& currentHash, unsigned int append);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include "ObscureValue.h"
|
||||
#include "FastLog.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
// Wrapper around boost::scoped_ptr that allows it to be used like
|
||||
// a normal reference to the type (i.e. T& instead of T*).
|
||||
// Also mildly obscures stored values so that they are harder to find
|
||||
// with a memory scan.
|
||||
template<typename T> class HeapValue {
|
||||
boost::scoped_ptr<ObscureValue<T> > storage;
|
||||
public:
|
||||
explicit HeapValue(const T& value) : storage(new ObscureValue<T>(value)) {
|
||||
}
|
||||
|
||||
operator const T() const {
|
||||
return *storage;
|
||||
}
|
||||
|
||||
HeapValue& operator=(const T& other) {
|
||||
*storage = other;
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
// Disable no-arg construction, copy, and regular assign.
|
||||
// Some of these may be safe, but they are not needed yet,
|
||||
// and the safety of this class is easier to understand without
|
||||
// them.
|
||||
HeapValue();
|
||||
HeapValue(const HeapValue&);
|
||||
HeapValue& operator=(const HeapValue&);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "rbx/signal.h"
|
||||
#include "Util/G3DCore.h"
|
||||
|
||||
// hook up by overriding onServiceProvider call in this pattern:
|
||||
//
|
||||
// /*override*/ void onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider) {
|
||||
// Super::onServiceProvider(oldProvider, newProvider);
|
||||
// onServiceProviderHeartbeatInstance(oldProvider, newProvider); // hooks up heartbeat
|
||||
// }
|
||||
//
|
||||
|
||||
namespace RBX {
|
||||
class Heartbeat;
|
||||
class ServiceProvider;
|
||||
|
||||
class HeartbeatInstance
|
||||
{
|
||||
private:
|
||||
rbx::signals::scoped_connection heartbeatConnection;
|
||||
|
||||
protected:
|
||||
// call this inside onServiceProvider
|
||||
void onServiceProviderHeartbeatInstance(ServiceProvider* oldProvider, ServiceProvider* newProvider);
|
||||
|
||||
/*implement*/ virtual void onHeartbeat(const Heartbeat& event) = 0;
|
||||
|
||||
public:
|
||||
HeartbeatInstance() {}
|
||||
virtual ~HeartbeatInstance() {}
|
||||
};
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
#include "Util/NormalId.h"
|
||||
#include "appdraw/HandleType.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Extents;
|
||||
|
||||
class HandleHitTest
|
||||
{
|
||||
public:
|
||||
static bool hitTestHandleLocal( const Extents& localExtents,
|
||||
const CoordinateFrame& location,
|
||||
HandleType handleType,
|
||||
const Ray& gridRay,
|
||||
Vector3& hitPointWorld,
|
||||
NormalId& localNormalId,
|
||||
const int normalIdMask = NORM_ALL_MASK);
|
||||
|
||||
static bool hitTestHandleWorld( const Extents& worldExtents,
|
||||
HandleType handleType,
|
||||
const Ray& gridRay,
|
||||
Vector3& hitPointWorld,
|
||||
NormalId& worldNormalId,
|
||||
const int normalIdMask = NORM_ALL_MASK);
|
||||
|
||||
static bool hitTestMoveHandleWorld(const Extents& worldExtents,
|
||||
const RbxRay& gridRay,
|
||||
Vector3& hitPointWorld,
|
||||
NormalId& worldNormalId,
|
||||
const int normalIdMask = NORM_ALL_MASK);
|
||||
};
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Primitive;
|
||||
|
||||
// Fail: Stop the hit test - don't bore any further down
|
||||
// Ignore: Keep testing
|
||||
// Hit: Found something
|
||||
|
||||
class HitTestFilter {
|
||||
public:
|
||||
typedef enum Result { STOP_TEST,
|
||||
IGNORE_PRIM,
|
||||
INCLUDE_PRIM} Result;
|
||||
|
||||
virtual Result filterResult(const Primitive* testMe) const = 0;
|
||||
virtual ~HitTestFilter()
|
||||
{}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "rbx/atomic.h"
|
||||
#include "rbx/CEvent.h"
|
||||
#include "rbx/RunningAverage.h"
|
||||
#include "rbx/rbxTime.h"
|
||||
#include "util/HttpAux.h"
|
||||
|
||||
DYNAMIC_FASTFLAG(UseAssetTypeHeader)
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace HttpCache
|
||||
{
|
||||
enum Policy
|
||||
{
|
||||
// No caching by default.
|
||||
PolicyDefault,
|
||||
|
||||
// Cache based on the final URL (after all 302s).
|
||||
PolicyFinalRedirect,
|
||||
};
|
||||
} // namespace HttpCache
|
||||
|
||||
class mutex;
|
||||
|
||||
class http_status_error:
|
||||
public std::runtime_error
|
||||
{
|
||||
public:
|
||||
int statusCode;
|
||||
http_status_error(int statusCode);
|
||||
http_status_error(int statusCode, const std::string& message);
|
||||
};
|
||||
|
||||
class Http
|
||||
{
|
||||
public:
|
||||
typedef enum { Uninitialized=-1 ,WinInet=0, WinHttp=1, XboxHttp=2 } API;
|
||||
|
||||
enum CookieSharingPolicy
|
||||
{
|
||||
CookieSharingUndefined = 0x0,
|
||||
CookieSharingMultipleProcessesRead = 0x1,
|
||||
CookieSharingMultipleProcessesWrite = 0x2,
|
||||
CookieSharingSingleProcessMultipleThreads = 0x4,
|
||||
};
|
||||
|
||||
inline friend CookieSharingPolicy operator|(CookieSharingPolicy a, CookieSharingPolicy b)
|
||||
{
|
||||
return static_cast<CookieSharingPolicy>(static_cast<int>(a) | static_cast<int>(b));
|
||||
}
|
||||
|
||||
inline friend CookieSharingPolicy operator|=(CookieSharingPolicy a, CookieSharingPolicy b)
|
||||
{
|
||||
return static_cast<CookieSharingPolicy>(static_cast<int>(a) | static_cast<int>(b));
|
||||
}
|
||||
|
||||
static std::string accessKey;
|
||||
static std::string gameSessionID; // additional header to be sent in POST requests to roblox
|
||||
static std::string gameID;
|
||||
static std::string placeID;
|
||||
static std::string requester;
|
||||
static std::string rbxUserAgent;
|
||||
|
||||
static int playerCount;
|
||||
|
||||
static bool useDefaultTimeouts;
|
||||
|
||||
// Defined in Utilities.cpp.
|
||||
static const std::string kGameSessionHeaderKey;
|
||||
static const std::string kGameIdHeaderKey;
|
||||
static const std::string kPlaceIdHeaderKey;
|
||||
static const std::string kRequesterHeaderKey;
|
||||
static const std::string kPlayerCountHeaderKey;
|
||||
static const std::string kAccessHeaderKey;
|
||||
static const std::string kAssetTypeKey;
|
||||
static const std::string kRBXAuthenticationNegotiation;
|
||||
static const std::string kContentTypeDefaultUnspecified;
|
||||
static const std::string kContentTypeUrlEncoded;
|
||||
static const std::string kContentTypeApplicationJson;
|
||||
static const std::string kContentTypeApplicationXml;
|
||||
static const std::string kContentTypeTextPlain;
|
||||
static const std::string kContentTypeTextXml;
|
||||
|
||||
private:
|
||||
static API defaultApi;
|
||||
static CookieSharingPolicy cookieSharingPolicy;
|
||||
|
||||
std::string alternateUrl; // Used if a CDN fails to deliver and we can try an alternate URL for gets
|
||||
|
||||
HttpCache::Policy cachePolicy;
|
||||
|
||||
int connectTimeoutMillis;
|
||||
int responseTimeoutMillis;
|
||||
int sendTimeoutMillis;
|
||||
int dataSendTimeoutMillis;
|
||||
|
||||
API instanceApi;
|
||||
|
||||
static RBX::mutex *robloxResponceLock;
|
||||
static RBX::mutex *cdnResponceLock;
|
||||
static std::string lastCsrfToken;
|
||||
static boost::mutex lastCsrfTokenMutex;
|
||||
|
||||
class MutexGuard
|
||||
{
|
||||
public:
|
||||
MutexGuard();
|
||||
~MutexGuard();
|
||||
};
|
||||
|
||||
static MutexGuard lockGuard;
|
||||
|
||||
void init();
|
||||
public:
|
||||
static void init(API api, CookieSharingPolicy cookieSharingPolicy);
|
||||
static void SetUseStatistics(bool value);
|
||||
static void SetUseCurl(bool value);
|
||||
static rbx::atomic<int> cdnSuccessCount;
|
||||
static rbx::atomic<int> cdnFailureCount;
|
||||
static rbx::atomic<int> alternateCdnSuccessCount;
|
||||
static rbx::atomic<int> alternateCdnFailureCount;
|
||||
static double lastCdnFailureTimeSpan;
|
||||
static rbx::atomic<int> robloxSuccessCount;
|
||||
static rbx::atomic<int> robloxFailureCount;
|
||||
|
||||
static WindowAverage<double, double> robloxResponce;
|
||||
static WindowAverage<double, double> cdnResponce;
|
||||
|
||||
static RBX::mutex *getRobloxResponceLock();
|
||||
static RBX::mutex *getCdnResponceLock();
|
||||
|
||||
std::string url;
|
||||
Http():instanceApi(defaultApi),url("") { init(); }
|
||||
Http(const char* url):instanceApi(defaultApi),url(url) { init(); }
|
||||
Http(const char* url, API api):instanceApi(api),url(url) { init(); }
|
||||
Http(const std::string& url):instanceApi(defaultApi),url(url) { init(); }
|
||||
Http(const std::string& url, API api):instanceApi(api),url(url) { init(); }
|
||||
|
||||
bool recordStatistics;
|
||||
bool shouldRetry;
|
||||
HttpAux::AdditionalHeaders additionalHeaders;
|
||||
bool doNotUseCachedResponse;
|
||||
std::string authDomainUrl;
|
||||
void setAuthDomain(std::string domain)
|
||||
{
|
||||
authDomainUrl = domain;
|
||||
additionalHeaders[kRBXAuthenticationNegotiation] = domain;
|
||||
}
|
||||
void setExpectedAssetType(const std::string& type)
|
||||
{
|
||||
if (DFFlag::UseAssetTypeHeader && !type.empty())
|
||||
additionalHeaders[kAssetTypeKey] = type;
|
||||
}
|
||||
|
||||
static void setCookiesForDomain(const std::string& domain, const std::string& cookies);
|
||||
static void getCookiesForDomain(const std::string& domain, std::string& cookies);
|
||||
|
||||
void setResponseTimeout(int timeout) { responseTimeoutMillis = timeout; }
|
||||
void setSendTimeout(int timeout) { sendTimeoutMillis = timeout; }
|
||||
void setDataSendTimeout(int timeout) { dataSendTimeoutMillis = timeout; }
|
||||
void setConnectionTimeout(int timeout) { connectTimeoutMillis = timeout; }
|
||||
void setCachePolicy(const HttpCache::Policy policy) { cachePolicy = policy; }
|
||||
|
||||
// Async
|
||||
void post(const std::string& input, const std::string& contentType, bool compress, boost::function<void(std::string*, std::exception*)> handler, bool externalRequest = false);
|
||||
void post(boost::shared_ptr<std::istream> input, const std::string& contentType, bool compress, boost::function<void(std::string *, std::exception*)> handler, bool externalRequest = false);
|
||||
void get(boost::function<void(std::string*, std::exception*)> handler, bool allowExternal = false);
|
||||
|
||||
// Sync
|
||||
void post(std::istream& input, const std::string& contentType, bool compress, std::string& response, bool externalRequest = false);
|
||||
void get(std::string& response, bool allowExternal = false);
|
||||
|
||||
static bool isExternalRequest(const char* url);
|
||||
static bool trustCheck(const char* url, bool allowExternal = false);
|
||||
static bool trustCheckBrowser(const char* url);
|
||||
static bool isScript(const char* url);
|
||||
static bool isRobloxSite(const char* url);
|
||||
static bool isStrictlyRobloxSite(const char* url);
|
||||
static bool isMoneySite(const char* url);
|
||||
|
||||
// Utility
|
||||
static std::string urlEncode(const std::string& s);
|
||||
// urlDecode is only tested to work on strings produced from urlEncode
|
||||
static std::string urlDecode(const std::string& fragment);
|
||||
|
||||
void applyAdditionalHeaders(RBX::HttpAux::AdditionalHeaders& outHeaders);
|
||||
|
||||
private:
|
||||
void httpGetPost(bool isPost, std::istream& dataStream, const std::string& contentType, bool compressData, const HttpAux::AdditionalHeaders& additionalHeaders, bool allowExternal, std::string& response, bool forceNativeHttp = false);
|
||||
#if defined(RBX_PLATFORM_DURANGO)
|
||||
void httpGetPostXbox(bool isPost, std::istream& dataStream, const std::string& contentType, bool compressData, const HttpAux::AdditionalHeaders& additionalHeaders, bool allowExternal, HttpCache::Policy cachePolicy, std::string& response);
|
||||
#elif defined(_WIN32)
|
||||
void httpGetPostWinInet(bool isPost, std::istream& dataStream, const std::string& contentType, bool compressData, const HttpAux::AdditionalHeaders& additionalHeaders, bool allowExternal, std::string& response);
|
||||
void httpGetPostWinHttp(bool isPost, std::istream& dataStream, const std::string& contentType, bool compressData, const HttpAux::AdditionalHeaders& additionalHeaders, bool allowExternal, std::string& response);
|
||||
#elif defined(__APPLE__)
|
||||
void httpGetPostImpl(bool isPost, std::istream& dataStream, const std::string& contentType, bool compressData, const HttpAux::AdditionalHeaders& additionalHeaders, bool allowExternal, std::string& response);
|
||||
#endif
|
||||
bool doHttpGetPostWithNativeFallbackForReporting(bool isPost, std::istream& dataStream, const std::string& contentType, bool compressData, const HttpAux::AdditionalHeaders& additionalHeaders, bool allowExternal, std::string& response);
|
||||
|
||||
void ThrowIfFailure(bool success, const char* message);
|
||||
|
||||
#ifdef _WIN32
|
||||
static void setCookiesForDomainWinInet(const std::string& domain, const std::string& cookies);
|
||||
#endif
|
||||
public:
|
||||
#ifdef _WIN32
|
||||
void onWinHttpRedirect(unsigned long dwInternetStatus, std::string redirectUrl);
|
||||
#endif
|
||||
|
||||
static void ThrowIfFailure(bool success, const char* url, const char* message);
|
||||
|
||||
#if defined(_WIN32) && !defined(RBX_PLATFORM_DURANGO)
|
||||
static void ThrowLastError(int error, const char* url, const char* message);
|
||||
#endif
|
||||
|
||||
static void setProxy(const std::string& host, long port = 0);
|
||||
|
||||
// These methods are not safe to be called from static initializers, because they rely on
|
||||
// static member variables (which don't have order guarantees wrt other static initializers).
|
||||
static std::string getLastCsrfToken();
|
||||
static void setLastCsrfToken(const std::string& newToken);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <istream>
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "util/HttpAux.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
typedef boost::shared_future<std::string> HttpFuture;
|
||||
|
||||
class HttpOptions
|
||||
{
|
||||
friend class HttpAsync;
|
||||
|
||||
public:
|
||||
HttpOptions()
|
||||
: external(false)
|
||||
, doNotUseCachedResponse(false)
|
||||
{
|
||||
}
|
||||
|
||||
void addHeader(const std::string& key, const std::string& value);
|
||||
void setExternal(bool value);
|
||||
void setDoNotUseCachedResponse();
|
||||
|
||||
private:
|
||||
HttpAux::AdditionalHeaders headers;
|
||||
bool external;
|
||||
bool doNotUseCachedResponse;
|
||||
};
|
||||
|
||||
class HttpPostData
|
||||
{
|
||||
friend class HttpAsync;
|
||||
|
||||
public:
|
||||
HttpPostData(const std::string& contents, const std::string& contentType, bool compress);
|
||||
HttpPostData(const boost::shared_ptr<std::istream>& contents, const std::string& contentType, bool compress);
|
||||
|
||||
private:
|
||||
boost::shared_ptr<std::istream> data;
|
||||
std::string contentType;
|
||||
bool compress;
|
||||
};
|
||||
|
||||
class HttpAsync
|
||||
{
|
||||
public:
|
||||
static HttpFuture get(const std::string& url, const HttpOptions& options = HttpOptions());
|
||||
static HttpFuture getWithRetries(const std::string& url, int retryCount, const HttpOptions& options = HttpOptions());
|
||||
|
||||
static HttpFuture post(const std::string& url, const HttpPostData& postData, const HttpOptions& options = HttpOptions());
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace HttpAux
|
||||
{
|
||||
typedef boost::unordered_map<std::string, std::string> AdditionalHeaders;
|
||||
} // namespace HttpAux
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,207 @@
|
||||
#pragma once
|
||||
#define _CRT_SECURE_NO_WARNINGS 1
|
||||
|
||||
#include "util/Http.h"
|
||||
#include "util/HttpAux.h"
|
||||
#include "util/FileSystem.h"
|
||||
#include "util/NamedMutex.h"
|
||||
#include "rbx/Debug.h"
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace HttpPlatformImpl
|
||||
{
|
||||
namespace Cache
|
||||
{
|
||||
// Given a url, provide hashed file location on disk.
|
||||
boost::filesystem::path cacheFilePath(const char* url);
|
||||
|
||||
struct Header
|
||||
{
|
||||
#define RBX_CACHE_FILE_MAGIC 0x52425848 // RBXH
|
||||
#define RBX_CACHE_FILE_VERSION 0x1
|
||||
#define RBX_CACHE_URL_MAX_LENGTH 1024U
|
||||
|
||||
const uint32_t magic;
|
||||
const uint32_t version;
|
||||
const uint32_t urlBytes;
|
||||
const uint8_t url[RBX_CACHE_URL_MAX_LENGTH]; // not null-terminated
|
||||
const uint32_t responseCode;
|
||||
const uint32_t responseHeadersSize;
|
||||
const uint32_t responseHeadersHash;
|
||||
const uint32_t responseBodySize;
|
||||
const uint32_t responseBodyHash;
|
||||
const uint32_t reserved;
|
||||
};
|
||||
|
||||
class Data
|
||||
{
|
||||
const uint8_t* underlying;
|
||||
const size_t bytes;
|
||||
|
||||
public:
|
||||
Data(const uint8_t* data, const size_t bytes) :
|
||||
underlying(data), bytes(bytes)
|
||||
{}
|
||||
|
||||
Data(const char* data, const size_t bytes) :
|
||||
underlying(reinterpret_cast<const uint8_t*>(data)), bytes(bytes)
|
||||
{
|
||||
RBXASSERT(sizeof(char) == sizeof(uint8_t));
|
||||
}
|
||||
|
||||
uint8_t operator[](size_t index) const
|
||||
{
|
||||
return underlying[index];
|
||||
}
|
||||
|
||||
const uint8_t* data() const
|
||||
{
|
||||
return underlying;
|
||||
}
|
||||
|
||||
std::string toString() const
|
||||
{
|
||||
std::string result;
|
||||
result.assign(underlying, underlying+bytes);
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return bytes;
|
||||
}
|
||||
};
|
||||
|
||||
// The data in this structure is read-only, and if you
|
||||
// want to update the underlying data, you must do it via
|
||||
// the update() method.
|
||||
struct CacheEntry // Word-aligned data structure
|
||||
{
|
||||
Header cacheHeader;
|
||||
uint8_t data[1];
|
||||
|
||||
const Data getResponseHeader() const;
|
||||
const Data getResponseBody() const;
|
||||
|
||||
CacheEntry(const Header& cacheHeader, const Data& responseHeaders, const Data& responseBody);
|
||||
};
|
||||
|
||||
class CacheResult
|
||||
{
|
||||
boost::shared_ptr<CacheEntry> cacheEntry;
|
||||
size_t cacheSize;
|
||||
const std::string invalidReason;
|
||||
|
||||
public:
|
||||
explicit CacheResult(const std::string& invalidReason) : invalidReason(invalidReason)
|
||||
{}
|
||||
|
||||
explicit CacheResult( shared_ptr<CacheEntry> entry, size_t size)
|
||||
: cacheEntry(entry), cacheSize(size)
|
||||
{
|
||||
RBXASSERT(size);
|
||||
}
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return NULL != cacheEntry;
|
||||
}
|
||||
|
||||
const std::string& getInvalidReason() const
|
||||
{
|
||||
return invalidReason;
|
||||
}
|
||||
|
||||
const Header& getCacheHeader() const
|
||||
{
|
||||
return cacheEntry->cacheHeader;
|
||||
}
|
||||
|
||||
const Data getResponseHeader() const
|
||||
{
|
||||
return cacheEntry->getResponseHeader();
|
||||
}
|
||||
const Data getResponseBody() const
|
||||
{
|
||||
return cacheEntry->getResponseBody();
|
||||
}
|
||||
|
||||
const size_t size() const
|
||||
{
|
||||
return cacheSize;
|
||||
}
|
||||
|
||||
|
||||
// Converts the URL to a known location on disk and tries to open and return that file.
|
||||
// Returns NULL if file could not be opened.
|
||||
static CacheResult open(const char* assetUrl, const char* cdnUrl);
|
||||
|
||||
// Atomically update the file with new data and returned a new CacheEntry to it.
|
||||
static CacheResult update(const char* assetUrl, const char* cdnUrl, const uint32_t responseCode, const Data& headers, const Data& body);
|
||||
};
|
||||
|
||||
struct CacheCleanOptions
|
||||
{
|
||||
size_t numFilesRequiredBeforeCleaning;
|
||||
size_t numFilesToKeep;
|
||||
size_t numGigaBytesAvailableTrigger;
|
||||
bool flagCleanUpBasedOnMemory;
|
||||
};
|
||||
|
||||
void cleanCache(const CacheCleanOptions& options);
|
||||
} // namespace Cache
|
||||
|
||||
struct HttpOptions
|
||||
{
|
||||
// Basic data
|
||||
const std::string& url;
|
||||
bool externalRequest;
|
||||
HttpCache::Policy cachePolicy;
|
||||
|
||||
// Connection handling information
|
||||
long connectTimeoutMillis;
|
||||
long performTimeoutMillis;
|
||||
|
||||
// Post data
|
||||
std::istream* postData;
|
||||
bool compressedPostData;
|
||||
|
||||
// Header data
|
||||
std::string const* hdrContentType;
|
||||
HttpAux::AdditionalHeaders const* addlHeaders;
|
||||
|
||||
HttpOptions(const std::string& url, bool externalRequest, HttpCache::Policy cachePolicy, long connectTimeoutMillis, long performTimeoutMillis)
|
||||
:url(url)
|
||||
,externalRequest(externalRequest)
|
||||
,cachePolicy(cachePolicy)
|
||||
,connectTimeoutMillis(connectTimeoutMillis)
|
||||
,performTimeoutMillis(performTimeoutMillis)
|
||||
,postData(NULL)
|
||||
,hdrContentType(NULL)
|
||||
,addlHeaders(NULL)
|
||||
{}
|
||||
|
||||
void setPostData(std::istream* dataStream, bool compressed)
|
||||
{
|
||||
postData = dataStream;
|
||||
compressedPostData = compressed;
|
||||
}
|
||||
|
||||
void setHeaders(const std::string* contentType, const HttpAux::AdditionalHeaders* headers)
|
||||
{
|
||||
hdrContentType = contentType;
|
||||
addlHeaders = headers;
|
||||
}
|
||||
}; // struct HttpOptions
|
||||
|
||||
void init(Http::CookieSharingPolicy cookieSharingPolicy); // NOTE: This call is not thread-safe.
|
||||
void setCookiesForDomain(const std::string& domain, const std::string& cookies);
|
||||
void getCookiesForDomain(const std::string& domain, std::string& cookies);
|
||||
boost::filesystem::path getRobloxCookieJarPath();
|
||||
void setProxy(const std::string& host, long port = 0);
|
||||
void perform(HttpOptions& options, std::string& response);
|
||||
} // namespace HttpPlatformImpl
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,24 @@
|
||||
/* Copyright 2003-2006 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
#include "rbx/Declarations.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
//
|
||||
// http://www.parashift.com/c++-faq-lite/multiple-inheritance.html#faq-25.10
|
||||
|
||||
// This is a virtual base class - see note above. Any object that descends from it
|
||||
// should use the "virtual" keyword, so only one is included.
|
||||
//
|
||||
class RBXInterface IHasLocation
|
||||
{
|
||||
public:
|
||||
virtual const CoordinateFrame getLocation() = 0;
|
||||
|
||||
virtual ~IHasLocation() {}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,20 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "rbx/Debug.h"
|
||||
|
||||
// Simple class for returning metric values - used for graphics reporting
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class RBXInterface IMetric
|
||||
{
|
||||
public:
|
||||
IMetric() {}
|
||||
virtual ~IMetric() {}
|
||||
|
||||
virtual std::string getMetric(const std::string& metric) const = 0;
|
||||
virtual double getMetricValue(const std::string& metric) const = 0;
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,154 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "boost/utility.hpp"
|
||||
#include "util/utilities.h"
|
||||
#include "Util/G3DCore.h"
|
||||
#include "rbx/Debug.h"
|
||||
#include "G3D/Array.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
/* USAGE
|
||||
class C
|
||||
{
|
||||
private:
|
||||
int index;
|
||||
|
||||
public:
|
||||
C() : index(-1) {}
|
||||
~C() {RBXASSERT(index == -1);}
|
||||
|
||||
int& getIndex() {return index;}
|
||||
};
|
||||
|
||||
|
||||
main()
|
||||
{
|
||||
IndexArray<C, &C::getIndex> array;
|
||||
|
||||
C* c = new C();
|
||||
C c2;
|
||||
|
||||
array.fastAppend(c);
|
||||
array.fastAppend(&c2);
|
||||
|
||||
array.fastRemove(c)
|
||||
array.fastRemove(&c2);
|
||||
}
|
||||
*/
|
||||
|
||||
template <class Item, int& (Item::*getIndex)()>
|
||||
class IndexArray
|
||||
: public boost::noncopyable // You can't copy elements from one array to another
|
||||
// since the index values can't be shared.
|
||||
{
|
||||
private:
|
||||
G3D::Array<Item*> array;
|
||||
|
||||
int& indexOf(Item* item) const {
|
||||
return (item->*getIndex)();
|
||||
}
|
||||
|
||||
public:
|
||||
typedef Item** Iterator;
|
||||
typedef const Item** ConstIterator;
|
||||
|
||||
inline void fastAppend(Item* item)
|
||||
{
|
||||
RBXASSERT(item);
|
||||
RBXASSERT(indexOf(item) == -1);
|
||||
RBXASSERT_IF_VALIDATING(array.find(item) == array.end());
|
||||
|
||||
indexOf(item) = array.size();
|
||||
array.append(item);
|
||||
}
|
||||
|
||||
inline void fastRemove(Item* item)
|
||||
{
|
||||
RBXASSERT_IF_VALIDATING(array.find(item) != array.end());
|
||||
|
||||
int removeIndex = indexOf(item);
|
||||
|
||||
RBXASSERT(removeIndex >= 0);
|
||||
RBXASSERT(array[removeIndex] == item);
|
||||
|
||||
// Move last item to removal index
|
||||
Item* oldLast = array.last(); // if array size == 1, this is redundant
|
||||
array[removeIndex] = oldLast;
|
||||
indexOf(oldLast) = removeIndex;
|
||||
array.pop(false);
|
||||
|
||||
// Update indices
|
||||
indexOf(item) = -1;
|
||||
}
|
||||
|
||||
inline void remove(Item* item)
|
||||
{
|
||||
RBXASSERT_IF_VALIDATING(array.find(item) != array.end());
|
||||
|
||||
int removeIndex = indexOf(item);
|
||||
|
||||
RBXASSERT(removeIndex >= 0);
|
||||
RBXASSERT(array[removeIndex] == item);
|
||||
|
||||
// Move all the items back in the array.
|
||||
for (int i = removeIndex; i < array.size() - 1; i++)
|
||||
{
|
||||
Item* nextItem = array[i + 1];
|
||||
array[i] = nextItem;
|
||||
indexOf(nextItem) = i;
|
||||
}
|
||||
|
||||
array.pop(false);
|
||||
|
||||
// Update indices
|
||||
indexOf(item) = -1;
|
||||
}
|
||||
|
||||
inline bool fastContains(Item* item) const
|
||||
{
|
||||
bool answer = (indexOf(item) >= 0);
|
||||
RBXASSERT_IF_VALIDATING(answer == underlyingArray().contains(item));
|
||||
return answer;
|
||||
}
|
||||
|
||||
G3D::Array<Item*>& underlyingArray() {
|
||||
return array;
|
||||
}
|
||||
|
||||
const G3D::Array<Item*>& underlyingArray() const {
|
||||
return array;
|
||||
}
|
||||
|
||||
inline Item* operator[](int n) {
|
||||
RBXASSERT(indexOf(array[n]) == n);
|
||||
return array[n];
|
||||
}
|
||||
|
||||
inline Item* operator[](unsigned int n) {
|
||||
RBXASSERT(indexOf(array[n]) == n);
|
||||
return array[n];
|
||||
}
|
||||
|
||||
inline Item* const operator[](int n) const { // the pointer is const?
|
||||
RBXASSERT(indexOf(array[n]) == n);
|
||||
return array[n];
|
||||
}
|
||||
|
||||
inline Item* const operator[](unsigned int n) const { // the pointer is const?...
|
||||
RBXASSERT(indexOf(array[n]) == n);
|
||||
return array[n];
|
||||
}
|
||||
|
||||
inline int size() const {
|
||||
return array.size();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}// namespace
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class IndexBox {
|
||||
|
||||
private:
|
||||
/**
|
||||
Looking from positive X back through to negative X, z is left, y is up
|
||||
0 1 4 5
|
||||
|
||||
2 3 6 7
|
||||
front back (seen through front)
|
||||
*/
|
||||
|
||||
Vector3 corner[8];
|
||||
public:
|
||||
|
||||
IndexBox();
|
||||
IndexBox(
|
||||
const Vector3& min,
|
||||
const Vector3& max);
|
||||
|
||||
virtual ~IndexBox() {}
|
||||
|
||||
Vector3 getCenter() const;
|
||||
|
||||
Vector3 getCorner(int i) const {
|
||||
return corner[i];
|
||||
}
|
||||
|
||||
Vector3 getFaceNormal(int f) const {
|
||||
return Vector3( INDEXBOX_FACE_TO_NORMAL[f][0],
|
||||
INDEXBOX_FACE_TO_NORMAL[f][1],
|
||||
INDEXBOX_FACE_TO_NORMAL[f][2]);
|
||||
}
|
||||
|
||||
Vector3 getEdgeNormal(int f, int e) const {
|
||||
return getFaceNormal(INDEXBOX_FACE_EDGE_TO_NORMAL[f][e]);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the four corners of a face (0 <= f < 6).
|
||||
The corners are returned to form a counter clockwise quad facing outwards.
|
||||
*/
|
||||
void getFaceCorners(
|
||||
int f,
|
||||
Vector3& v0,
|
||||
Vector3& v1,
|
||||
Vector3& v2,
|
||||
Vector3& v3) const;
|
||||
|
||||
/** The edge travels from v0 to v1. nR is to the right and nL is to the left.*/
|
||||
void getEdge(
|
||||
int e,
|
||||
Vector3& v0,
|
||||
Vector3& v1,
|
||||
Vector3& nL,
|
||||
Vector3& nR) const;
|
||||
|
||||
void getEdge(
|
||||
int e,
|
||||
Vector4& v0,
|
||||
Vector4& v1,
|
||||
Vector3& nL,
|
||||
Vector3& nR) const;
|
||||
|
||||
static void getTextureCornersCentered(
|
||||
int f,
|
||||
const Vector3& halfSize,
|
||||
Vector2& t0,
|
||||
Vector2& t1,
|
||||
Vector2& t2,
|
||||
Vector2& t3);
|
||||
|
||||
static void getTextureCornersGrid(
|
||||
int f,
|
||||
const Vector3& halfSize,
|
||||
Vector2& t0,
|
||||
Vector2& t1,
|
||||
Vector2& t2,
|
||||
Vector2& t3);
|
||||
/**
|
||||
Returns true if this IndexBox is culled by the provided set of
|
||||
planes. The IndexBox is culled if there exists at least one plane
|
||||
whose halfspace the entire IndexBox is not in.
|
||||
*/
|
||||
bool culledBy(
|
||||
const Plane* plane,
|
||||
int numPlanes) const;
|
||||
|
||||
|
||||
bool contains(
|
||||
const Vector3& point) const;
|
||||
|
||||
static const int INDEXBOX_FACE_TO_VERTEX[6][4];
|
||||
static const float INDEXBOX_FACE_TO_NORMAL[6][3];
|
||||
static const int INDEXBOX_FACE_EDGE_TO_NORMAL[6][4];
|
||||
|
||||
/** normal indices are into INDEXBOX_FACE_TO_NORMAL array */
|
||||
static const int INDEXBOX_EDGE_TO_VERTEX_AND_NORMALS[12][4];
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,138 @@
|
||||
/* Copyright 2003-2006 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Util/IndexedTree.h"
|
||||
|
||||
/*
|
||||
used ad the basis for the Primitive / Clump / Assembly / Mechanism / SimJob data structures
|
||||
|
||||
Up: Parent
|
||||
Down: Child
|
||||
Right: Upper
|
||||
Left: Lower
|
||||
|
||||
Primitive <-> Clump <-> Assembly <-> Mechanism
|
||||
A
|
||||
|
|
||||
Primitive
|
||||
A A
|
||||
| |
|
||||
Primitive
|
||||
A
|
||||
|
|
||||
Primitive <-> Clump A
|
||||
A |
|
||||
|
|
||||
Primitive
|
||||
A A
|
||||
| |
|
||||
Primitive
|
||||
A
|
||||
|
|
||||
Primitive <-> Clump <-> Assembly
|
||||
|
||||
*/
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class IndexedMesh : public IndexedTree
|
||||
{
|
||||
private:
|
||||
IndexedMesh* upper; // could be null - only exists if direct connection to upper
|
||||
IndexedMesh* lower; // could be null - only exists if direct connection to upper
|
||||
IndexedMesh* computedUpper; // should == computeUpper;
|
||||
|
||||
protected:
|
||||
// TODO: Make these protected
|
||||
IndexedMesh* getUpper() {return upper;}
|
||||
IndexedMesh* getLower() {return lower;}
|
||||
|
||||
const IndexedMesh* getConstUpper() const {return upper;}
|
||||
const IndexedMesh* getConstLower() const {return lower;}
|
||||
|
||||
private:
|
||||
const IndexedMesh* computeParentFromLower() const;
|
||||
|
||||
void setComputedUpper(IndexedMesh* newComputedUpper);
|
||||
void setLower(IndexedMesh* newLower);
|
||||
|
||||
void severeChildren(IndexedMesh* lowerChild);
|
||||
void attachChildren(IndexedMesh* lowerChild);
|
||||
|
||||
void lowersChanged() { // cycles up to the parent, calling onLowersChanged();
|
||||
onLowersChanged();
|
||||
if (getTypedParent<IndexedMesh>()) {
|
||||
getTypedParent<IndexedMesh>()->lowersChanged();
|
||||
}
|
||||
if (getUpper()) {
|
||||
getUpper()->lowersChanged();
|
||||
}
|
||||
}
|
||||
static IndexedMesh* computeUpper(IndexedMesh* lower);
|
||||
static const IndexedMesh* computeConstUpper(const IndexedMesh* lower);
|
||||
|
||||
void onLowerChildRemoved(IndexedMesh* lowerChild);
|
||||
void onLowerChildAdded(IndexedMesh* lowerChild);
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
//
|
||||
// Indexed Tree
|
||||
/*override*/ void onParentChanged(IndexedTree* oldParent);
|
||||
|
||||
protected:
|
||||
/*implement*/ virtual void onLowersChanged() {}
|
||||
|
||||
public:
|
||||
IndexedMesh();
|
||||
IndexedMesh(IndexedMesh* lower, IndexedMesh* parent);
|
||||
|
||||
~IndexedMesh();
|
||||
|
||||
IndexedMesh* getIndexedMeshParent(); // same as getTypedParent, but with bug checking
|
||||
const IndexedMesh* getConstIndexedMeshParent() const; // same as getTypedParent, but with bug checking
|
||||
|
||||
void setUpper(IndexedMesh* newUpper);
|
||||
|
||||
template<class Type>
|
||||
Type* getTypedLower() {
|
||||
return rbx_static_cast<Type*>(getLower());
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
const Type* getConstTypedLower() const {
|
||||
return rbx_static_cast<const Type*>(getConstLower());
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
Type* getTypedUpper() {
|
||||
return rbx_static_cast<Type*>(getUpper());
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
const Type* getConstTypedUpper() const {
|
||||
return rbx_static_cast<const Type*>(getConstUpper());
|
||||
}
|
||||
|
||||
IndexedMesh* getComputedUpper();
|
||||
const IndexedMesh* getConstComputedUpper() const;
|
||||
|
||||
static bool isUpperRoot(const IndexedMesh* lower);
|
||||
|
||||
template<class Type, class Func>
|
||||
inline void visitMeAndChildrenWhileNoUpper(Func func) // hack - for iterating all assemblies in a mechanism
|
||||
{
|
||||
Type* t = rbx_static_cast<Type*>(this);
|
||||
func(t);
|
||||
for (int i = 0; i < numChildren(); ++i) {
|
||||
Type* child = getTypedChild<Type>(i);
|
||||
IndexedMesh* childUpper = child->getUpper();
|
||||
if (!childUpper)
|
||||
{
|
||||
child->visitMeAndChildrenWhileNoUpperUppers(func);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,132 @@
|
||||
/* Copyright 2003-2006 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "rbx/Declarations.h"
|
||||
#include "Util/IndexArray.h"
|
||||
#include "rbx/Debug.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class RBXBaseClass IndexedTree
|
||||
{
|
||||
private:
|
||||
IndexedTree* parent;
|
||||
|
||||
int index;
|
||||
int& getIndex() {return index;}
|
||||
|
||||
IndexArray<IndexedTree, &IndexedTree::getIndex> children;
|
||||
|
||||
bool circularReference(IndexedTree* newAncestor, IndexedTree* child);
|
||||
|
||||
protected:
|
||||
virtual void onParentChanging() {}
|
||||
virtual void onParentChanged(IndexedTree* oldParent) {}
|
||||
virtual void onChildAdding(IndexedTree* child) {}
|
||||
virtual void onChildAdded(IndexedTree* child) {}
|
||||
virtual void onChildRemoving(IndexedTree* child) {}
|
||||
virtual void onChildRemoved(IndexedTree* child) {}
|
||||
virtual void onAncestorChanged() {}
|
||||
|
||||
void setIndexedTreeParent(IndexedTree* newParent);
|
||||
|
||||
public:
|
||||
IndexedTree();
|
||||
|
||||
virtual ~IndexedTree();
|
||||
|
||||
int numChildren() const {return children.size();}
|
||||
|
||||
template<class Type>
|
||||
Type* getTypedChild(int i) {
|
||||
return rbx_static_cast<Type*>(children[i]);
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
const Type* getConstTypedChild(int i) const {
|
||||
return rbx_static_cast<Type*>(children[i]);
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
Type* getTypedParent() {
|
||||
return rbx_static_cast<Type*>(parent);
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
const Type* getConstTypedParent() const {
|
||||
return rbx_static_cast<Type*>(parent);
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
Type* getRoot() {
|
||||
return (parent)
|
||||
? parent->getRoot<Type>()
|
||||
: rbx_static_cast<Type*>(this);
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
const Type* getRoot() const {
|
||||
return (parent)
|
||||
? parent->getRoot<Type>()
|
||||
: rbx_static_cast<const Type*>(this);
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
Type* getOneBelowRoot() {
|
||||
IndexedTree* above = parent;
|
||||
RBXASSERT(above != NULL);
|
||||
IndexedTree* answer = this;
|
||||
while (above->parent) {
|
||||
answer = above;
|
||||
above = above->parent;
|
||||
}
|
||||
return rbx_static_cast<Type*>(answer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int getDepth() const {
|
||||
return parent ? (parent->getDepth() + 1) : 1;
|
||||
}
|
||||
|
||||
template<class Type, class Func>
|
||||
inline void visitMeAndChildren(Func func)
|
||||
{
|
||||
Type* t = rbx_static_cast<Type*>(this);
|
||||
func(t);
|
||||
for (int i = 0; i < children.size(); ++i) {
|
||||
children[i]->visitMeAndChildren<Type, Func>(func);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Type, class Func>
|
||||
inline void visitConstMeAndChildren(Func func)
|
||||
{
|
||||
const Type* t = rbx_static_cast<const Type*>(this);
|
||||
func(t);
|
||||
for (int i = 0; i < children.size(); ++i) {
|
||||
children[i]->visitConstMeAndChildren<Type, Func>(func);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Type, class Func>
|
||||
inline void visitDescendents(Func func)
|
||||
{
|
||||
for (int i = 0; i < children.size(); ++i) {
|
||||
children[i]->visitMeAndChildren<Type, Func>(func);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Type, class Func>
|
||||
inline void visitConstDescendents(Func func) const
|
||||
{
|
||||
for (int i = 0; i < children.size(); ++i) {
|
||||
children[i]->visitConstMeAndChildren<Type, Func>(func);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
// A simple hash function from Robert Sedgwicks Algorithms in C book.
|
||||
|
||||
namespace RBX {
|
||||
|
||||
typedef enum {INSERT_RAW, INSERT_TO_TREE, INSERT_TO_3D_VIEW} InsertMode;
|
||||
|
||||
typedef enum {
|
||||
PUT_TOOL_IN_STARTERPACK, // The user has been prompted about putting a tool into the starter pack
|
||||
SUPPRESS_PROMPTS}
|
||||
PromptMode;
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,326 @@
|
||||
#pragma once
|
||||
|
||||
// This code was adapted from SDL via GNU license below
|
||||
|
||||
/*
|
||||
SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Sam Lantinga
|
||||
slouken@libsdl.org
|
||||
*/
|
||||
|
||||
namespace RBX {
|
||||
|
||||
enum KeyCode {
|
||||
SDLK_UNKNOWN = 0,
|
||||
SDLK_BACKSPACE = 8,
|
||||
SDLK_TAB = 9,
|
||||
SDLK_CLEAR = 12,
|
||||
SDLK_RETURN = 13,
|
||||
SDLK_PAUSE = 19,
|
||||
SDLK_ESCAPE = 27,
|
||||
SDLK_SPACE = 32,
|
||||
SDLK_EXCLAIM = 33,
|
||||
SDLK_QUOTEDBL = 34,
|
||||
SDLK_HASH = 35,
|
||||
SDLK_DOLLAR = 36,
|
||||
SDLK_PERCENT = 37,
|
||||
SDLK_AMPERSAND = 38,
|
||||
SDLK_QUOTE = 39,
|
||||
SDLK_LEFTPAREN = 40,
|
||||
SDLK_RIGHTPAREN = 41,
|
||||
SDLK_ASTERISK = 42,
|
||||
SDLK_PLUS = 43,
|
||||
SDLK_COMMA = 44,
|
||||
SDLK_MINUS = 45,
|
||||
SDLK_PERIOD = 46,
|
||||
SDLK_SLASH = 47,
|
||||
SDLK_0 = 48,
|
||||
SDLK_1 = 49,
|
||||
SDLK_2 = 50,
|
||||
SDLK_3 = 51,
|
||||
SDLK_4 = 52,
|
||||
SDLK_5 = 53,
|
||||
SDLK_6 = 54,
|
||||
SDLK_7 = 55,
|
||||
SDLK_8 = 56,
|
||||
SDLK_9 = 57,
|
||||
SDLK_COLON = 58,
|
||||
SDLK_SEMICOLON = 59,
|
||||
SDLK_LESS = 60,
|
||||
SDLK_EQUALS = 61,
|
||||
SDLK_GREATER = 62,
|
||||
SDLK_QUESTION = 63,
|
||||
SDLK_AT = 64,
|
||||
/*
|
||||
Skip uppercase letters
|
||||
*/
|
||||
SDLK_LEFTBRACKET = 91,
|
||||
SDLK_BACKSLASH = 92,
|
||||
SDLK_RIGHTBRACKET = 93,
|
||||
SDLK_CARET = 94,
|
||||
SDLK_UNDERSCORE = 95,
|
||||
SDLK_BACKQUOTE = 96,
|
||||
SDLK_a = 97,
|
||||
SDLK_b = 98,
|
||||
SDLK_c = 99,
|
||||
SDLK_d = 100,
|
||||
SDLK_e = 101,
|
||||
SDLK_f = 102,
|
||||
SDLK_g = 103,
|
||||
SDLK_h = 104,
|
||||
SDLK_i = 105,
|
||||
SDLK_j = 106,
|
||||
SDLK_k = 107,
|
||||
SDLK_l = 108,
|
||||
SDLK_m = 109,
|
||||
SDLK_n = 110,
|
||||
SDLK_o = 111,
|
||||
SDLK_p = 112,
|
||||
SDLK_q = 113,
|
||||
SDLK_r = 114,
|
||||
SDLK_s = 115,
|
||||
SDLK_t = 116,
|
||||
SDLK_u = 117,
|
||||
SDLK_v = 118,
|
||||
SDLK_w = 119,
|
||||
SDLK_x = 120,
|
||||
SDLK_y = 121,
|
||||
SDLK_z = 122,
|
||||
|
||||
SDLK_LEFTCURLY = 123,
|
||||
SDLK_PIPE = 124,
|
||||
SDLK_RIGHTCURLY = 125,
|
||||
SDLK_TILDE = 126,
|
||||
SDLK_DELETE = 127,
|
||||
/* End of ASCII mapped keysyms */
|
||||
|
||||
/* International keyboard syms */
|
||||
SDLK_WORLD_0 = 160, /* 0xA0 */
|
||||
SDLK_WORLD_1 = 161,
|
||||
SDLK_WORLD_2 = 162,
|
||||
SDLK_WORLD_3 = 163,
|
||||
SDLK_WORLD_4 = 164,
|
||||
SDLK_WORLD_5 = 165,
|
||||
SDLK_WORLD_6 = 166,
|
||||
SDLK_WORLD_7 = 167,
|
||||
SDLK_WORLD_8 = 168,
|
||||
SDLK_WORLD_9 = 169,
|
||||
SDLK_WORLD_10 = 170,
|
||||
SDLK_WORLD_11 = 171,
|
||||
SDLK_WORLD_12 = 172,
|
||||
SDLK_WORLD_13 = 173,
|
||||
SDLK_WORLD_14 = 174,
|
||||
SDLK_WORLD_15 = 175,
|
||||
SDLK_WORLD_16 = 176,
|
||||
SDLK_WORLD_17 = 177,
|
||||
SDLK_WORLD_18 = 178,
|
||||
SDLK_WORLD_19 = 179,
|
||||
SDLK_WORLD_20 = 180,
|
||||
SDLK_WORLD_21 = 181,
|
||||
SDLK_WORLD_22 = 182,
|
||||
SDLK_WORLD_23 = 183,
|
||||
SDLK_WORLD_24 = 184,
|
||||
SDLK_WORLD_25 = 185,
|
||||
SDLK_WORLD_26 = 186,
|
||||
SDLK_WORLD_27 = 187,
|
||||
SDLK_WORLD_28 = 188,
|
||||
SDLK_WORLD_29 = 189,
|
||||
SDLK_WORLD_30 = 190,
|
||||
SDLK_WORLD_31 = 191,
|
||||
SDLK_WORLD_32 = 192,
|
||||
SDLK_WORLD_33 = 193,
|
||||
SDLK_WORLD_34 = 194,
|
||||
SDLK_WORLD_35 = 195,
|
||||
SDLK_WORLD_36 = 196,
|
||||
SDLK_WORLD_37 = 197,
|
||||
SDLK_WORLD_38 = 198,
|
||||
SDLK_WORLD_39 = 199,
|
||||
SDLK_WORLD_40 = 200,
|
||||
SDLK_WORLD_41 = 201,
|
||||
SDLK_WORLD_42 = 202,
|
||||
SDLK_WORLD_43 = 203,
|
||||
SDLK_WORLD_44 = 204,
|
||||
SDLK_WORLD_45 = 205,
|
||||
SDLK_WORLD_46 = 206,
|
||||
SDLK_WORLD_47 = 207,
|
||||
SDLK_WORLD_48 = 208,
|
||||
SDLK_WORLD_49 = 209,
|
||||
SDLK_WORLD_50 = 210,
|
||||
SDLK_WORLD_51 = 211,
|
||||
SDLK_WORLD_52 = 212,
|
||||
SDLK_WORLD_53 = 213,
|
||||
SDLK_WORLD_54 = 214,
|
||||
SDLK_WORLD_55 = 215,
|
||||
SDLK_WORLD_56 = 216,
|
||||
SDLK_WORLD_57 = 217,
|
||||
SDLK_WORLD_58 = 218,
|
||||
SDLK_WORLD_59 = 219,
|
||||
SDLK_WORLD_60 = 220,
|
||||
SDLK_WORLD_61 = 221,
|
||||
SDLK_WORLD_62 = 222,
|
||||
SDLK_WORLD_63 = 223,
|
||||
SDLK_WORLD_64 = 224,
|
||||
SDLK_WORLD_65 = 225,
|
||||
SDLK_WORLD_66 = 226,
|
||||
SDLK_WORLD_67 = 227,
|
||||
SDLK_WORLD_68 = 228,
|
||||
SDLK_WORLD_69 = 229,
|
||||
SDLK_WORLD_70 = 230,
|
||||
SDLK_WORLD_71 = 231,
|
||||
SDLK_WORLD_72 = 232,
|
||||
SDLK_WORLD_73 = 233,
|
||||
SDLK_WORLD_74 = 234,
|
||||
SDLK_WORLD_75 = 235,
|
||||
SDLK_WORLD_76 = 236,
|
||||
SDLK_WORLD_77 = 237,
|
||||
SDLK_WORLD_78 = 238,
|
||||
SDLK_WORLD_79 = 239,
|
||||
SDLK_WORLD_80 = 240,
|
||||
SDLK_WORLD_81 = 241,
|
||||
SDLK_WORLD_82 = 242,
|
||||
SDLK_WORLD_83 = 243,
|
||||
SDLK_WORLD_84 = 244,
|
||||
SDLK_WORLD_85 = 245,
|
||||
SDLK_WORLD_86 = 246,
|
||||
SDLK_WORLD_87 = 247,
|
||||
SDLK_WORLD_88 = 248,
|
||||
SDLK_WORLD_89 = 249,
|
||||
SDLK_WORLD_90 = 250,
|
||||
SDLK_WORLD_91 = 251,
|
||||
SDLK_WORLD_92 = 252,
|
||||
SDLK_WORLD_93 = 253,
|
||||
SDLK_WORLD_94 = 254,
|
||||
SDLK_WORLD_95 = 255, /* 0xFF */
|
||||
|
||||
/* Numeric keypad */
|
||||
SDLK_KP0 = 256,
|
||||
SDLK_KP1 = 257,
|
||||
SDLK_KP2 = 258,
|
||||
SDLK_KP3 = 259,
|
||||
SDLK_KP4 = 260,
|
||||
SDLK_KP5 = 261,
|
||||
SDLK_KP6 = 262,
|
||||
SDLK_KP7 = 263,
|
||||
SDLK_KP8 = 264,
|
||||
SDLK_KP9 = 265,
|
||||
SDLK_KP_PERIOD = 266,
|
||||
SDLK_KP_DIVIDE = 267,
|
||||
SDLK_KP_MULTIPLY = 268,
|
||||
SDLK_KP_MINUS = 269,
|
||||
SDLK_KP_PLUS = 270,
|
||||
SDLK_KP_ENTER = 271,
|
||||
SDLK_KP_EQUALS = 272,
|
||||
|
||||
/* Arrows + Home/End pad */
|
||||
SDLK_UP = 273,
|
||||
SDLK_DOWN = 274,
|
||||
SDLK_RIGHT = 275,
|
||||
SDLK_LEFT = 276,
|
||||
SDLK_INSERT = 277,
|
||||
SDLK_HOME = 278,
|
||||
SDLK_END = 279,
|
||||
SDLK_PAGEUP = 280,
|
||||
SDLK_PAGEDOWN = 281,
|
||||
|
||||
/* Function keys */
|
||||
SDLK_F1 = 282,
|
||||
SDLK_F2 = 283,
|
||||
SDLK_F3 = 284,
|
||||
SDLK_F4 = 285,
|
||||
SDLK_F5 = 286,
|
||||
SDLK_F6 = 287,
|
||||
SDLK_F7 = 288,
|
||||
SDLK_F8 = 289,
|
||||
SDLK_F9 = 290,
|
||||
SDLK_F10 = 291,
|
||||
SDLK_F11 = 292,
|
||||
SDLK_F12 = 293,
|
||||
SDLK_F13 = 294,
|
||||
SDLK_F14 = 295,
|
||||
SDLK_F15 = 296,
|
||||
|
||||
/* Key state modifier keys */
|
||||
SDLK_NUMLOCK = 300,
|
||||
SDLK_CAPSLOCK = 301,
|
||||
SDLK_SCROLLOCK = 302,
|
||||
SDLK_RSHIFT = 303,
|
||||
SDLK_LSHIFT = 304,
|
||||
SDLK_RCTRL = 305,
|
||||
SDLK_LCTRL = 306,
|
||||
SDLK_RALT = 307,
|
||||
SDLK_LALT = 308,
|
||||
SDLK_RMETA = 309,
|
||||
SDLK_LMETA = 310,
|
||||
SDLK_LSUPER = 311, /* Left "Windows" key */
|
||||
SDLK_RSUPER = 312, /* Right "Windows" key */
|
||||
SDLK_MODE = 313, /* "Alt Gr" key */
|
||||
SDLK_COMPOSE = 314, /* Multi-key compose key */
|
||||
|
||||
/* Miscellaneous function keys */
|
||||
SDLK_HELP = 315,
|
||||
SDLK_PRINT = 316,
|
||||
SDLK_SYSREQ = 317,
|
||||
SDLK_BREAK = 318,
|
||||
SDLK_MENU = 319,
|
||||
SDLK_POWER = 320, /* Power Macintosh power key */
|
||||
SDLK_EURO = 321, /* Some european keyboards */
|
||||
SDLK_UNDO = 322, /* Atari keyboard has Undo */
|
||||
|
||||
/* Add any other keys here */
|
||||
|
||||
|
||||
// ROBLOX Gamepad stuff
|
||||
SDLK_GAMEPAD_BUTTONX = 1000,
|
||||
SDLK_GAMEPAD_BUTTONY = 1001,
|
||||
SDLK_GAMEPAD_BUTTONA = 1002,
|
||||
SDLK_GAMEPAD_BUTTONB = 1003,
|
||||
SDLK_GAMEPAD_BUTTONR1 = 1004,
|
||||
SDLK_GAMEPAD_BUTTONL1 = 1005,
|
||||
SDLK_GAMEPAD_BUTTONR2 = 1006,
|
||||
SDLK_GAMEPAD_BUTTONL2 = 1007,
|
||||
SDLK_GAMEPAD_BUTTONR3 = 1008,
|
||||
SDLK_GAMEPAD_BUTTONL3 = 1009,
|
||||
SDLK_GAMEPAD_BUTTONSTART = 1010,
|
||||
SDLK_GAMEPAD_BUTTONSELECT = 1011,
|
||||
SDLK_GAMEPAD_DPADLEFT = 1012,
|
||||
SDLK_GAMEPAD_DPADRIGHT = 1013,
|
||||
SDLK_GAMEPAD_DPADUP = 1014,
|
||||
SDLK_GAMEPAD_DPADDOWN = 1015,
|
||||
SDLK_GAMEPAD_THUMBSTICK1 = 1016,
|
||||
SDLK_GAMEPAD_THUMBSTICK2 = 1017,
|
||||
|
||||
SDLK_LAST
|
||||
};
|
||||
enum ModCode {
|
||||
KMOD_NONE = 0x0000,
|
||||
KMOD_LSHIFT= 0x0001,
|
||||
KMOD_RSHIFT= 0x0002,
|
||||
KMOD_LCTRL = 0x0040,
|
||||
KMOD_RCTRL = 0x0080,
|
||||
KMOD_LALT = 0x0100,
|
||||
KMOD_RALT = 0x0200,
|
||||
KMOD_LMETA = 0x0400,
|
||||
KMOD_RMETA = 0x0800,
|
||||
KMOD_NUM = 0x1000,
|
||||
KMOD_CAPS = 0x2000,
|
||||
KMOD_MODE = 0x4000,
|
||||
KMOD_RESERVED = 0x8000
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
namespace RBX {
|
||||
|
||||
typedef enum KeywordFilterType { INCLUDE_KEYWORDS = 0,
|
||||
EXCLUDE_KEYWORDS } KeywordFilterType;
|
||||
|
||||
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,267 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "Util/StandardOut.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
|
||||
template<class Key, class Data>
|
||||
class LRUCache
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::list< std::pair< Key, std::pair<unsigned long, Data> > > List; ///< Main cache storage typedef
|
||||
typedef typename List::iterator List_Iter; ///< Main cache iterator
|
||||
typedef typename List::const_iterator List_cIter; ///< Main cache iterator (const)
|
||||
|
||||
typedef boost::unordered_map<Key, List_Iter> Map; ///< Index typedef
|
||||
|
||||
typedef typename Map::iterator Map_Iter; ///< Index iterator
|
||||
typedef typename Map::const_iterator Map_cIter; ///< Index iterator (const)
|
||||
|
||||
protected:
|
||||
/// Main cache storage
|
||||
List list;
|
||||
/// Cache storage index
|
||||
Map index;
|
||||
|
||||
unsigned long totalMemory;
|
||||
|
||||
public:
|
||||
LRUCache() : totalMemory(0) {}
|
||||
~LRUCache()
|
||||
{
|
||||
this->clear();
|
||||
}
|
||||
|
||||
inline void printContentNames()
|
||||
{
|
||||
for(List_Iter iter = list.begin(); iter != list.end(); ++iter)
|
||||
{
|
||||
StandardOut::singleton()->printf(RBX::MESSAGE_INFO, "%s", iter->first.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
inline unsigned long size()
|
||||
{
|
||||
return list.size();
|
||||
}
|
||||
|
||||
inline unsigned long memSize()
|
||||
{
|
||||
return this->totalMemory;
|
||||
}
|
||||
|
||||
inline void clear()
|
||||
{
|
||||
list.clear();
|
||||
index.clear();
|
||||
totalMemory = 0;
|
||||
}
|
||||
|
||||
inline bool exists( const Key &key ) const
|
||||
{
|
||||
return index.find( key ) != index.end();
|
||||
}
|
||||
inline bool empty() const
|
||||
{
|
||||
return list.empty();
|
||||
}
|
||||
inline bool remove( const Key &key )
|
||||
{
|
||||
Map_Iter miter = index.find( key );
|
||||
if( miter == index.end() ) return false;
|
||||
remove( miter );
|
||||
return true;
|
||||
}
|
||||
/*inline void touch( const Key &key )
|
||||
{
|
||||
internalTouch(key);
|
||||
}*/
|
||||
|
||||
inline bool fetch( const Key &key, Data* result, unsigned long* size, bool touch = true )
|
||||
{
|
||||
Map_Iter miter = index.find( key );
|
||||
if( miter == index.end() ) return false;
|
||||
|
||||
if(touch){
|
||||
this->internalTouch( key );
|
||||
}
|
||||
if(result){
|
||||
(*result) = miter->second->second.second; // map -> list -> pair -> value
|
||||
}
|
||||
if(size){
|
||||
(*size) = miter->second->second.first;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool fetch( const Key &key, Data* result, bool touch = true )
|
||||
{
|
||||
unsigned long size = 0;
|
||||
return fetch(key, result, &size, touch);
|
||||
}
|
||||
|
||||
inline virtual void resize( unsigned long newSize)
|
||||
{
|
||||
while( list.size() > newSize) {
|
||||
// Remove the last element.
|
||||
List_Iter liter = list.end();
|
||||
--liter;
|
||||
this->remove( liter->first );
|
||||
}
|
||||
}
|
||||
|
||||
// returns the size of last removed element
|
||||
inline void removeLeastRecentlyUsed()
|
||||
{
|
||||
// Remove the last element.
|
||||
List_Iter liter = list.end();
|
||||
--liter;
|
||||
this->remove( liter->first );
|
||||
}
|
||||
|
||||
inline virtual void insert( const Key &key, const Data &data, const unsigned long dataSize = 0)
|
||||
{
|
||||
// Touch the key, if it exists, then replace the content.
|
||||
Map_Iter miter = this->internalTouch( key );
|
||||
if( miter != index.end() )
|
||||
this->remove( miter );
|
||||
|
||||
// Ok, do the actual insert at the head of the list
|
||||
list.push_front( std::make_pair( key, std::make_pair(dataSize, data) ) );
|
||||
List_Iter liter = list.begin();
|
||||
|
||||
// Store the index
|
||||
index.insert( std::make_pair( key, liter ) );
|
||||
|
||||
totalMemory += dataSize;
|
||||
}
|
||||
|
||||
inline void insert(List_cIter iter, List_cIter iterEnd)
|
||||
{
|
||||
for(; iter != iterEnd; ++iter){
|
||||
insert(iter->first, iter->second.second, iter->second.first);
|
||||
}
|
||||
}
|
||||
|
||||
inline List_Iter begin()
|
||||
{
|
||||
return list.begin();
|
||||
}
|
||||
inline List_Iter end()
|
||||
{
|
||||
return list.end();
|
||||
}
|
||||
private:
|
||||
inline Map_Iter internalTouch( const Key &key )
|
||||
{
|
||||
Map_Iter miter = index.find( key );
|
||||
if( miter == index.end() ) return miter;
|
||||
// Move the found node to the head of the list.
|
||||
list.splice( list.begin(), list, miter->second );
|
||||
return miter;
|
||||
}
|
||||
inline void remove( const Map_Iter &miter )
|
||||
{
|
||||
totalMemory -= miter->second->second.first;
|
||||
list.erase( miter->second );
|
||||
index.erase( miter );
|
||||
}
|
||||
};
|
||||
|
||||
template<class Key,class Data>
|
||||
class SizeEnforcedLRUCache : public LRUCache<Key, Data>
|
||||
{
|
||||
typedef LRUCache<Key, Data> Super;
|
||||
|
||||
/// Maximum size of the cache in elements
|
||||
unsigned long maxSize;
|
||||
|
||||
public:
|
||||
|
||||
SizeEnforcedLRUCache(const unsigned long maxSize)
|
||||
: maxSize(maxSize)
|
||||
{}
|
||||
~SizeEnforcedLRUCache() {}
|
||||
|
||||
inline void resize( unsigned long newSize)
|
||||
{
|
||||
maxSize = newSize;
|
||||
Super::resize(maxSize);
|
||||
}
|
||||
|
||||
inline void insert( const Key &key, const Data &data, const unsigned long dataSize = 0)
|
||||
{
|
||||
Super::insert(key, data, dataSize);
|
||||
|
||||
// Check to see if we need to remove an element due to exceeding max_size
|
||||
if( this->list.size() > maxSize ) {
|
||||
Super::removeLeastRecentlyUsed();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<class Key, class Data>
|
||||
class MemEnforcedLRUCache : public LRUCache<Key, Data>
|
||||
{
|
||||
typedef LRUCache<Key, Data> Super;
|
||||
|
||||
// Maximum memory size of all the elements in the cache
|
||||
unsigned long maxMemSize;
|
||||
|
||||
public:
|
||||
|
||||
MemEnforcedLRUCache (const unsigned long maxSize) : maxMemSize(maxSize) {}
|
||||
|
||||
inline virtual void resize( unsigned long newSize)
|
||||
{
|
||||
maxMemSize = newSize;
|
||||
while( this->totalMemory > maxMemSize )
|
||||
{
|
||||
Super::removeLeastRecentlyUsed();
|
||||
RBXASSERT(this->totalMemory >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
inline void insert( const Key &key, const Data &data, const unsigned long dataSize)
|
||||
{
|
||||
Super::insert(key, data, dataSize);
|
||||
|
||||
// Check to see if we need to remove an element due to exceeding max_size
|
||||
while( this->totalMemory > maxMemSize ) {
|
||||
Super::removeLeastRecentlyUsed();
|
||||
RBXASSERT(this->totalMemory >= 0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<class Key,class Data>
|
||||
class ConcurrentLRUCache
|
||||
{
|
||||
public:
|
||||
RBX::LRUCache<Key, Data> cache;
|
||||
boost::mutex mutex;
|
||||
public:
|
||||
ConcurrentLRUCache (int size)
|
||||
: cache(size)
|
||||
{}
|
||||
|
||||
bool fetch(const Key& id, Data* result)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
return cache.fetch(id, result);
|
||||
}
|
||||
|
||||
void insert(const Key& id, const Data& data)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
cache.insert(id, data);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/* Copyright 2014 ROBLOX Corporation, All Rights Reserved */
|
||||
#include "stdafx.h"
|
||||
|
||||
class LcmRand
|
||||
{
|
||||
public:
|
||||
LcmRand() : seed(1337U) {}
|
||||
|
||||
uint32_t value()
|
||||
{
|
||||
const static uint32_t a = 214013U;
|
||||
const static uint32_t c = 2531011U;
|
||||
seed = seed * a + c;
|
||||
return (seed >> 16) & 0x7FFF;
|
||||
}
|
||||
|
||||
void setSeed(uint32_t newSeed)
|
||||
{
|
||||
seed = newSeed;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t seed;
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class LegacyContentTable
|
||||
{
|
||||
private:
|
||||
typedef boost::unordered_map<std::string, std::string> UrlMap;
|
||||
UrlMap mMap;
|
||||
std::string mEmpty;
|
||||
|
||||
public:
|
||||
LegacyContentTable();
|
||||
|
||||
void AddEntry(const std::string& path, const std::string& contentId);
|
||||
void AddEntryProd(const std::string& path, const std::string& contentId);
|
||||
const std::string& FindEntry(const std::string& path);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
#pragma once
|
||||
#include "V8Tree/Service.h"
|
||||
#include "Util/AsyncHttpCache.h"
|
||||
|
||||
namespace RBX {
|
||||
extern const char* const sPages;
|
||||
|
||||
class Pages :
|
||||
public DescribedNonCreatable<Pages, Instance, sPages, Reflection::ClassDescriptor::RUNTIME_LOCAL>
|
||||
{
|
||||
protected:
|
||||
bool finished;
|
||||
shared_ptr<const Reflection::ValueArray> currentPage;
|
||||
|
||||
public:
|
||||
Pages();
|
||||
|
||||
virtual void fetchNextChunk(boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction) {};
|
||||
|
||||
shared_ptr<const Reflection::ValueArray> getCurrentPage();
|
||||
bool isFinished() const;
|
||||
void advanceToNextPageAsync(boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
};
|
||||
|
||||
extern const char* const sStandardPages;
|
||||
|
||||
class StandardPages :
|
||||
public DescribedNonCreatable<StandardPages, Pages, sStandardPages, Reflection::ClassDescriptor::RUNTIME_LOCAL>
|
||||
{
|
||||
weak_ptr<DataModel> weakDM;
|
||||
std::string fieldName;
|
||||
std::string requestUrl;
|
||||
int pageNumber;
|
||||
|
||||
void processFetchSuccess(std::string response, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
void processFetchError(std::string error, boost::function<void(std::string)> errorFunction);
|
||||
void processFetch(std::string* response, std::exception* exception, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
|
||||
public:
|
||||
StandardPages(weak_ptr<DataModel> weakDM, const std::string& requestUrl, const std::string& fieldName);
|
||||
virtual void fetchNextChunk(boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
};
|
||||
|
||||
extern const char* const sFriendPages;
|
||||
|
||||
class FriendPages :
|
||||
public DescribedNonCreatable<FriendPages, Pages, sFriendPages, Reflection::ClassDescriptor::RUNTIME_LOCAL>
|
||||
{
|
||||
weak_ptr<DataModel> weakDM;
|
||||
std::string fieldName;
|
||||
std::string requestUrl;
|
||||
shared_ptr<const Reflection::ValueArray> nextPage;
|
||||
int pageNumber;
|
||||
bool firstTime;
|
||||
|
||||
void processFetchSuccess(std::string response, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
void processFetchError(std::string error, boost::function<void(std::string)> errorFunction);
|
||||
void processFetch(std::string* response, std::exception* exception, boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
|
||||
public:
|
||||
FriendPages(weak_ptr<DataModel> weakDM, const std::string& requestUrl);
|
||||
virtual void fetchNextChunk(boost::function<void()> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
};
|
||||
|
||||
extern const char *const sLuaWebService;
|
||||
|
||||
#define LUA_WEB_SERVICE_STANDARD_PRIORITY 50
|
||||
|
||||
// This service is used to make web queries. It is frequently used by
|
||||
// function calls originating in Lua, but is not restricted to use
|
||||
// by Lua
|
||||
class LuaWebService
|
||||
: public DescribedNonCreatable<LuaWebService, Instance, sLuaWebService>
|
||||
, public Service
|
||||
{
|
||||
private:
|
||||
typedef DescribedNonCreatable<LuaWebService, Instance, sLuaWebService> Super;
|
||||
|
||||
struct CachedLuaWebServiceInfo
|
||||
{
|
||||
Reflection::Variant value;
|
||||
CachedLuaWebServiceInfo() {}
|
||||
CachedLuaWebServiceInfo(shared_ptr<const std::string> data, shared_ptr<const std::string> filename);
|
||||
};
|
||||
|
||||
struct CachedRawLuaWebServiceInfo
|
||||
{
|
||||
std::string value;
|
||||
CachedRawLuaWebServiceInfo() {}
|
||||
CachedRawLuaWebServiceInfo(shared_ptr<const std::string> data, shared_ptr<const std::string> filename);
|
||||
};
|
||||
|
||||
boost::shared_ptr<AsyncHttpCache<CachedLuaWebServiceInfo, true> > webCache;
|
||||
boost::shared_ptr<AsyncHttpCache<CachedRawLuaWebServiceInfo, true> > webRawCache;
|
||||
bool checkApiAccess;
|
||||
Time timeToRecheckApiAccess;
|
||||
boost::optional<bool > apiAccess;
|
||||
|
||||
template<typename Result>
|
||||
bool checkCache(const std::string& url, boost::function<void(Result)> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
|
||||
template<typename Result>
|
||||
static bool TryDispatchRequest(AsyncHttpCache<LuaWebService::CachedLuaWebServiceInfo, true>* webCache, const std::string& url,
|
||||
boost::function<void(Result)> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
|
||||
template<typename Result>
|
||||
static bool TryRawDispatchRequest(AsyncHttpCache<LuaWebService::CachedRawLuaWebServiceInfo, true>* webCache, const std::string& url,
|
||||
boost::function<void(Result)> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
|
||||
template<typename Result>
|
||||
static void Callback(boost::weak_ptr<LuaWebService> weakLuaWebService, AsyncHttpQueue::RequestResult requestResult, std::string url,
|
||||
boost::function<void(Result)> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
|
||||
static void RawCallback(boost::weak_ptr<LuaWebService> weakLuaWebService, AsyncHttpQueue::RequestResult requestResult, std::string url,
|
||||
boost::function<void(std::string)> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
public:
|
||||
LuaWebService();
|
||||
void asyncRequest(const std::string& url, float priority,
|
||||
boost::function<void(shared_ptr<const Reflection::ValueArray>)> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
void asyncRequest(const std::string& url, float priority,
|
||||
boost::function<void(shared_ptr<const Reflection::ValueMap>)> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
void asyncRequest(const std::string& url, float priority,
|
||||
boost::function<void(bool)> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
void asyncRequest(const std::string& url, float priority,
|
||||
boost::function<void(std::string)> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
void asyncRequest(const std::string& url, float priority,
|
||||
boost::function<void(int)> resumeFunction, boost::function<void(std::string)> errorFunction);
|
||||
|
||||
//Skips the caches
|
||||
void asyncRequestNoCache(const std::string& url, float priority, boost::function<void(shared_ptr<const Reflection::ValueMap>)> callback, AsyncHttpQueue::ResultJob resultJob);
|
||||
|
||||
// will block until api access request has returned
|
||||
bool isApiAccessEnabled();
|
||||
void setCheckApiAccessBecauseInStudio();
|
||||
|
||||
static bool parseWebJSONResponseHelper(std::string* response, std::exception* exception,
|
||||
shared_ptr<const Reflection::ValueTable>& result, std::string& status);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "rbx/declarations.h"
|
||||
#include <string>
|
||||
#include <istream>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class RBXInterface MD5Hasher
|
||||
{
|
||||
public:
|
||||
static MD5Hasher* create();
|
||||
virtual ~MD5Hasher() {}
|
||||
virtual void addData(std::istream& data) = 0;
|
||||
virtual void addData(const std::string& data) = 0;
|
||||
virtual void addData(const char* data, size_t nBytes) = 0;
|
||||
virtual const std::string& toString() = 0;
|
||||
virtual const char* c_str() = 0;
|
||||
|
||||
virtual void toBuffer(char (&result)[16]) = 0;
|
||||
|
||||
// Before 03-12-07 the hashing function didn't pad bytes with '0'
|
||||
static std::string convertToLegacyHash(std::string hash);
|
||||
};
|
||||
|
||||
std::string CollectMd5Hash(const std::string& fileName);
|
||||
std::string ComputeMd5Hash(const std::string& data);
|
||||
|
||||
}//namespace
|
||||
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// MachOBaseAddr.h
|
||||
// App
|
||||
//
|
||||
// Created by David Stahl on 11/10/14.
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef App_MachOBaseAddr_h
|
||||
#define App_MachOBaseAddr_h
|
||||
|
||||
uint32_t machODynamicBaseAddress(void);
|
||||
|
||||
uint32_t machOTextSize(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
// Helper class to gather identifying information about this machine and for
|
||||
// communicating with the web banned machine database.
|
||||
class MachineIdUploader {
|
||||
public:
|
||||
static const char* kBannedMachineMessage;
|
||||
enum Result {
|
||||
RESULT_MachineAccepted = 1,
|
||||
RESULT_MachineBanned = 0
|
||||
};
|
||||
// Gather identifying info for this machine, send it out, and return
|
||||
// weather this machine has been banned or not.
|
||||
static Result uploadMachineId(const char* baseUrl);
|
||||
|
||||
static std::string getMachineId();
|
||||
|
||||
private:
|
||||
struct MacAddress {
|
||||
static const int kBytesInMacAddress = 6;
|
||||
unsigned char address[kBytesInMacAddress];
|
||||
std::string asString() const;
|
||||
};
|
||||
|
||||
struct MachineId {
|
||||
std::vector<MacAddress> macAddresses;
|
||||
};
|
||||
|
||||
static bool fillMachineId(MachineId* out);
|
||||
static bool buildMacAddressContent(bool needsLeadingAmp, const MachineId& id, std::stringstream& stream);
|
||||
static void buildContent(const MachineId& id, std::stringstream& stream);
|
||||
};
|
||||
|
||||
}
|
||||
+387
@@ -0,0 +1,387 @@
|
||||
/* Copyright 2003-2007 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Util/NormalId.h"
|
||||
#include "Util/G3DCore.h"
|
||||
#include "Util/PV.h"
|
||||
#include "rbx/Debug.h"
|
||||
#include "G3D/Array.h"
|
||||
#include "RbxG3D/RbxRay.h"
|
||||
#include <limits>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
inline int fastFloorInt(float value)
|
||||
{
|
||||
return value < 0 ? static_cast<int>(value - 0.999f) : static_cast<int>(value);
|
||||
}
|
||||
|
||||
inline int fastCeilInt(float value)
|
||||
{
|
||||
return value < 0 ? static_cast<int>(value) : static_cast<int>(value + 0.999f);
|
||||
}
|
||||
|
||||
inline Vector3int16 fastFloorInt16(const Vector3& v)
|
||||
{
|
||||
return Vector3int16(fastFloorInt(v.x), fastFloorInt(v.y), fastFloorInt(v.z));
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
AXIS_X = 0,
|
||||
AXIS_Y = 1,
|
||||
AXIS_Z = 2
|
||||
} AxisIndex;
|
||||
|
||||
namespace Math
|
||||
{
|
||||
inline double pi() {return 3.14159265358979323846;}
|
||||
inline double piHalf() {return pi() * 0.5f;}
|
||||
inline double twoPi() {return pi() * 2.0f;}
|
||||
inline float pif() {return static_cast<float>(pi());}
|
||||
inline float piHalff() {return static_cast<float>(piHalf());}
|
||||
inline float twoPif() {return static_cast<float>(twoPi());}
|
||||
inline const float& inf() {
|
||||
static const float i = std::numeric_limits<float>::infinity();
|
||||
return i;
|
||||
}
|
||||
|
||||
// Returns the 0-based most-significant bit (-1 if v is 0)
|
||||
inline size_t computeMSB(size_t v)
|
||||
{
|
||||
size_t msb = -1;
|
||||
while (v>0)
|
||||
{
|
||||
v >>= 1;
|
||||
++msb;
|
||||
}
|
||||
return msb;
|
||||
}
|
||||
|
||||
inline int iRound(float value) {
|
||||
return G3D::iRound(value);
|
||||
}
|
||||
inline int iFloor(float value) {
|
||||
return G3D::iRound(::floor(value));
|
||||
}
|
||||
inline float polarity(float value) {
|
||||
return (value >= 0.0f) ? 1.0f : -1.0f;
|
||||
}
|
||||
inline float sign(float value) {
|
||||
return (value > 0.0f)
|
||||
? 1.0f
|
||||
: (value < 0.0f ? -1.0f : 0.0f);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// Denormalized detection
|
||||
|
||||
bool isDenormal(float f);
|
||||
bool isNan(float f);
|
||||
bool isNan(const Vector3& v);
|
||||
bool isNanInf(float f);
|
||||
bool isNanInfDenorm(float f);
|
||||
bool isNanInfVector3(const Vector3& v);
|
||||
bool isNanInfDenormVector3(const Vector3& v);
|
||||
bool isNanInfDenormMatrix3(const Matrix3& m);
|
||||
bool hasNanOrInf(const CoordinateFrame& c);
|
||||
bool hasNanOrInf(const Matrix3& m);
|
||||
|
||||
// Sets denormalized values to 0.0
|
||||
bool fixDenorm(float& f);
|
||||
bool fixDenorm(Vector3& v);
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// fuzzyEq stuff
|
||||
inline float epsilonf() { return 1.0e-6f; }
|
||||
inline bool fuzzyEq(float a, float b, float epsilon) {
|
||||
float aa = fabsf(a) + 1.0f;
|
||||
return (a == b) || (fabsf(a - b) <= (aa * epsilon));
|
||||
}
|
||||
|
||||
inline bool fuzzyEq(double a, double b, double epsilon) {
|
||||
double aa = fabs(a) + 1.0f;
|
||||
return (a == b) || (fabs(a - b) <= (aa * epsilon));
|
||||
}
|
||||
|
||||
bool fuzzyEq(const Vector3& v0, const Vector3& v1, float epsilon = 1.0e-5f); // Note G3D::eps == 1e-6;
|
||||
bool fuzzyEq(const Matrix3& m0, const Matrix3& m1, float epsilon = 1.0e-5f); // Note G3D::eps == 1e-6;
|
||||
bool fuzzyEq(const Matrix4& m0, const Matrix4& m1, float epsilon = 1.0e-5f); // Note G3D::eps == 1e-6;
|
||||
bool fuzzyEq(const CoordinateFrame& c0, const CoordinateFrame& c1, float epsT = 1.0e-5f, float epsRad = 1.0e-5f);
|
||||
bool fuzzyAxisAligned(const Matrix3& m0, const Matrix3& m1, float radTolerance);
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// odd / even stuff
|
||||
inline bool isEven(int value) {
|
||||
return ((value % 2) == 0);
|
||||
}
|
||||
|
||||
inline bool isOdd(int value) {
|
||||
return ((value % 2) != 0);
|
||||
}
|
||||
|
||||
inline int nextEven(int value) {
|
||||
return (value + 1 + ((value + 1) % 2));
|
||||
}
|
||||
|
||||
inline int nextOdd(int value) {
|
||||
return (value + 1 + (value % 2));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// Vector2 stuff
|
||||
inline Vector2 expandVector2(const Vector2& v, int expand) {
|
||||
Vector2 answer(v);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
answer[i] += expand * RBX::Math::sign(v[i]);
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
|
||||
inline Vector2 roundVector2(const Vector2& v) {
|
||||
return Vector2(iRound(v.x), iRound(v.y));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// Vector3 stuff
|
||||
|
||||
size_t hash(const Vector3& v);
|
||||
bool isIntegerVector3(const Vector3& v);
|
||||
Vector3 iRoundVector3(const Vector3& point);
|
||||
float angle(const Vector3& v0, const Vector3& v1);
|
||||
float smallAngle(const Vector3& v0, const Vector3& v1);
|
||||
float elevationAngle(const Vector3& look);
|
||||
Vector3 vector3Abs(const Vector3& v);
|
||||
float volume(const Vector3& v);
|
||||
float maxAxisLength(const Vector3& v);
|
||||
Vector3 sortVector3(const Vector3& v);
|
||||
Vector3 safeDirection(const Vector3& v); // handles case where V == vector3::zero();
|
||||
Velocity calcTrajectory(const Vector3& launch, const Vector3& target, float speed);
|
||||
Vector3 toGrid(const Vector3& v, const Vector3& grid);
|
||||
Vector3 toGrid(const Vector3& v, float grid);
|
||||
bool lessThan(const Vector3& min, const Vector3& max);
|
||||
inline float longestVector3Component(const Vector3& v) {
|
||||
return std::max(fabs(v.x), std::max(fabs(v.y), fabs(v.z)));
|
||||
}
|
||||
inline float planarSize(const Vector3& v) {
|
||||
return (v.x < v.y)
|
||||
? ((v.x < v.z) ? v.y * v.z : v.y * v.x)
|
||||
: ((v.y < v.z) ? v.x * v.z : v.x * v.y);
|
||||
}
|
||||
inline float taxiCabMagnitude(const Vector3& v) {
|
||||
return fabs(v.x) + fabs(v.y) + fabs(v.z);
|
||||
}
|
||||
float sumDeltaAxis(const Matrix3& r0, const Matrix3& r1);
|
||||
|
||||
inline const Plane& yPlane() {static Plane p(Vector3(0.0, 1.0, 0.0), Vector3::zero()); return p;}
|
||||
Vector3 closestPointOnRay(const RBX::RbxRay& pointOnRay, const RBX::RbxRay& otherRay);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// Manipulate/rotate Matrix3 and CoordinateFrame
|
||||
|
||||
Vector3 rotateAboutYGlobal(const Vector3& v, float radians);
|
||||
Vector3 toSmallAngles(const Matrix3& matrix);
|
||||
Matrix3 snapToAxes(const Matrix3& matrix);
|
||||
bool isOrthonormal(const Matrix3& m);
|
||||
bool orthonormalizeIfNecessary(Matrix3& m); // true if an orthonormalize was necessary
|
||||
|
||||
Vector3 toFocusSpace(const Vector3& goal, const CoordinateFrame& focus);
|
||||
Vector3 fromFocusSpace(const Vector3& goal, const CoordinateFrame& focus);
|
||||
|
||||
Vector3 toDiagonal(const Matrix3& m);
|
||||
|
||||
inline Matrix3 fromDiagonal(const Vector3& v) {
|
||||
return Matrix3( v[0], 0.0f, 0.0f,
|
||||
0.0f, v[1], 0.0f,
|
||||
0.0f, 0.0f, v[2] );
|
||||
}
|
||||
|
||||
// Return the skew symmetric matrix for the the given vector.
|
||||
// a.cross( b ) = A_* b where A_is the skew symmetric matrix for a.
|
||||
//
|
||||
inline Matrix3 toSkewSymmetric(const Vector3& v) {
|
||||
return Matrix3( 0.0f, -v.z, v.y,
|
||||
v.z, 0.0f, -v.x,
|
||||
-v.y, v.x, 0.0f );
|
||||
}
|
||||
|
||||
Matrix3 fromVectorToVectorRotation( const Vector3& fromVec, const Vector3& toVec );
|
||||
Matrix3 fromRotationAxisAndAngle( const Vector3& axis, const float& angleRads );
|
||||
Matrix3 fromShortestPlanarRotation( const Vector3& targetX, const Vector3& targetY );
|
||||
Matrix3 fromDirectionCosines( const Vector3& fromX, const Vector3& fromY, const Vector3& fromZ,
|
||||
const Vector3& toX, const Vector3& toY, const Vector3& toZ );
|
||||
|
||||
inline Vector3 getColumn(const Matrix3& m, int iCol) {
|
||||
RBXASSERT_VERY_FAST((0 <= iCol) && (iCol < 3));
|
||||
return Vector3(m[0][iCol], m[1][iCol], m[2][iCol]);
|
||||
}
|
||||
|
||||
void mulMatrixDiagVector(const Matrix3& _mat, const Vector3& _vec, Matrix3& _answer);
|
||||
void mulMatrixMatrixTranspose(const Matrix3& _m0, const Matrix3& _m1, Matrix3& _answer);
|
||||
void mulMatrixTransposeMatrix(const Matrix3& _m0, const Matrix3& _m1, Matrix3& _answer);
|
||||
|
||||
// Byte Angles
|
||||
unsigned char rotationToByte(float angle);
|
||||
float rotationFromByte(unsigned char byteAngle);
|
||||
|
||||
// Axis Aligned Matrix / OrientId
|
||||
static const int maxOrientationId = 36;
|
||||
static const int minOrientationId = 0;
|
||||
bool isAxisAligned(const Matrix3& matrix);
|
||||
int getOrientId(const Matrix3& matrix);
|
||||
void idToMatrix3(int orientId, Matrix3& matrix);
|
||||
|
||||
const Matrix3& matrixRotateX();
|
||||
//static const Matrix3& matrixRotateNegativeX();
|
||||
const Matrix3& matrixRotateY();
|
||||
const Matrix3& matrixRotateNegativeY();
|
||||
const Matrix3& matrixTiltZ();
|
||||
const Matrix3& matrixTiltNegativeZ();
|
||||
const Matrix3 matrixTiltQuadrant(int quadrant);
|
||||
void rotateMatrixAboutX90(Matrix3& matrix, int times = 1);
|
||||
void rotateMatrixAboutY90(Matrix3& matrix, int times = 1);
|
||||
void rotateMatrixAboutZ90(Matrix3& matrix);
|
||||
Matrix3 rotateAboutZ(const Matrix3& matrix, float radians);
|
||||
Matrix3 getWellFormedRotForZVector(const Vector3& vec);
|
||||
Matrix3 momentToObjectSpace(const Matrix3& iWorld, const Matrix3& bodyRotation);
|
||||
Matrix3 momentToWorldSpace(const Matrix3& iBody, const Matrix3& bodyRotation);
|
||||
Matrix3 getIWorldAtPoint(const Vector3& cofmPos,
|
||||
const Vector3& worldPos,
|
||||
const Matrix3& iWorldAtCofm,
|
||||
float mass);
|
||||
Matrix3 getIBodyAtPoint(const Vector3& pos,
|
||||
const Matrix3& iBody,
|
||||
float mass);
|
||||
|
||||
// CoordinateFrame
|
||||
void rotateAboutYLocal(CoordinateFrame& c, float radians);
|
||||
void rotateAboutYGlobal(CoordinateFrame& c, float radians);
|
||||
CoordinateFrame snapToGrid(const CoordinateFrame& snap, float grid);
|
||||
CoordinateFrame snapToGrid(const CoordinateFrame& snap, const Vector3& grid);
|
||||
// http://www.vlfeat.org/api/mathop_8h-source.html#l00227
|
||||
inline float atan2Fast(float y, float x) {
|
||||
float angle, r;
|
||||
float const c3 = 0.1821f;
|
||||
float const c1 = 0.9675f;
|
||||
float abs_y = fabsf(y) + 1.19209290e-07f;
|
||||
if (x >= 0) {
|
||||
r = (x - abs_y) / (x + abs_y) ;
|
||||
angle = Math::pif() / 4.0f;
|
||||
} else {
|
||||
r = (x + abs_y) / (abs_y - x) ;
|
||||
angle = 3.0f * Math::pif() / 4.0f ;
|
||||
}
|
||||
angle += (c3*r*r - c1) * r ;
|
||||
return (y < 0) ? - angle : angle ;
|
||||
}
|
||||
|
||||
inline float zAxisAngle(const Matrix3& matrix) {
|
||||
Vector3 look = matrix.column(0);
|
||||
float angle = (float) atan2(look.y, look.x);
|
||||
// float angle = Math::atan2Fast(look.y, look.x);
|
||||
return angle;
|
||||
}
|
||||
void pan(const Vector3& focusPosition, CoordinateFrame& camera, float radians);
|
||||
|
||||
// std::vector
|
||||
void lerpArray(
|
||||
const G3D::Array<float>& before,
|
||||
const G3D::Array<float>& after,
|
||||
G3D::Array<float>& answer,
|
||||
float alpha);
|
||||
|
||||
// Pitch, Yaw stuff - replaces Euler Angles
|
||||
int radiansToQuadrant(float radians);
|
||||
int radiansToOctant(float radians);
|
||||
inline float radiansToDegrees(float radians) {return radians * (180.0f / Math::pif());}
|
||||
inline float degreesToRadians(float degrees) {return degrees * (Math::pif() / 180.0f);}
|
||||
|
||||
/**
|
||||
Returns the heading as an angle in radians, where
|
||||
north is 0 and west is PI/2
|
||||
North == -z
|
||||
|
||||
Elevation is angle above (+) or below(-) horizon
|
||||
*/
|
||||
inline float getHeading(const Vector3& look) { return atan2( -look.x, -look.z); }
|
||||
inline float getElevation(const Vector3& look) { return asin(look.y); }
|
||||
|
||||
void getHeadingElevation(const CoordinateFrame& c, float& heading, float& elevation);
|
||||
void setHeadingElevation(CoordinateFrame& c, float heading, float elevation);
|
||||
|
||||
CoordinateFrame getFocusSpace(const CoordinateFrame& focus);
|
||||
|
||||
int toYAxisQuadrant(const CoordinateFrame& c); // 0..3
|
||||
|
||||
Matrix3 alignAxesClosest(const Matrix3& align, const Matrix3& target);
|
||||
|
||||
// NormalId stuff
|
||||
NormalId getClosestObjectNormalId(const Vector3& worldV, const Matrix3& objectR);
|
||||
|
||||
inline Vector3 getWorldNormal(NormalId objId, const Matrix3& objectR) {
|
||||
// return (objId < 3) ? getColumn(objectR, objId) : -getColumn(objectR, objId - 3);
|
||||
int column = objId % 3;
|
||||
int polarity = ((objId / 3) * (-2)) + 1;
|
||||
return polarity * getColumn(objectR, column);
|
||||
}
|
||||
|
||||
inline Vector3 getWorldNormal(NormalId objId, const CoordinateFrame& objectC) {
|
||||
return getWorldNormal(objId, objectC.rotation);
|
||||
}
|
||||
|
||||
// wraps from -pi to pi
|
||||
|
||||
float deltaRotationClose(float aRot, float bRot); // computes aRot - bRot, assuming angles are close. Undoes wrapping
|
||||
float averageRotationClose(float aRot, float bRot); // computes average aRot, bRot, assuming angles are close. Undoes wrapping
|
||||
|
||||
double advanceWoundRotation(double currentRotationWound, double newRotationNotWound); // properly increments a wound up rotation - detects flips
|
||||
float clampRotationClose(float rot, float limitLo, float limitHi);
|
||||
// -3pi to -pi: -1
|
||||
// -pi to pi: 0
|
||||
// pi to 3pi: 1
|
||||
inline double windingPart(double rad) {
|
||||
return ::floor((rad + pi()) / twoPi()) ;
|
||||
}
|
||||
|
||||
inline float radWrap(double rad) { // extra part
|
||||
if ((rad >= -pi()) && (rad < pi())) {
|
||||
return static_cast<float>(rad);
|
||||
}
|
||||
double answer = rad - (twoPi() * windingPart(rad));
|
||||
RBXASSERT((answer >= -pi()) && (answer <= pi()));
|
||||
return static_cast<float>(answer);
|
||||
}
|
||||
|
||||
// Matrix operations
|
||||
const Matrix3& getAxisRotationMatrix(int face);
|
||||
|
||||
// Vector to Object Space
|
||||
// == mat.transpose() * vec
|
||||
inline Vector3 vectorToObjectSpace(const Vector3& vec, const Matrix3& mat);
|
||||
|
||||
// Ray, Line
|
||||
bool clipRay(Vector3& origin, Vector3& ray, Vector3 box[], Vector3& endPoint);
|
||||
bool intersectLinePlane(const Line& line, const Plane& plane, Vector3& hit);
|
||||
bool intersectRayPlane(const RbxRay& ray, const Plane& plane, Vector3& hit);
|
||||
bool intersectRayConvexPolygon(const RBX::RbxRay& ray, const std::vector<Vector3>& poly, Vector3& hit, bool oneSided);
|
||||
bool lineSegmentDistanceIfCrossing(const Vector3& line1Pt1, const Vector3& line1Pt2, const Vector3& line2Pt1, const Vector3& line2Pt2, float& distance, float adjustEdgeTol = 0.0f);
|
||||
std::vector<Vector3> spatialPolygonIntersection(const std::vector<Vector3>& polyA, const std::vector<Vector3>& polyB);
|
||||
std::vector<Vector2> planarPolygonIntersection(const std::vector<Vector2>& poly1, const std::vector<Vector2>& poly2);
|
||||
|
||||
|
||||
// Misc.
|
||||
float computeLaunchAngle(float v, float x, float y, float g);
|
||||
Vector2 polygonStartingPoint(int numSides, float maxWidth);
|
||||
bool evenWholeNumber( const float& rawInput );
|
||||
bool evenWholeNumberFuzzy( const float& rawInput );
|
||||
}
|
||||
} // namespace
|
||||
|
||||
#include "Math.inl"
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
namespace RBX {
|
||||
namespace Math{
|
||||
|
||||
// = mat.transpose() * vec
|
||||
Vector3 vectorToObjectSpace(const Vector3& _vec, const Matrix3& _mat)
|
||||
{
|
||||
const float* vec = &_vec[0];
|
||||
const float* mat = &_mat[0][0];
|
||||
|
||||
return Vector3 ( mat[0]*vec[0] + mat[3]*vec[1] + mat[6]*vec[2],
|
||||
mat[1]*vec[0] + mat[4]*vec[1] + mat[7]*vec[2],
|
||||
mat[2]*vec[0] + mat[5]*vec[1] + mat[8]*vec[2] );
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
#include "rbx/memory.h"
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include "standardout.h"
|
||||
#include "FastLog.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
// Utility functions for determining used/free/total memory.
|
||||
namespace MemoryStats {
|
||||
|
||||
enum MemoryLevel
|
||||
{
|
||||
MEMORYLEVEL_ALL_CRITICAL_LOW,
|
||||
MEMORYLEVEL_ONLY_PHYSICAL_CRITICAL_LOW,
|
||||
MEMORYLEVEL_ALL_LOW,
|
||||
MEMORYLEVEL_ONLY_PHYSICAL_LOW,
|
||||
MEMORYLEVEL_LIMITED,
|
||||
MEMORYLEVEL_OK
|
||||
};
|
||||
|
||||
typedef boost::uint64_t memsize_t;
|
||||
|
||||
memsize_t usedMemoryBytes();
|
||||
memsize_t freeMemoryBytes();
|
||||
memsize_t totalMemoryBytes();
|
||||
size_t slowGetMemoryPoolAllocation();
|
||||
size_t slowGetMemoryPoolAvailability();
|
||||
void releaseAllPoolMemory();
|
||||
MemoryLevel slowCheckMemoryLevel(memsize_t extraMemoryUsed);
|
||||
|
||||
} // namespace MemoryStats
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,22 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8Tree/Service.h"
|
||||
#include "Util/RunStateOwner.h"
|
||||
#include "Reflection/Event.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class PartInstance;
|
||||
|
||||
class MeshId : public ContentId
|
||||
{
|
||||
public:
|
||||
MeshId(const ContentId& id):ContentId(id) {}
|
||||
MeshId(const char* id):ContentId(id) {}
|
||||
MeshId(const std::string& id):ContentId(id) {}
|
||||
MeshId() {}
|
||||
};
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,123 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
#pragma once
|
||||
|
||||
#include <boost/circular_buffer.hpp>
|
||||
#include "G3DCore.h"
|
||||
#include "rbx/rbxTime.h"
|
||||
#include "boost/thread/mutex.hpp"
|
||||
#include "Math.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
#define MH_NUM_MAX_NODES 80
|
||||
#define MH_MIN_PRECISION 0.01f
|
||||
#define MH_TOLERABLE_COMPRESSION_ERROR 1.f
|
||||
|
||||
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed char int8_t;
|
||||
|
||||
class MovementHistory
|
||||
{
|
||||
|
||||
public:
|
||||
struct DeltaCompressedTranslation
|
||||
{
|
||||
// in terms of MIN_PRECISION
|
||||
uint8_t precisionLevel;
|
||||
int8_t dX;
|
||||
int8_t dY;
|
||||
int8_t dZ;
|
||||
};
|
||||
|
||||
struct MovementNode
|
||||
{
|
||||
DeltaCompressedTranslation translation;
|
||||
uint8_t delta2Ms;
|
||||
MovementNode()
|
||||
{
|
||||
setZero();
|
||||
}
|
||||
MovementNode(const CoordinateFrame& newCFrame, const CoordinateFrame& oldCFrame, float deltaSecs)
|
||||
{
|
||||
Vector3 delta = newCFrame.translation - oldCFrame.translation;
|
||||
compress(delta, *this);
|
||||
if (deltaSecs < 0.f)
|
||||
{
|
||||
delta2Ms = 0;
|
||||
}
|
||||
else if (deltaSecs > 0.510f)
|
||||
{
|
||||
delta2Ms = 255; // overflow, use 255 to indicate the long gap
|
||||
}
|
||||
else
|
||||
{
|
||||
delta2Ms = (uint8_t)(deltaSecs*500.f);
|
||||
}
|
||||
}
|
||||
bool isZero() const
|
||||
{
|
||||
return translation.dX == 0 && translation.dY == 0 && translation.dZ == 0;
|
||||
}
|
||||
void setZero()
|
||||
{
|
||||
translation.precisionLevel = 0;
|
||||
translation.dX = 0;
|
||||
translation.dY = 0;
|
||||
translation.dZ = 0;
|
||||
delta2Ms = 0;
|
||||
}
|
||||
// rotation will be estimated by interpolation
|
||||
};
|
||||
|
||||
static const MovementHistory& getDefaultHistory()
|
||||
{
|
||||
static CoordinateFrame zeroCFrame;
|
||||
static Velocity zeroVelocity;
|
||||
static MovementHistory defaultMovementHistory(zeroCFrame, zeroVelocity, Time());
|
||||
return defaultMovementHistory;
|
||||
}
|
||||
|
||||
MovementHistory(const CoordinateFrame& cFrame, const Velocity& velocity, const Time& timeStamp);
|
||||
~MovementHistory()
|
||||
{}
|
||||
|
||||
void clearNodeHistory();
|
||||
void addNode(const CoordinateFrame& cFrame, const Velocity& velocity, const Time& timeStamp);
|
||||
|
||||
size_t getNumNodes() const {return size;}
|
||||
bool hasHistory(float accumulatedError) const;
|
||||
void getMovementNodeList(const Time& lastCutOffTime, const Time& currentCutOffTime, std::deque<MovementNode>& result, bool crossPacketCompression, const CoordinateFrame& lastSentCFrame, CoordinateFrame& outCalculatedBaselineCFrame, Vector3& outCalculatedLinearVelocity) const;
|
||||
const CoordinateFrame& getBaselineCFrame() const {return baselineCFrame;}
|
||||
const Velocity& getBaselineVelocity() const {return baselineVelocity;}
|
||||
|
||||
static float decompress(int8_t v, uint8_t precisionLevel);
|
||||
static void decompress(MovementNode node, Vector3& outTranslation);
|
||||
|
||||
const Time& getLastUpdateTime() const {return lastUpdateTime;}
|
||||
float getTimeSpan() const {return timeSpanSec;}
|
||||
|
||||
static float getSecFrom2Ms(uint8_t delta2MS)
|
||||
{
|
||||
return ((float)delta2MS)/500.f;
|
||||
}
|
||||
|
||||
private:
|
||||
CoordinateFrame baselineCFrame;
|
||||
Velocity baselineVelocity;
|
||||
Time lastUpdateTime;
|
||||
float timeSpanSec;
|
||||
int checksum;
|
||||
|
||||
MovementNode movementNodes[MH_NUM_MAX_NODES];
|
||||
size_t startIndex;
|
||||
size_t size;
|
||||
void popFront();
|
||||
void pushBack(MovementNode node);
|
||||
MovementNode concatNode(size_t lastIndex, size_t numNodesToConcat) const;
|
||||
|
||||
static int8_t compress(float v, uint8_t precisionLevel);
|
||||
static void compress(Vector3 translation, MovementNode& outMovementNode);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
|
||||
|
||||
#ifndef _E34E3E6DF0724eb493E138F10DF08D03
|
||||
#define _E34E3E6DF0724eb493E138F10DF08D03
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "boost/utility.hpp"
|
||||
|
||||
#include "rbx/Debug.h"
|
||||
#include "rbx/boost.hpp"
|
||||
#include "rbx/atomic.h"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include "rbx/threadsafe.h"
|
||||
|
||||
#include "security/ApiSecurity.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Name : public boost::noncopyable
|
||||
{
|
||||
static RBX::mutex& mutex();
|
||||
class NameMap;
|
||||
static NameMap& map();
|
||||
|
||||
template<const char* const& sName>
|
||||
static const Name& doDeclare()
|
||||
{
|
||||
static const Name& n = declare(sName);
|
||||
return n;
|
||||
}
|
||||
template<const char* const& sName>
|
||||
static void callDoDeclare()
|
||||
{
|
||||
doDeclare<sName>();
|
||||
}
|
||||
|
||||
// sortIndex is atomic to avoid any chance of stale
|
||||
// data when calling setOrderIndex
|
||||
rbx::atomic<int> sortIndex;
|
||||
|
||||
public:
|
||||
std::string const str; // the string that is the text name
|
||||
|
||||
static size_t size();
|
||||
static size_t approximateMemoryUsage();
|
||||
|
||||
// Declaration and Query
|
||||
static const Name& getNullName();
|
||||
|
||||
// Fast and thread-safe
|
||||
NOINLINE static const Name& declare(const char* const& sName);
|
||||
FORCEINLINE static const Name& declare(const std::string& sName)
|
||||
{
|
||||
return declare(sName.c_str());
|
||||
}
|
||||
template<const char* const& sName>
|
||||
static const Name& declare()
|
||||
{
|
||||
if(sName == NULL)
|
||||
return getNullName();
|
||||
|
||||
static boost::once_flag flag = BOOST_ONCE_INIT;
|
||||
boost::call_once(&callDoDeclare<sName>, flag);
|
||||
return doDeclare<sName>();
|
||||
}
|
||||
|
||||
NOINLINE static const Name& lookup(const char* const& sName);
|
||||
FORCEINLINE static const Name& lookup(const std::string& sName)
|
||||
{
|
||||
return lookup(sName.c_str());
|
||||
}
|
||||
|
||||
bool empty() const { return getNullName()==*this; }
|
||||
static bool empty(const Name* name) { return name==0 || *name==getNullName(); }
|
||||
|
||||
// Convert to string
|
||||
const std::string& toString() const { return str; }
|
||||
const char* c_str() const { return str.c_str(); }
|
||||
|
||||
// Comparison
|
||||
#if 1
|
||||
// Optimization - avoids string comparisons
|
||||
static inline int compare(const Name& a, const Name& b) {
|
||||
return a.sortIndex - b.sortIndex;
|
||||
}
|
||||
inline int compare(const Name& other) const {
|
||||
return sortIndex - other.sortIndex;
|
||||
}
|
||||
inline bool operator < (const Name& other) const {
|
||||
return sortIndex < other.sortIndex;
|
||||
}
|
||||
inline bool operator > (const Name& other) const {
|
||||
return sortIndex > other.sortIndex;
|
||||
}
|
||||
#else
|
||||
static inline int compare(const Name& a, const Name& b) {
|
||||
return a.str.compare(b.str);
|
||||
}
|
||||
inline int compare(const Name& other) const {
|
||||
return str.compare(other.str);
|
||||
}
|
||||
inline bool operator < (const Name& other) const {
|
||||
return str < other.str;
|
||||
}
|
||||
inline bool operator > (const Name& other) const {
|
||||
return str > other.str;
|
||||
}
|
||||
#endif
|
||||
inline bool operator == (const Name& other) const {
|
||||
return this==&other;
|
||||
}
|
||||
inline bool operator != (const Name& other) const {
|
||||
return this!=&other;
|
||||
}
|
||||
inline bool operator == (const std::string& sName) const {
|
||||
return this->str == sName;
|
||||
}
|
||||
inline bool operator != (const std::string& sName) const {
|
||||
return this->str != sName;
|
||||
}
|
||||
inline bool operator == (const char* const &sName) const {
|
||||
return this->str == sName;
|
||||
}
|
||||
inline bool operator != (const char* const &sName) const {
|
||||
return this->str != sName;
|
||||
}
|
||||
|
||||
private:
|
||||
explicit Name(const char* const &sName);
|
||||
void setOrderIndex();
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const RBX::Name& name);
|
||||
|
||||
// An object that has a Name
|
||||
class RBXInterface INamed {
|
||||
public:
|
||||
virtual const Name& getName() const = 0;
|
||||
};
|
||||
|
||||
// A template implementation of INamed
|
||||
template <class BaseClass, const char* const& sName>
|
||||
class Named : public BaseClass {
|
||||
public:
|
||||
|
||||
// Constructors with different numbers of arguments
|
||||
Named() : BaseClass() {}
|
||||
template<typename Arg0>
|
||||
Named(Arg0 arg0) : BaseClass(arg0) {}
|
||||
template<typename Arg0, typename Arg1>
|
||||
Named(Arg0 arg0, Arg1 arg1) : BaseClass(arg0, arg1) {}
|
||||
template<typename Arg0, typename Arg1, typename Arg2>
|
||||
Named(Arg0 arg0, Arg1 arg1, Arg2 arg2) : BaseClass(arg0, arg1, arg2) {}
|
||||
template<typename Arg0, typename Arg1, typename Arg2, typename Arg3>
|
||||
Named(Arg0 arg0, Arg1 arg1, Arg2 arg2, Arg3 arg3) : BaseClass(arg0, arg1, arg2, arg3) {}
|
||||
|
||||
static const Name& name() {
|
||||
return Name::declare<sName>();
|
||||
}
|
||||
virtual const Name& getName() const {
|
||||
return name();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class ScopedNamedMutex
|
||||
{
|
||||
HANDLE hMutex;
|
||||
|
||||
public:
|
||||
ScopedNamedMutex(const char* name);
|
||||
~ScopedNamedMutex();
|
||||
};
|
||||
} // namespace RBX
|
||||
#endif // #ifdef _WIN32
|
||||
@@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class NavKeys {
|
||||
public:
|
||||
bool forward_arrow;
|
||||
bool backward_arrow;
|
||||
bool left_arrow;
|
||||
bool right_arrow;
|
||||
bool forward_asdw;
|
||||
bool backward_asdw;
|
||||
bool left_asdw;
|
||||
bool right_asdw;
|
||||
bool strafe_left_q;
|
||||
bool strafe_right_e;
|
||||
bool space;
|
||||
bool backspace;
|
||||
bool shift;
|
||||
|
||||
NavKeys() : forward_arrow(false),
|
||||
backward_arrow(false),
|
||||
left_arrow(false),
|
||||
right_arrow(false),
|
||||
forward_asdw(false),
|
||||
backward_asdw(false),
|
||||
left_asdw(false),
|
||||
right_asdw(false),
|
||||
strafe_left_q(false),
|
||||
strafe_right_e(false),
|
||||
space(false),
|
||||
backspace(false),
|
||||
shift(false)
|
||||
{}
|
||||
|
||||
bool forward() const {return (forward_arrow || forward_asdw);}
|
||||
|
||||
bool backward() const {return (backward_arrow || backward_asdw);}
|
||||
|
||||
bool left() const {return (left_arrow || left_asdw);}
|
||||
|
||||
bool right() const {return (right_arrow || right_asdw);}
|
||||
|
||||
bool up() const {return strafe_left_q;}
|
||||
|
||||
bool down() const {return strafe_right_e;}
|
||||
|
||||
bool backspaceDown() const {return backspace;}
|
||||
|
||||
bool arrowKeyDown() const {return (forward_arrow || backward_arrow || left_arrow || right_arrow);}
|
||||
|
||||
bool asdwKeyDown() const {return (forward_asdw || backward_asdw || left_asdw || right_asdw);}
|
||||
|
||||
bool qeKeyDown() const {return (strafe_left_q || strafe_right_e);}
|
||||
|
||||
bool navKeyDown() const {return (arrowKeyDown() || asdwKeyDown() || qeKeyDown() || space) || backspaceDown();}
|
||||
|
||||
int leftRightASDW() const {return left_asdw ? 1 : (right_asdw ? -1 : 0);}
|
||||
|
||||
int strafeQE() const {return strafe_left_q ? 1 : (strafe_right_e ? -1 : 0);}
|
||||
|
||||
int leftRightArrow() const {
|
||||
return left_arrow ? 1 : (right_arrow ? -1 : 0);
|
||||
}
|
||||
|
||||
int forwardBackwardArrow() const {
|
||||
return forward_arrow ? 1 : (backward_arrow ? -1 : 0);
|
||||
}
|
||||
|
||||
int forwardBackwardASDW() const {
|
||||
return forward_asdw ? 1 : (backward_asdw ? -1 : 0);
|
||||
}
|
||||
|
||||
int strafeLeftRightQE() const {
|
||||
return strafe_left_q ? 1 : (strafe_right_e ? -1 : 0);
|
||||
}
|
||||
|
||||
bool shiftKeyDown() const
|
||||
{
|
||||
return shift;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,69 @@
|
||||
/* Copyright 2003-2006 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
enum NormalIdMask
|
||||
{
|
||||
NORM_NONE_MASK = 0x00,
|
||||
NORM_X_MASK = 0x01,
|
||||
NORM_Y_MASK = 0x02,
|
||||
NORM_Z_MASK = 0x04,
|
||||
NORM_X_NEG_MASK = 0x08,
|
||||
NORM_Y_NEG_MASK = 0x10,
|
||||
NORM_Z_NEG_MASK = 0x20,
|
||||
NORM_ALL_MASK = 0x3f
|
||||
};
|
||||
enum NormalId { NORM_X = 0,
|
||||
NORM_Y,
|
||||
NORM_Z,
|
||||
NORM_X_NEG,
|
||||
NORM_Y_NEG,
|
||||
NORM_Z_NEG,
|
||||
NORM_UNDEFINED};
|
||||
|
||||
|
||||
bool validNormalId(NormalId normalId);
|
||||
|
||||
NormalIdMask normalIdToMask(NormalId normal);
|
||||
|
||||
NormalId normalIdOpposite(NormalId normalId);
|
||||
NormalId normalIdToU(NormalId normalId);
|
||||
NormalId normalIdToV(NormalId normalId);
|
||||
|
||||
const Vector3& normalIdToVector3(NormalId normalId); // Vector pointing along the normal direction
|
||||
const Matrix3& normalIdToMatrix3(NormalId normalId); // Z axis is away from face
|
||||
|
||||
NormalId Vector3ToNormalId(const Vector3& v);
|
||||
NormalId Matrix3ToNormalId(const Matrix3& m);
|
||||
NormalId intToNormalId(int i);
|
||||
|
||||
Vector3 uvwToObject(const Vector3& uvwPt, NormalId faceId);
|
||||
Vector3 objectToUvw(const Vector3& objectPt, NormalId faceId);
|
||||
|
||||
template<NormalId faceId>
|
||||
Vector3 uvwToObject(const Vector3& v);
|
||||
|
||||
template<NormalId faceId>
|
||||
Vector3 objectToUvw(const Vector3& v);
|
||||
|
||||
|
||||
|
||||
// LEGACY - Deprecated
|
||||
// old stuff - need to inspect and see if it is really objectToUvw or uvwToObject
|
||||
Vector3 mapToUvw_Legacy(const Vector3& ptInObject, NormalId normalId);
|
||||
|
||||
template<NormalId normalId>
|
||||
Vector3 faceMap_Legacy(const Vector3& v) {
|
||||
return uvwToObject<normalId>(v);
|
||||
}
|
||||
|
||||
template<NormalId normalId>
|
||||
Vector3 faceMap_Legacy(float x, float y, float z) {
|
||||
return faceMap_Legacy<normalId>(Vector3(x, y, z));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,375 @@
|
||||
/* Copyright 2003-2007 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "rbx/Debug.h"
|
||||
#include "Util/Name.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "Security/ApiSecurity.h"
|
||||
#include "Security/FuzzyTokens.h"
|
||||
#include "V8DataModel/HackDefines.h"
|
||||
|
||||
#include "rbx/boost.hpp"
|
||||
#include "boost/weak_ptr.hpp"
|
||||
#include "boost/shared_ptr.hpp"
|
||||
#include "boost/scoped_ptr.hpp"
|
||||
#include "boost/enable_shared_from_this.hpp"
|
||||
|
||||
using boost::shared_ptr;
|
||||
using boost::scoped_ptr;
|
||||
using boost::weak_ptr;
|
||||
using boost::enable_shared_from_this;
|
||||
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Reflection
|
||||
{
|
||||
class DescribedBase;
|
||||
}
|
||||
|
||||
enum CreatorRole
|
||||
{
|
||||
ReplicationCreator,
|
||||
SerializationCreator,
|
||||
ScriptingCreator,
|
||||
EngineCreator
|
||||
};
|
||||
|
||||
|
||||
template<class T, class U> boost::shared_ptr<T> shared_polymorphic_downcast(const boost::shared_ptr<U>& r)
|
||||
{
|
||||
BOOST_ASSERT(dynamic_cast<T *>(r.get()) == r.get());
|
||||
return boost::static_pointer_cast<T>(r);
|
||||
}
|
||||
|
||||
template<class T, class U> boost::shared_ptr<T> shared_dynamic_cast(const boost::shared_ptr<U>& r)
|
||||
{
|
||||
return boost::dynamic_pointer_cast<T>(r);
|
||||
}
|
||||
|
||||
template<class T, class U> boost::shared_ptr<T> shared_static_cast(const boost::shared_ptr<U>& r)
|
||||
{
|
||||
return boost::static_pointer_cast<T>(r);
|
||||
}
|
||||
|
||||
// Use this to convert an object to its corresponding boost::shared_ptr
|
||||
template<class T> boost::shared_ptr<T> shared_from(T* r)
|
||||
{
|
||||
return r ? boost::static_pointer_cast<T>(r->shared_from_this()) : boost::shared_ptr<T>();
|
||||
}
|
||||
|
||||
template<class T> weak_ptr<T> weak_from(T* r)
|
||||
{
|
||||
return r ? boost::static_pointer_cast<T>(r->shared_from_this()) : boost::shared_ptr<T>();
|
||||
}
|
||||
|
||||
// Use this to downcast an object to a shared_ptr
|
||||
template<class T, class U> shared_ptr<T> shared_from_polymorphic_downcast(enable_shared_from_this<U>* r)
|
||||
{
|
||||
return r ? shared_polymorphic_downcast<T>(r->shared_from_this()) : shared_ptr<T>();
|
||||
}
|
||||
|
||||
template<class T, class U> shared_ptr<T> shared_from_static_cast(enable_shared_from_this<U>* r)
|
||||
{
|
||||
return r ? shared_static_cast<T>(r->shared_from_this()) : shared_ptr<T>();
|
||||
}
|
||||
|
||||
template<class T, class U> shared_ptr<T> shared_from_dynamic_cast(enable_shared_from_this<U>* r)
|
||||
{
|
||||
return r ? shared_dynamic_cast<T>(r->shared_from_this()) : shared_ptr<T>();
|
||||
}
|
||||
|
||||
template <class T> inline bool weak_equal(const weak_ptr<T>& lhs, const weak_ptr<T>& rhs)
|
||||
{
|
||||
return !(lhs < rhs) && !(rhs < lhs);
|
||||
}
|
||||
|
||||
class RBXInterface ICreator
|
||||
{
|
||||
public:
|
||||
virtual shared_ptr<Reflection::DescribedBase> create() const = 0;
|
||||
};
|
||||
|
||||
template<class Class>
|
||||
class RBXBaseClass Creatable
|
||||
{
|
||||
public:
|
||||
class Deleter
|
||||
{
|
||||
public:
|
||||
void operator()(Class* instance)
|
||||
{
|
||||
Class::predelete(instance);
|
||||
delete instance;
|
||||
}
|
||||
};
|
||||
|
||||
template<class T>
|
||||
static shared_ptr<T> create()
|
||||
{
|
||||
shared_ptr<T> obj = shared_ptr<T>(new T(), Deleter());
|
||||
shared_ptr<T> (*thisFunction)() = &create;
|
||||
checkRbxCaller<kCallCheckCallersCode, callCheckSetBasicFlag<HATE_RETURN_CHECK> >(reinterpret_cast<void*>(thisFunction));
|
||||
return obj;
|
||||
}
|
||||
template<class T, typename P1>
|
||||
static shared_ptr<T> create(P1 p1)
|
||||
{
|
||||
shared_ptr<T> obj = shared_ptr<T>(new T(p1), Deleter());
|
||||
shared_ptr<T> (*thisFunction)(P1) = &create;
|
||||
checkRbxCaller<kCallCheckCallersCode, callCheckSetBasicFlag<HATE_RETURN_CHECK> >(reinterpret_cast<void*>(thisFunction));
|
||||
return obj;
|
||||
}
|
||||
template<class T, typename P1, typename P2>
|
||||
static shared_ptr<T> create(P1 p1, P2 p2)
|
||||
{
|
||||
shared_ptr<T> obj = shared_ptr<T>(new T(p1, p2), Deleter());
|
||||
shared_ptr<T> (*thisFunction)(P1, P2) = &create;
|
||||
checkRbxCaller<kCallCheckCallersCode, callCheckSetBasicFlag<HATE_RETURN_CHECK> >(reinterpret_cast<void*>(thisFunction));
|
||||
return obj;
|
||||
}
|
||||
template<class T, typename P1, typename P2, typename P3>
|
||||
static shared_ptr<T> create(P1 p1, P2 p2, P3 p3)
|
||||
{
|
||||
shared_ptr<T> obj = shared_ptr<T>(new T(p1, p2, p3), Deleter());
|
||||
shared_ptr<T> (*thisFunction)(P1, P2, P3) = &create;
|
||||
checkRbxCaller<kCallCheckCallersCode, callCheckSetBasicFlag<HATE_RETURN_CHECK> >(reinterpret_cast<void*>(thisFunction));
|
||||
return obj;
|
||||
}
|
||||
template<class T, typename P1, typename P2, typename P3, typename P4>
|
||||
static shared_ptr<T> create(P1 p1, P2 p2, P3 p3, P4 p4)
|
||||
{
|
||||
shared_ptr<T> obj = shared_ptr<T>(new T(p1, p2, p3, p4), Deleter());
|
||||
shared_ptr<T> (*thisFunction)(P1, P2, P3, P4) = &create;
|
||||
checkRbxCaller<kCallCheckCallersCode, callCheckSetBasicFlag<HATE_RETURN_CHECK> >(reinterpret_cast<void*>(thisFunction));
|
||||
return obj;
|
||||
}
|
||||
template<class T, typename P1, typename P2, typename P3, typename P4, typename P5>
|
||||
static shared_ptr<T> create(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
|
||||
{
|
||||
shared_ptr<T> obj = shared_ptr<T>(new T(p1, p2, p3, p4, p5), Deleter());
|
||||
shared_ptr<T> (*thisFunction)(P1, P2, P3, P4, P5) = &create;
|
||||
checkRbxCaller<kCallCheckCallersCode, callCheckSetBasicFlag<HATE_RETURN_CHECK> >(reinterpret_cast<void*>(thisFunction));
|
||||
return obj;
|
||||
}
|
||||
template<class T, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
|
||||
static shared_ptr<T> create(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6)
|
||||
{
|
||||
shared_ptr<T> obj = shared_ptr<T>(new T(p1, p2, p3, p4, p5, p6), Deleter());
|
||||
shared_ptr<T> (*thisFunction)(P1, P2, P3, P4, P5, P6) = &create;
|
||||
checkRbxCaller<kCallCheckCallersCode, callCheckSetBasicFlag<HATE_RETURN_CHECK> >(reinterpret_cast<void*>(thisFunction));
|
||||
return obj;
|
||||
}
|
||||
template<class T, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
|
||||
static shared_ptr<T> create(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7)
|
||||
{
|
||||
shared_ptr<T> obj = shared_ptr<T>(new T(p1, p2, p3, p4, p5, p6, p7), Deleter());
|
||||
shared_ptr<T> (*thisFunction)(P1, P2, P3, P4, P5, P6, P7) = &create;
|
||||
checkRbxCaller<kCallCheckCallersCode, callCheckSetBasicFlag<HATE_RETURN_CHECK> >(reinterpret_cast<void*>(thisFunction));
|
||||
return obj;
|
||||
}
|
||||
|
||||
static std::map<const Name*, const ICreator*>& getCreators()
|
||||
{
|
||||
// TODO: replace with a faster lookup map, like the Loki AssocVector?
|
||||
static std::map<const Name*, const ICreator*> creators;
|
||||
return creators;
|
||||
}
|
||||
|
||||
static shared_ptr<Class> createByName(const Name& name, CreatorRole creatorRole)
|
||||
{
|
||||
std::map<const Name*, const ICreator*>::iterator iter = getCreators().find(&name);
|
||||
if (iter!=getCreators().end()){
|
||||
if(shared_ptr<Class> result = shared_polymorphic_downcast<Class>(iter->second->create())){
|
||||
switch(creatorRole)
|
||||
{
|
||||
case ReplicationCreator:
|
||||
return result;
|
||||
case SerializationCreator:
|
||||
if(result->getDescriptor().isSerializable())
|
||||
return result;
|
||||
break;
|
||||
case ScriptingCreator:
|
||||
if(result->getDescriptor().isScriptCreatable())
|
||||
return result;
|
||||
break;
|
||||
case EngineCreator:
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return shared_ptr<Class>();
|
||||
}
|
||||
|
||||
// Get object creator by className
|
||||
static const ICreator* getCreator(const Name& name)
|
||||
{
|
||||
std::map<const Name*, const ICreator*>::iterator iter = getCreators().find(&name);
|
||||
return (iter!=getCreators().end()) ? iter->second : NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
Creatable(); // this is a utility class
|
||||
};
|
||||
|
||||
template <class Class, class BaseClass, const char* const& sClassName, class FactoryClass>
|
||||
class FactoryProduct : public BaseClass {
|
||||
class Creator : public ICreator {
|
||||
private:
|
||||
static int isConstructedTrue() {return 666;}
|
||||
static int isConstructed; // debugging - if constructed, == 666
|
||||
|
||||
const RBX::Name& getClassNameUnconstructed() const {
|
||||
return RBX::Name::declare<sClassName>();
|
||||
}
|
||||
|
||||
public:
|
||||
static bool wasConstructed() {return isConstructed == isConstructedTrue();}
|
||||
|
||||
/* override */ shared_ptr<Reflection::DescribedBase> create() const {
|
||||
RBXASSERT(wasConstructed());
|
||||
return Creatable<FactoryClass>::template create<Class>();
|
||||
}
|
||||
|
||||
const RBX::Name& getClassName() const {
|
||||
RBXASSERT(wasConstructed());
|
||||
return RBX::Name::declare<sClassName>();
|
||||
}
|
||||
|
||||
Creator()
|
||||
{
|
||||
// Register this creator for create-by-className
|
||||
const RBX::Name& name = getClassNameUnconstructed();
|
||||
|
||||
auto& creators = Creatable<FactoryClass>::getCreators();
|
||||
|
||||
RBXASSERT(creators.find(&name)==creators.end());
|
||||
RBXASSERT(!wasConstructed());
|
||||
|
||||
creators[&name] = this;
|
||||
isConstructed = isConstructedTrue();
|
||||
|
||||
RBXASSERT(creators.find(&name)!=creators.end());
|
||||
RBXASSERT(wasConstructed());
|
||||
}
|
||||
|
||||
~Creator() {
|
||||
auto& creators = Creatable<FactoryClass>::getCreators();
|
||||
|
||||
RBXASSERT(wasConstructed());
|
||||
creators.erase(&getClassName());
|
||||
}
|
||||
};
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
static const Creator creatorPrivate;
|
||||
#else
|
||||
static Creator creatorPrivate;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
FactoryProduct()
|
||||
{
|
||||
}
|
||||
template<class Arg0>
|
||||
FactoryProduct(Arg0 arg0):BaseClass(arg0)
|
||||
{
|
||||
}
|
||||
template<class Arg0, class Arg1>
|
||||
FactoryProduct(Arg0 arg0, Arg1 arg1):BaseClass(arg0,arg1)
|
||||
{
|
||||
}
|
||||
virtual ~FactoryProduct()
|
||||
{
|
||||
}
|
||||
static const Creator& static_getCreator() {
|
||||
RBXASSERT(Creator::wasConstructed());
|
||||
return creatorPrivate;
|
||||
}
|
||||
public:
|
||||
const ICreator& getCreator() {
|
||||
return static_getCreator();
|
||||
}
|
||||
|
||||
static const RBX::Name& className() { return static_getCreator().getClassName(); };
|
||||
static bool isNullClassName() {
|
||||
RBXASSERT(!className().empty());
|
||||
return false;
|
||||
};
|
||||
const RBX::Name& getClassName() const { return static_getCreator().getClassName(); };
|
||||
|
||||
// Convenient static functions for creating an instance of this class:
|
||||
// TODO: Refactor: rename createInstance --> create, but also need to rename AbstractFactoryProduct::create to something else
|
||||
static shared_ptr<Class> createInstance() {
|
||||
return Creatable<FactoryClass>::template create<Class>();
|
||||
}
|
||||
template<typename P1>
|
||||
static shared_ptr<Class> createInstance(P1 p1)
|
||||
{
|
||||
return Creatable<FactoryClass>::template create<Class>(p1);
|
||||
}
|
||||
template<typename P1, typename P2>
|
||||
static shared_ptr<Class> createInstance(P1 p1, P2 p2)
|
||||
{
|
||||
return Creatable<FactoryClass>::template create<Class>(p1, p2);
|
||||
}
|
||||
template<typename P1, typename P2, typename P3>
|
||||
static shared_ptr<Class> createInstance(P1 p1, P2 p2, P3 p3)
|
||||
{
|
||||
return Creatable<FactoryClass>::template create<Class>(p1, p2, p3);
|
||||
}
|
||||
template<typename P1, typename P2, typename P3, typename P4>
|
||||
static shared_ptr<Class> createInstance(P1 p1, P2 p2, P3 p3, P4 p4)
|
||||
{
|
||||
return Creatable<FactoryClass>::template create<Class>(p1, p2, p3, p4);
|
||||
}
|
||||
};
|
||||
|
||||
// Static Defination Go Here
|
||||
// creatorPrivate was a const earlier, but that gives gcc error while trying to define the variable with const qualification.
|
||||
// gcc error: expected nested-name-specifier before 'const'
|
||||
// This is not a proper way to fix, but I do not have a choice right now. The variable is in a private section of a class so should be safe.
|
||||
template <class Class, class BaseClass, const char* const& sClassName, class FactoryClass>
|
||||
#ifdef _WIN32
|
||||
typename const FactoryProduct<Class, BaseClass, sClassName, FactoryClass>::Creator FactoryProduct<Class, BaseClass, sClassName, FactoryClass>::creatorPrivate;
|
||||
#else
|
||||
typename FactoryProduct<Class, BaseClass, sClassName, FactoryClass>::Creator FactoryProduct<Class, BaseClass, sClassName, FactoryClass>::creatorPrivate;
|
||||
#endif
|
||||
|
||||
template <class Class, class BaseClass, const char* const& sClassName, class FactoryClass>
|
||||
int FactoryProduct<Class, BaseClass, sClassName, FactoryClass>::Creator::isConstructed;
|
||||
|
||||
// For objects that should NOT be creatable by a factory
|
||||
template <class BaseClass, const char* const& sClassName>
|
||||
class NonFactoryProduct : public BaseClass
|
||||
{
|
||||
public:
|
||||
NonFactoryProduct():BaseClass() {}
|
||||
|
||||
template<class Arg0>
|
||||
NonFactoryProduct(Arg0 arg0):BaseClass(arg0) {}
|
||||
template<class Arg0, class Arg1>
|
||||
NonFactoryProduct(Arg0 arg0, Arg1 arg1):BaseClass(arg0, arg1) {}
|
||||
template<class Arg0, class Arg1, class Arg2>
|
||||
NonFactoryProduct(Arg0 arg0, Arg1 arg1, Arg2 arg2):BaseClass(arg0, arg1, arg2) {}
|
||||
template<class Arg0, class Arg1, class Arg2, class Arg3>
|
||||
NonFactoryProduct(Arg0 arg0, Arg1 arg1, Arg2 arg2, Arg3 arg3):BaseClass(arg0, arg1, arg2, arg3) {}
|
||||
|
||||
static const RBX::Name& className()
|
||||
{
|
||||
return RBX::Name::declare<sClassName>();
|
||||
};
|
||||
|
||||
static bool isNullClassName() {
|
||||
RBXASSERT(className().empty() == (sClassName==NULL));
|
||||
return sClassName==NULL;
|
||||
};
|
||||
const RBX::Name& getClassName() const {
|
||||
return className();
|
||||
}
|
||||
};
|
||||
} // namespace RBX
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include "FastLog.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
// Wrapper around values that allows it to be used like
|
||||
// a normal reference to the type (i.e. T& instead of T*).
|
||||
// Also mildly obscures stored values so that they are harder to find
|
||||
// with a memory scan.
|
||||
template<typename T> class ObscureValue {
|
||||
static const int kArraySize = (sizeof(T)/sizeof(long) < 1) ? 1 : sizeof(T)/sizeof(long);
|
||||
union InternalStorage
|
||||
{
|
||||
long asRaw[kArraySize];
|
||||
T asBase;
|
||||
};
|
||||
InternalStorage storage;
|
||||
public:
|
||||
explicit ObscureValue(const T& value){
|
||||
InternalStorage tmp;
|
||||
tmp.asBase = value;
|
||||
for (int i = 0; i < kArraySize; ++i)
|
||||
{
|
||||
storage.asRaw[i] = tmp.asRaw[i] ^ reinterpret_cast<uintptr_t>(this) ;
|
||||
}
|
||||
}
|
||||
|
||||
operator const T() const {
|
||||
InternalStorage tmp;
|
||||
for (int i = 0; i < kArraySize; ++i)
|
||||
{
|
||||
tmp.asRaw[i] = storage.asRaw[i] ^ reinterpret_cast<uintptr_t>(this) ;
|
||||
}
|
||||
return tmp.asBase;
|
||||
}
|
||||
|
||||
ObscureValue& operator=(const T& other) {
|
||||
InternalStorage tmp;
|
||||
tmp.asBase = other;
|
||||
for (int i = 0; i < kArraySize; ++i)
|
||||
{
|
||||
storage.asRaw[i] = tmp.asRaw[i] ^ reinterpret_cast<uintptr_t>(this) ;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
private:
|
||||
// Disable no-arg construction, copy, and regular assign.
|
||||
// Some of these may be safe, but they are not needed yet,
|
||||
// and the safety of this class is easier to understand without
|
||||
// them.
|
||||
ObscureValue();
|
||||
ObscureValue(const ObscureValue&);
|
||||
ObscureValue& operator=(const ObscureValue&);
|
||||
};
|
||||
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/Velocity.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class PV
|
||||
{
|
||||
public:
|
||||
CoordinateFrame position;
|
||||
Velocity velocity;
|
||||
|
||||
private:
|
||||
/*
|
||||
inline PV operator *(const PV& localPV) const {
|
||||
CoordinateFrame worldPos(position * localPV.position);
|
||||
Velocity otherVWorld = localPV.velocity.rotateBy(position.rotation);
|
||||
Vector3 linearVel = linearVelocityAtPoint(worldPos.translation) + otherVWorld.linear;
|
||||
Vector3 rotVel = velocity.rotational + otherVWorld.rotational;
|
||||
Velocity worldVel(linearVel, rotVel);
|
||||
return PV(worldPos, worldVel);
|
||||
}
|
||||
*/
|
||||
|
||||
public:
|
||||
|
||||
bool operator==(const PV& other) const {
|
||||
return (position == other.position) && (velocity == other.velocity);
|
||||
}
|
||||
|
||||
bool operator!=(const PV& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
// CoordinateFrame and Velocity both initialize to identity/0
|
||||
inline PV()
|
||||
{}
|
||||
|
||||
PV(const CoordinateFrame& _position, const Velocity& _velocity) :
|
||||
position(_position), velocity(_velocity) {}
|
||||
|
||||
PV(const PV &other) :
|
||||
position(other.position), velocity(other.velocity) {}
|
||||
|
||||
inline ~PV() {}
|
||||
|
||||
/**
|
||||
Computes the inverse of this PV.
|
||||
*/
|
||||
/*
|
||||
inline PV inverse() const {
|
||||
PV out;
|
||||
out.position = position.inverse();
|
||||
out.velocity = -velocity.rotateBy(out.position.rotation);
|
||||
return out;
|
||||
}
|
||||
|
||||
inline PV toObjectSpace(const PV& g) const {
|
||||
return this->inverse() * g;
|
||||
}
|
||||
|
||||
inline PV toWorldSpace(const PV& localPV) const {
|
||||
return *this * localPV;
|
||||
}
|
||||
*/
|
||||
|
||||
// Generate Local Linear Velocities
|
||||
|
||||
inline Vector3 linearVelocityAtPoint(const Vector3& worldPos) const {
|
||||
return velocity.linearVelocityAtOffset(worldPos - position.translation);
|
||||
}
|
||||
|
||||
|
||||
// Generate Local Velocities
|
||||
|
||||
inline Velocity velocityAtPoint(const Vector3& worldPos) const {
|
||||
return velocity.velocityAtOffset(worldPos - position.translation);
|
||||
}
|
||||
|
||||
inline Velocity velocityAtLocalOffset(const Vector3& localOffset) const {
|
||||
Vector3 worldPos = position.pointToWorldSpace(localOffset);
|
||||
return velocityAtPoint(worldPos);
|
||||
}
|
||||
|
||||
// Generate Local PVs
|
||||
inline PV pvAtLocalOffset(const Vector3& localOffset) const {
|
||||
return pvAtLocalCoord(CoordinateFrame(localOffset));
|
||||
}
|
||||
|
||||
static inline void pvAtLocalCoord(const PV& base, const CoordinateFrame& localCoord, PV& answer) {
|
||||
CoordinateFrame::mul(base.position, localCoord, answer.position);
|
||||
answer.velocity = base.velocityAtPoint(answer.position.translation);
|
||||
}
|
||||
|
||||
inline PV pvAtLocalCoord(const CoordinateFrame& localCoord) const {
|
||||
PV answer;
|
||||
pvAtLocalCoord(*this, localCoord, answer);
|
||||
return answer;
|
||||
}
|
||||
|
||||
inline PV lerp(const PV& other, float alpha) const {
|
||||
return PV( position.lerp(other.position, alpha),
|
||||
velocity.lerp(other.velocity, alpha) );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
namespace RBX {
|
||||
|
||||
enum PartMaterial
|
||||
{
|
||||
PLASTIC_MATERIAL = 0x0100,
|
||||
SMOOTH_PLASTIC_MATERIAL = 0x0110,
|
||||
NEON_MATERIAL = 0x0120,
|
||||
WOOD_MATERIAL = 0x0200,
|
||||
WOODPLANKS_MATERIAL = 0x0210,
|
||||
MARBLE_MATERIAL = 0x0310,
|
||||
SLATE_MATERIAL = 0x0320,
|
||||
CONCRETE_MATERIAL = 0x0330,
|
||||
GRANITE_MATERIAL = 0x0340,
|
||||
BRICK_MATERIAL = 0x0350,
|
||||
PEBBLE_MATERIAL = 0x0360,
|
||||
COBBLESTONE_MATERIAL= 0x0370,
|
||||
ROCK_MATERIAL = 0x0380,
|
||||
SANDSTONE_MATERIAL = 0x0390,
|
||||
BASALT_MATERIAL = 0x0314,
|
||||
CRACKED_LAVA_MATERIAL = 0x0324,
|
||||
RUST_MATERIAL = 0x0410,
|
||||
DIAMONDPLATE_MATERIAL = 0x0420,
|
||||
ALUMINUM_MATERIAL = 0x0430,
|
||||
METAL_MATERIAL = 0x0440,
|
||||
GRASS_MATERIAL = 0x0500,
|
||||
SAND_MATERIAL = 0x0510,
|
||||
FABRIC_MATERIAL = 0x0520,
|
||||
SNOW_MATERIAL = 0x0530,
|
||||
MUD_MATERIAL = 0x0540,
|
||||
GROUND_MATERIAL = 0x0550,
|
||||
ICE_MATERIAL = 0x0600,
|
||||
GLACIER_MATERIAL = 0x0610,
|
||||
AIR_MATERIAL = 0x0700,
|
||||
WATER_MATERIAL = 0x0800,
|
||||
LEGACY_MATERIAL = 0xFFFF, // should not be serialized
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
#include "rbx/rbxTime.h"
|
||||
#include <boost/circular_buffer.hpp>
|
||||
#include "Util/Average.h"
|
||||
#include "Util/Velocity.h"
|
||||
#include "rbx/RunningAverage.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
#define NUM_MAX_HISTORY 8
|
||||
#define NUM_BUFFER_NODES 2
|
||||
|
||||
class PartInstance;
|
||||
|
||||
// This class keeps a list of frames and the time they were set.
|
||||
|
||||
class PathInterpolatedCFrame
|
||||
{
|
||||
private:
|
||||
|
||||
struct FrameInfo
|
||||
{
|
||||
CoordinateFrame coordinateFrame;
|
||||
Velocity velocity;
|
||||
RemoteTime remoteTime; // in sender's time scale
|
||||
FrameInfo() {}
|
||||
FrameInfo(const CoordinateFrame &cf, const Velocity& vel, const Time& local, const RemoteTime& remote) : coordinateFrame(cf), velocity(vel), remoteTime(remote) {}
|
||||
};
|
||||
|
||||
FrameInfo prevFrame;
|
||||
FrameInfo lastStartFrame;
|
||||
|
||||
bool beingMoved;
|
||||
int uiStepId;
|
||||
double localToRemoteTimeOffset; // subtract local time by this value to get remote time
|
||||
RunningAverage<> avgInterval;
|
||||
Time prevStepTime;
|
||||
boost::circular_buffer_space_optimized<FrameInfo> frameInfos;
|
||||
|
||||
float targetDelayInSeconds;
|
||||
int targetFrame;
|
||||
|
||||
// for analytics
|
||||
double lastTargetDelayValue;
|
||||
double targetDelayDeltaMax;
|
||||
|
||||
|
||||
inline const CoordinateFrame& recordAndReturn(const CoordinateFrame& value, const Time& local, const RemoteTime& remote)
|
||||
{
|
||||
beingMoved = true;
|
||||
prevFrame.coordinateFrame = value;
|
||||
prevFrame.remoteTime = remote;
|
||||
return prevFrame.coordinateFrame;
|
||||
}
|
||||
|
||||
inline const CoordinateFrame& recordAndReturnHermite(const CoordinateFrame& value, const FrameInfo& startFrame, const Time& local, const RemoteTime& remote)
|
||||
{
|
||||
beingMoved = true;
|
||||
lastStartFrame = startFrame;
|
||||
prevFrame.coordinateFrame = value;
|
||||
prevFrame.remoteTime = remote;
|
||||
return prevFrame.coordinateFrame;
|
||||
}
|
||||
|
||||
const CoordinateFrame& interpolate( const Time& now, const Time& targetTime, const unsigned int& upper, const PartInstance* part = NULL);
|
||||
const CoordinateFrame& interpolateHermiteSpline( const Time& now, const Time& targetTime, const unsigned int& upper, const PartInstance* part = NULL);
|
||||
RemoteTime computeSampleTargetTime( const Time& now);
|
||||
|
||||
public:
|
||||
PathInterpolatedCFrame();
|
||||
~PathInterpolatedCFrame() {}
|
||||
|
||||
void clearHistory();
|
||||
|
||||
// timeStamp is time this value was set. If coming from network, the value should be time it was send from the server
|
||||
void setValue(PartInstance* part, const CoordinateFrame& value, const Velocity& vel, const RemoteTime& timeStamp, Time now, float localTimeOffest, int numNodesAhead);
|
||||
|
||||
void setTargetDelay(float value);
|
||||
|
||||
void setUiStepId(int id) {uiStepId = id;}
|
||||
int getUiStepId() const {return uiStepId;}
|
||||
|
||||
double getLocalToRemoteTimeOffset() {return localToRemoteTimeOffset;}
|
||||
|
||||
void setRenderedFrame(const CoordinateFrame& value);
|
||||
void setRenderedFrame(const CoordinateFrame& value, const RemoteTime& remoteTime);
|
||||
|
||||
CoordinateFrame computeValue(PartInstance* part, const Time& t);
|
||||
CoordinateFrame getLastComputedValue() const { return prevFrame.coordinateFrame; }
|
||||
|
||||
bool isBeingMovedByInterpolator() const { return beingMoved; }
|
||||
|
||||
Color3 getSampleIntervalColor() const;
|
||||
float getSampleInterval() const;
|
||||
|
||||
void renderPath(Adorn* adorn);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,117 @@
|
||||
#pragma once
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include "Util/Math.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
enum PhysicalPropertiesMode
|
||||
{
|
||||
PhysicalPropertiesMode_Legacy,
|
||||
PhysicalPropertiesMode_Default,
|
||||
PhysicalPropertiesMode_NewPartProperties
|
||||
};
|
||||
|
||||
|
||||
class PhysicalProperties
|
||||
{
|
||||
private:
|
||||
bool customEnabled;
|
||||
float density;
|
||||
float elasticity;
|
||||
float friction;
|
||||
float frictionWeight;
|
||||
float elasticityWeight;
|
||||
|
||||
static float minDen() { return 0.01f; }
|
||||
static float maxDen() { return 100.0f;}
|
||||
static float minFri() { return 0.0f; } // Negative friction Generates energy
|
||||
static float maxFri() { return 2.0f; }
|
||||
static float minFrW() { return 0.0f; }
|
||||
static float maxFrW() { return 100.0f;}
|
||||
static float minEla() { return 0.0f; } // Negative Elasticity causes penetration
|
||||
static float maxEla() { return 1.0f; } // Elasticity > 1 causes energy gain
|
||||
static float minElW() { return 0.0f; }
|
||||
static float maxElW() { return 100.0f;}
|
||||
|
||||
|
||||
public:
|
||||
// Default Constructor for initializing part instances
|
||||
PhysicalProperties():
|
||||
customEnabled(false),
|
||||
density(0),
|
||||
friction(0),
|
||||
elasticity(0),
|
||||
frictionWeight(0),
|
||||
elasticityWeight(0)
|
||||
{
|
||||
}
|
||||
|
||||
// Constructor for enabling Custom
|
||||
PhysicalProperties(float density_, float friction_, float elasticity_, float frictionWeight_ = 1.0f, float elasticityWeight_ = 1.0f):
|
||||
customEnabled(true),
|
||||
density (G3D::clamp(density_, minDen(), maxDen())),
|
||||
friction (G3D::clamp(friction_, minFri(), maxFri())),
|
||||
elasticity (G3D::clamp(elasticity_, minEla(), maxEla())),
|
||||
frictionWeight (G3D::clamp(frictionWeight_, minFrW(), maxFrW())),
|
||||
elasticityWeight(G3D::clamp(elasticityWeight_, minElW(), maxElW()))
|
||||
{
|
||||
}
|
||||
|
||||
size_t hashCode() const;
|
||||
|
||||
bool getCustomEnabled() const
|
||||
{
|
||||
return customEnabled;
|
||||
}
|
||||
|
||||
void setCustomEnabled( bool value )
|
||||
{
|
||||
customEnabled = value;
|
||||
}
|
||||
|
||||
float getDensity() const
|
||||
{
|
||||
return density;
|
||||
}
|
||||
|
||||
float getFriction() const
|
||||
{
|
||||
return friction;
|
||||
}
|
||||
|
||||
float getElasticity() const
|
||||
{
|
||||
return elasticity;
|
||||
}
|
||||
|
||||
float getFrictionWeight() const
|
||||
{
|
||||
return frictionWeight;
|
||||
}
|
||||
|
||||
float getElasticityWeight() const
|
||||
{
|
||||
return elasticityWeight;
|
||||
}
|
||||
|
||||
//Operators
|
||||
|
||||
bool operator==(const PhysicalProperties& other) const
|
||||
{
|
||||
return ((customEnabled == other.customEnabled) &&
|
||||
(density == other.density) &&
|
||||
(friction == other.friction) &&
|
||||
(elasticity == other.elasticity) &&
|
||||
(frictionWeight == other.frictionWeight) &&
|
||||
(elasticityWeight== other.elasticityWeight));
|
||||
}
|
||||
|
||||
bool operator!=(const PhysicalProperties& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
size_t hash_value(const PhysicalProperties& properties);
|
||||
|
||||
}; //Namespace RBX
|
||||
@@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
#include "Util/Quaternion.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class PhysicsCoord
|
||||
{
|
||||
public:
|
||||
Vector3 translation;
|
||||
Quaternion rotation;
|
||||
|
||||
bool operator==(const PhysicsCoord& other) const {
|
||||
return (translation == other.translation) && (rotation == other.rotation);
|
||||
}
|
||||
|
||||
bool operator!=(const PhysicsCoord& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
inline PhysicsCoord() :
|
||||
translation(Vector3::zero()) {}
|
||||
|
||||
PhysicsCoord(const CoordinateFrame& cframe) :
|
||||
translation(cframe.translation), rotation(cframe.rotation)
|
||||
{}
|
||||
|
||||
PhysicsCoord(const Vector3& _translation) :
|
||||
translation(_translation) {}
|
||||
|
||||
PhysicsCoord(const Vector3& _translation, const Quaternion& _rotation) :
|
||||
translation(_translation), rotation(_rotation) {}
|
||||
|
||||
PhysicsCoord(const PhysicsCoord &other) :
|
||||
translation(other.translation), rotation(other.rotation) {}
|
||||
|
||||
PhysicsCoord operator+ (const PhysicsCoord& rhs) const {
|
||||
return PhysicsCoord(translation + rhs.translation, rotation + rhs.rotation);
|
||||
}
|
||||
|
||||
PhysicsCoord operator- (const PhysicsCoord& rhs) const {
|
||||
return PhysicsCoord(translation - rhs.translation, rotation - rhs.rotation);
|
||||
}
|
||||
|
||||
float squaredMagnitude() const {
|
||||
return translation.squaredMagnitude() + rotation.magnitude(); // note for quaternion magnitude == squared values?....
|
||||
}
|
||||
|
||||
PhysicsCoord& operator+= (const PhysicsCoord& other) {
|
||||
translation += other.translation;
|
||||
rotation += other.rotation;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PhysicsCoord operator*(float f) const {
|
||||
return PhysicsCoord(translation * f, rotation * f);
|
||||
}
|
||||
|
||||
PhysicsCoord operator/(float f) const {
|
||||
float mul = 1.0f/f;
|
||||
return *this * mul;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
|
||||
#include "rbx/boost.hpp"
|
||||
#include "rbx/rbxTime.h"
|
||||
#include "boost/array.hpp"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Profiling
|
||||
{
|
||||
void init(bool enabled);
|
||||
void setEnabled(bool enabled);
|
||||
bool isEnabled();
|
||||
|
||||
struct Bucket
|
||||
{
|
||||
float sampleTimeElapsed; // System time span that the bucket sampled for
|
||||
float wallTimeSpan;
|
||||
int frames; // The number of "frames" recorded in the bucket
|
||||
|
||||
double getActualFPS() const; // frames/sec
|
||||
double getNominalFPS() const; // frames/sec
|
||||
double getNominalFramePeriod() const; // secs/frame
|
||||
|
||||
double getSampleTime() const { return sampleTimeElapsed; }
|
||||
double getWallTime() const { return wallTimeSpan; }
|
||||
int getFrames() const { return frames; }
|
||||
|
||||
Bucket();
|
||||
Bucket& operator+=(const Bucket& b);
|
||||
};
|
||||
|
||||
class Profiler : public boost::noncopyable
|
||||
{
|
||||
protected:
|
||||
const Time::Interval bucketTimeSpan; // The minimum amount of time per bucket
|
||||
int currentBucket;
|
||||
boost::array<Bucket, 512> buckets; // TODO: Use boost::circular_buffer
|
||||
Time lastSampleTime;
|
||||
public:
|
||||
const std::string name;
|
||||
Profiler(const char* name);
|
||||
virtual ~Profiler() {};
|
||||
Bucket getWindow(double window) const; // get last samples based on elapsed time
|
||||
Bucket getFrames(int frames) const; // get n last frames.
|
||||
static double profilingWindow;
|
||||
};
|
||||
|
||||
// Profiles sections of code using the Mark class
|
||||
class CodeProfiler : public Profiler
|
||||
{
|
||||
friend class Mark;
|
||||
public:
|
||||
CodeProfiler(const char* name);
|
||||
private:
|
||||
void log(bool frameTick, double wallTimeElapsed);
|
||||
void unlog(double wallTimeElapsed);
|
||||
};
|
||||
|
||||
// Mark a section of code as belonging to a CodeProfiler
|
||||
// (Enclosing Mark will be disabled for the lifetime of this object)
|
||||
class Mark
|
||||
{
|
||||
CodeProfiler& section;
|
||||
Mark* enclosingMark;
|
||||
bool frameTick;
|
||||
Time startTime;
|
||||
const bool enabled;
|
||||
Time::Interval childrenElapsed; // sum of elapsed time (inclusive) in all Markers that have _this_ as a enclosingMark.
|
||||
const bool logInclusive; // true if you want to log time including children. false will subtract time spent in children
|
||||
public:
|
||||
Mark(CodeProfiler& section, bool frameTick, bool logInclusive = false);
|
||||
~Mark();
|
||||
};
|
||||
|
||||
|
||||
// BucketProfile
|
||||
class BucketProfile
|
||||
{
|
||||
std::vector<int> data;
|
||||
const int* bucketLimits;
|
||||
|
||||
unsigned int findBucket(int v);
|
||||
int total;
|
||||
|
||||
public:
|
||||
// WARNING: assumes pointer to bucketLimits is static and saves it directly
|
||||
BucketProfile(const int* bucketLimits, int size);
|
||||
|
||||
BucketProfile(const BucketProfile& rhs);
|
||||
BucketProfile();
|
||||
const BucketProfile& operator = (const BucketProfile& rhs);
|
||||
|
||||
void addValue(int v);
|
||||
void removeValue(int v);
|
||||
void clear();
|
||||
|
||||
int getTotal() { return total; }
|
||||
|
||||
const std::vector<int>& getData() const { return data; };
|
||||
const int* getLimits() const { return bucketLimits; };
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,366 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include "rbx/rbxTime.h"
|
||||
#include <vector>
|
||||
#include "Security/RandomConstant.h"
|
||||
#include "v8datamodel/HackDefines.h"
|
||||
#include "util/HeapValue.h"
|
||||
#include "Security/ApiSecurity.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace Hasher
|
||||
{
|
||||
// The PMC constructor assumes a specific ordering of these items.
|
||||
enum HashSection
|
||||
{
|
||||
kGoldHashStart = 0,
|
||||
kGoldHashEnd = 1,
|
||||
kGoldHashRot = 2,
|
||||
kRdataHash = 3,
|
||||
kVmpPlainHash = 4,
|
||||
kVmpMutantHash = 5,
|
||||
kIatHash = 6,
|
||||
kMiscHash = 7,
|
||||
kMsvcHash = 8,
|
||||
kVmp0MiscHash = 9,
|
||||
kVmp1MiscHash = 10,
|
||||
kNonGoldHashRot = 11,
|
||||
kNumberOfSectionHashes = 12,
|
||||
kGoldHashStruct = 12,
|
||||
kAllHashStruct = 13,
|
||||
kNumberOfHashes = 14
|
||||
};
|
||||
|
||||
// These do not have a 1:1 relation with the indicies above.
|
||||
enum HashFailures
|
||||
{
|
||||
// 0x?000
|
||||
kVmp1MiscHashFail = 1<<15,
|
||||
kVmp0MiscHashFail = 1<<14,
|
||||
kVmpMutantHashFail = 1<<13,
|
||||
kIatHashFail = 1<<12,
|
||||
// 0x0?00
|
||||
kGoldHashFail = 1<<11,
|
||||
kNonceFail = 1<<10,
|
||||
kAllHashStructFail = 1<<9,
|
||||
kGoldHashStructFail = 1<<8,
|
||||
// 0x00?0
|
||||
kNonGoldHashRotFail = 1<<7,
|
||||
kVmpPlainHashFail = 1<<6,
|
||||
kMsvcHashFail = 1<<5,
|
||||
kRdataHashFail = 1<<4,
|
||||
// 0x000?
|
||||
kMiscHashFail = 1<<3,
|
||||
kGoldHashRotFail = 1<<2,
|
||||
kGoldHashEndFail = 1<<1,
|
||||
kGoldHashStartFail = 1<<0
|
||||
};
|
||||
|
||||
static const unsigned int kGoldHashMask = kGoldHashFail;
|
||||
|
||||
static const unsigned int kDiffHashMask = kGoldHashStartFail | kGoldHashEndFail
|
||||
| kMiscHashFail | kRdataHashFail | kMsvcHashFail | kGoldHashStructFail
|
||||
| kAllHashStructFail | kVmpPlainHashFail | kVmpMutantHashFail | kVmp0MiscHashFail
|
||||
| kVmp1MiscHashFail | kIatHashFail;
|
||||
|
||||
static const unsigned int kMovingHashMask = kNonceFail | kGoldHashRotFail
|
||||
| kNonGoldHashRotFail;
|
||||
|
||||
static const int zeroPad[4] = {0,0,0,0};
|
||||
|
||||
static const unsigned int kPmcNonceGoodInc = 3692164867;
|
||||
static const unsigned int kPmcNonceBadInc = 3692164869;
|
||||
static const unsigned int kPmcNonceGoodIncInv = 2880154539; //0xABABABAB supplied by irc user. unimportant fact.
|
||||
|
||||
}
|
||||
|
||||
struct ScanRegion
|
||||
{
|
||||
char* startingAddress;
|
||||
unsigned int size;
|
||||
|
||||
// ".text" and ".rdata" appear in several places in RAM, so it is safe to have them as literals.
|
||||
// likewise, exploiters would quickly realize that .text and .rdata are scanned.
|
||||
// if they change the value to something else, it would crash.
|
||||
static ScanRegion getScanRegion(const char* moduleName, const char* RegionName);
|
||||
|
||||
ScanRegion() : startingAddress(NULL), size(0){}
|
||||
ScanRegion(const ScanRegion &initValue) : startingAddress(initValue.startingAddress), size(initValue.size){}
|
||||
ScanRegion(char* startingAddress, unsigned int size) : startingAddress(startingAddress), size(size) {}
|
||||
};
|
||||
|
||||
struct ScanRegionTest : ScanRegion
|
||||
{
|
||||
void* hashState;
|
||||
unsigned int lastHashValue;
|
||||
bool closeHash;
|
||||
bool useHashValueInStructHash;
|
||||
bool useHashAddrSizeInStructHash;
|
||||
|
||||
ScanRegionTest() : ScanRegion(),
|
||||
hashState(NULL),
|
||||
lastHashValue(0),
|
||||
closeHash(false),
|
||||
useHashValueInStructHash(true),
|
||||
useHashAddrSizeInStructHash(true) {}
|
||||
ScanRegionTest(ScanRegion initValue) : ScanRegion(initValue),
|
||||
hashState(NULL),
|
||||
lastHashValue(0),
|
||||
closeHash(false),
|
||||
useHashValueInStructHash(true),
|
||||
useHashAddrSizeInStructHash(true) {}
|
||||
};
|
||||
|
||||
struct PmcHashContainer
|
||||
{
|
||||
typedef std::vector<unsigned int> HashVector;
|
||||
unsigned int nonce;
|
||||
HashVector hash;
|
||||
PmcHashContainer(const PmcHashContainer& init);
|
||||
PmcHashContainer() : nonce(0) {}
|
||||
};
|
||||
|
||||
extern PmcHashContainer pmcHash;
|
||||
|
||||
#if defined(_WIN32) && !defined(RBX_PLATFORM_DURANGO)
|
||||
class NtApiCaller
|
||||
{
|
||||
private:
|
||||
static const uintptr_t kKey = 111777;
|
||||
static const unsigned kNtQvmEndToken = 0x0018C204; // sub esp, 4; ret 0x18;
|
||||
static const unsigned kNtGtxEndToken = 0x0008C204; // sub esp, 4; ret 0x08;
|
||||
// on windows xp, this is 0x00?8C212FF // call dword ptr [edx]; ret 0x?8
|
||||
static const unsigned kEndMask = 0xFFFFFF00;
|
||||
typedef DWORD (NTAPI *NtQvmPfn)(HANDLE, PVOID, DWORD, PVOID, ULONG, PULONG);
|
||||
typedef DWORD (NTAPI *NtGtxPfn)(HANDLE, PCONTEXT);
|
||||
HANDLE thisProcess;
|
||||
HeapValue<size_t> hashEndSize;
|
||||
HeapValue<uintptr_t> ntQvmAsUint;
|
||||
HeapValue<size_t> ntQvmCallHash;
|
||||
HeapValue<uintptr_t> ntGtxAsUint;
|
||||
HeapValue<size_t> ntGtxCallHash;
|
||||
HeapValue<uintptr_t> ntdllTextBase;
|
||||
HeapValue<size_t> ntdllSize;
|
||||
|
||||
|
||||
static unsigned int hashFeed(unsigned int state, unsigned int value)
|
||||
{
|
||||
return state + _rotl((state+kKey)*(value-kKey), 7);
|
||||
}
|
||||
|
||||
__forceinline void initApiFunction(uintptr_t pfn, HeapValue<uintptr_t>& pfnOut, uintptr_t callTemplate, HeapValue<uintptr_t>& callHashOut, HeapValue<uintptr_t>& hashEndSizeOut, unsigned int endToken)
|
||||
{
|
||||
if (!pfn || (pfn - ntdllTextBase > ntdllSize))
|
||||
{
|
||||
// couldn't find NtQueryVirtualMemory or it wasn't in the dll.
|
||||
Tokens::apiToken.addFlagSafe(kNtApiNoApi);
|
||||
}
|
||||
pfnOut = pfn;
|
||||
|
||||
// ZwFilterToken isn't important, but it is called in a near identical way as NtQVM
|
||||
// generate a hash of how ntdll will be called.
|
||||
if (callTemplate && (callTemplate - ntdllTextBase < ntdllSize))
|
||||
{
|
||||
for (int i = 5; i < 32; ++i) // assume call takes < 32B on x86/WoW64
|
||||
{
|
||||
unsigned int value = *reinterpret_cast<unsigned int*>(callTemplate + i);
|
||||
callHashOut = hashFeed(callHashOut, value);
|
||||
if((kEndMask & value) == (kEndMask & endToken))
|
||||
{
|
||||
hashEndSizeOut = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hashEndSizeOut == 0)
|
||||
{
|
||||
// didn't find the end token for some reason.
|
||||
Tokens::apiToken.addFlagSafe(kNtApiNoSyscall);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// In this case, ZwFilterToken didn't exist for some reason, or wasn't in ntdll
|
||||
Tokens::apiToken.addFlagSafe(kNtApiNoTemplate);
|
||||
}
|
||||
}
|
||||
|
||||
__forceinline bool checkCaller(uintptr_t pfn, const HeapValue<uintptr_t>& callHash)
|
||||
{
|
||||
const unsigned char* const& funcMem = reinterpret_cast<const unsigned char*>(pfn);
|
||||
// probably should check to make sure this is within ntdll.
|
||||
if (pfn && (pfn - ntdllTextBase < ntdllSize))
|
||||
{
|
||||
bool canCall = true;
|
||||
// Check Early Hooking:
|
||||
// mov eax, dword 0x0000???? <- B8 ?? ?? 00 00
|
||||
if (funcMem[0] != 0xB8 || funcMem[3] != 0x00 || funcMem[4] != 0x00)
|
||||
{
|
||||
canCall = false;
|
||||
Tokens::apiToken.addFlagSafe(kNtApiEarly);
|
||||
}
|
||||
|
||||
// Check hash of function
|
||||
unsigned int checkHash = 0;
|
||||
int endIdx = hashEndSize;
|
||||
for (int i = 5; i < 32; ++i) // assume call takes < 32B on x86 and WoW64
|
||||
{
|
||||
unsigned int value = *reinterpret_cast<volatile const unsigned int*>(funcMem + i);
|
||||
checkHash = hashFeed(checkHash, value);
|
||||
if(i == endIdx)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (checkHash != callHash)
|
||||
{
|
||||
canCall = false;
|
||||
Tokens::apiToken.addFlagSafe(kNtApiHash);
|
||||
}
|
||||
|
||||
// This decodes and calls the function pointer
|
||||
return canCall;
|
||||
}
|
||||
else
|
||||
{
|
||||
// not defined or not within ntdll.
|
||||
Tokens::apiToken.addFlagSafe(kNtApiNoCall);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
__forceinline DWORD virtualQuery(void* addr, MEMORY_BASIC_INFORMATION* info, size_t cb)
|
||||
{
|
||||
volatile DWORD result = 0;
|
||||
uintptr_t pfn = ntQvmAsUint;
|
||||
if (checkCaller(pfn, ntQvmCallHash))
|
||||
{
|
||||
result = reinterpret_cast<NtQvmPfn>(pfn)(thisProcess, addr, 0, info, cb, NULL);
|
||||
}
|
||||
pfn = 0;
|
||||
return result;
|
||||
}
|
||||
__forceinline DWORD getThreadContext(HANDLE thread, CONTEXT* ctx)
|
||||
{
|
||||
volatile DWORD result = 0;
|
||||
uintptr_t pfn = ntGtxAsUint;
|
||||
if (checkCaller(pfn, ntGtxCallHash))
|
||||
{
|
||||
result = reinterpret_cast<NtGtxPfn>(pfn)(thread, ctx);
|
||||
}
|
||||
pfn = 0;
|
||||
return result;
|
||||
}
|
||||
__forceinline bool isNtdllAddress(uintptr_t addr)
|
||||
{
|
||||
return (addr - ntdllTextBase) < ntdllSize;
|
||||
}
|
||||
NtApiCaller();
|
||||
};
|
||||
#endif
|
||||
|
||||
class ProgramMemoryChecker
|
||||
{
|
||||
protected:
|
||||
unsigned int hsceHashOrReduced;
|
||||
unsigned int hsceHashAndReduced;
|
||||
public:
|
||||
static const int kHASH_SEED_INIT = 42;
|
||||
static const int kAllDone = 0xCCCCCCCC; // A number that is non-zero.
|
||||
static const int kLuaLockOk = 0x1842783;
|
||||
static const int kLuaLockBad = 0;
|
||||
static const int kSteps = 30;
|
||||
static const unsigned int kBlock = 16;
|
||||
ProgramMemoryChecker();
|
||||
unsigned int bytesPerStep;
|
||||
unsigned int currentRegion;
|
||||
const char* currentMemory;
|
||||
std::vector<ScanRegionTest> scanningRegions;
|
||||
unsigned int lastCompletedHash;
|
||||
unsigned int lastGoldenHash;
|
||||
Time lastCompletedTime;
|
||||
|
||||
unsigned int step();
|
||||
unsigned int getLastCompletedHash() const;
|
||||
unsigned int getLastGoldenHash() const;
|
||||
Time getLastCompletedTime() const;
|
||||
|
||||
void getLastHashes(PmcHashContainer::HashVector& outHashes) const;
|
||||
// This is a hash of the hashes, as well as a hash of the region information.
|
||||
unsigned int hashScanningRegions(size_t regions = Hasher::kNumberOfHashes-2) const;
|
||||
|
||||
// return hash of HumanoidState::computeEvent, update hsceHashOrReduce.
|
||||
unsigned int updateHsceHash();
|
||||
unsigned int getHsceOrHash() const;
|
||||
unsigned int getHsceAndHash() const;
|
||||
|
||||
// Should look at return code.
|
||||
int isLuaLockOk() const;
|
||||
|
||||
// Check for stealthedit. Stealthedit sets some pages to non-executable
|
||||
// and then catches the resulting exception, using the opportunity
|
||||
// to redirect to a modified page without disturbing the hash mechanism.
|
||||
// http://www.szemelyesintegracio.hu/cheats/41-game-hacking-articles/419-stealthedit
|
||||
static bool areMemoryPagePermissionsSetupForHacking();
|
||||
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
_declspec(align(8)) extern const char* const maskAddr;
|
||||
_declspec(align(8)) extern const char* const goldHash;
|
||||
unsigned int protectVmpSections();
|
||||
#else
|
||||
__attribute__((__aligned__(8))) extern const char* const maskAddr;
|
||||
__attribute__((__aligned__(8))) extern const char* const goldHash;
|
||||
#endif
|
||||
|
||||
|
||||
namespace Security{
|
||||
// The storage for hash checker related security constants.
|
||||
extern volatile const size_t rbxGoldHash;
|
||||
|
||||
// The lower part of .text
|
||||
extern volatile const uintptr_t rbxLowerBase;
|
||||
extern volatile const size_t rbxLowerSize;
|
||||
|
||||
// The upper part of .text
|
||||
extern volatile const uintptr_t rbxUpperBase;
|
||||
extern volatile const size_t rbxUpperSize;
|
||||
|
||||
// the .rdata section
|
||||
extern volatile const uintptr_t rbxRdataBase;
|
||||
extern volatile const size_t rbxRdataSize;
|
||||
|
||||
// the vmp sections
|
||||
extern volatile const uintptr_t rbxVmpBase;
|
||||
extern volatile const size_t rbxVmpSize;
|
||||
|
||||
// the Import Address (thunk) Table
|
||||
extern volatile const uintptr_t rbxIatBase;
|
||||
extern volatile const size_t rbxIatSize;
|
||||
|
||||
// the vmp sections (plain .text section)
|
||||
extern volatile const uintptr_t rbxVmpPlainBase;
|
||||
extern volatile const size_t rbxVmpPlainSize;
|
||||
|
||||
// the vmp sections (mutation .text section)
|
||||
extern volatile const uintptr_t rbxVmpMutantBase;
|
||||
extern volatile const size_t rbxVmpMutantSize;
|
||||
|
||||
// the vmp sections (don't know)
|
||||
extern volatile const uintptr_t rbxVmp0MiscBase;
|
||||
extern volatile const size_t rbxVmp0MiscSize;
|
||||
|
||||
// the vmp sections (don't know)
|
||||
extern volatile const uintptr_t rbxVmp1MiscBase;
|
||||
extern volatile const size_t rbxVmp1MiscSize;
|
||||
|
||||
// the .rdata section without IAT
|
||||
extern volatile const uintptr_t rbxRdataNoIatBase;
|
||||
extern volatile const size_t rbxRdataNoIatSize;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class IProgressIndicator
|
||||
{
|
||||
public:
|
||||
// returns true if cancel requested.
|
||||
virtual bool setProgess(float percent) { return step(); }; // optional
|
||||
virtual bool step() = 0;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <boost/functional/hash/hash.hpp>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
template<class Type>
|
||||
class ProtectedGeneric
|
||||
{
|
||||
private:
|
||||
Type value;
|
||||
std::size_t hash;
|
||||
public:
|
||||
const Type& peekValue() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
bool getValue(Type& _value) const
|
||||
{
|
||||
_value = this->value;
|
||||
|
||||
boost::hash<Type> hasher;
|
||||
std::size_t newHash = hasher(_value);
|
||||
return (hash == newHash);
|
||||
}
|
||||
void setValue(Type _value)
|
||||
{
|
||||
this->value = _value;
|
||||
|
||||
boost::hash<Type> hasher;
|
||||
hash = hasher(_value);
|
||||
}
|
||||
|
||||
ProtectedGeneric(Type _value)
|
||||
{
|
||||
setValue(_value);
|
||||
}
|
||||
private:
|
||||
ProtectedGeneric(const ProtectedGeneric& other)
|
||||
{}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
||||
struct lua_State;
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class ProtectedString
|
||||
{
|
||||
public:
|
||||
static const ProtectedString emptyString;
|
||||
|
||||
static ProtectedString fromTrustedSource(const std::string& stringRef);
|
||||
static ProtectedString fromBytecode(const std::string& stringRef);
|
||||
|
||||
// Only use in unit tests!
|
||||
static ProtectedString fromTestSource(const std::string& stringRef);
|
||||
|
||||
ProtectedString();
|
||||
ProtectedString(const ProtectedString& other);
|
||||
|
||||
const std::string& getSource() const { return source; }
|
||||
const std::string& getBytecode() const { return bytecode; }
|
||||
|
||||
bool empty() const { return source.empty() && bytecode.empty(); }
|
||||
|
||||
const std::string& getOriginalHash() const;
|
||||
void calculateHash(std::string* out) const;
|
||||
|
||||
bool operator==(const ProtectedString& other) const;
|
||||
bool operator!=(const ProtectedString& other) const;
|
||||
|
||||
ProtectedString& operator=(const ProtectedString& other);
|
||||
|
||||
private:
|
||||
std::string source;
|
||||
std::string bytecode;
|
||||
|
||||
// Need to keep a pointer to hash to keep the size of this object in
|
||||
// line with other lua-bridged types.
|
||||
boost::scoped_ptr<std::string> hash;
|
||||
|
||||
// Hide this to force all changes in string to go through
|
||||
// fromTrustedSource.
|
||||
void setString(const std::string& newSource, const std::string& newBytecode);
|
||||
};
|
||||
|
||||
size_t hash_value(const ProtectedString& str);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Quaternion {
|
||||
public:
|
||||
float x, y, z, w;
|
||||
|
||||
Quaternion(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {}
|
||||
|
||||
Quaternion(const G3D::Vector3& v, float _w = 0) : x((float)v.x), y((float)v.y), z((float)v.z), w(_w) {}
|
||||
|
||||
Quaternion() : x(0.0f), y(0.0f), z(0.0f), w(1.0f) {}
|
||||
|
||||
Quaternion(const G3D::Matrix3& rot);
|
||||
|
||||
Quaternion& operator= (const Quaternion& other);
|
||||
|
||||
inline const G3D::Vector3& imag() const {
|
||||
return *(reinterpret_cast<const G3D::Vector3*>(this));
|
||||
}
|
||||
|
||||
inline G3D::Vector3& imag() {
|
||||
return *(reinterpret_cast<G3D::Vector3*>(this));
|
||||
}
|
||||
|
||||
void toRotationMatrix(
|
||||
Matrix3& rot) const;
|
||||
|
||||
inline float dot(const Quaternion& other) const {
|
||||
return (x * other.x) + (y * other.y) + (z * other.z) + (w * other.w);
|
||||
}
|
||||
|
||||
inline float magnitude() const {
|
||||
return x*x + y*y + z*z + w*w;
|
||||
}
|
||||
|
||||
float maxComponent() const {
|
||||
return std::max( std::max(fabs(x), fabs(y)), std::max(fabs(z), fabs(w)));
|
||||
}
|
||||
|
||||
// Return the angle of the axis-angle representation of the quaternion
|
||||
inline float getAngle() const {
|
||||
return 2.0f * acos(w);
|
||||
}
|
||||
|
||||
// Return the axis of the axis-angle representation of the quaternion
|
||||
inline Vector3 getAxis() const {
|
||||
float sinSquared = 1.f - w * w;
|
||||
if (sinSquared < 1e-6) //Check for divide by zero
|
||||
return Vector3(1.0, 0.0, 0.0); // Arbitrary
|
||||
float sinRecip = 1.f/ sqrtf(sinSquared);
|
||||
return Vector3(x * sinRecip, y * sinRecip, z * sinRecip);
|
||||
}
|
||||
|
||||
inline Quaternion conjugate() const {
|
||||
return Quaternion(-x, -y, -z, w);
|
||||
}
|
||||
|
||||
inline float& operator[] (int i) const {
|
||||
return ((float*)this)[i];
|
||||
}
|
||||
|
||||
inline operator float* () {
|
||||
return (float*)this;
|
||||
}
|
||||
|
||||
inline operator const float* () const {
|
||||
return (float*)this;
|
||||
}
|
||||
|
||||
inline Quaternion operator*(const Quaternion& other) const {
|
||||
// Following Watt & Watt, page 360
|
||||
const Vector3& v1 = imag();
|
||||
const Vector3& v2 = other.imag();
|
||||
float s1 = w;
|
||||
float s2 = other.w;
|
||||
return Quaternion(s1*v2 + s2*v1 + v1.cross(v2), s1*s2 - v1.dot(v2));
|
||||
}
|
||||
|
||||
inline Quaternion operator+ (const Quaternion& other) const {
|
||||
return Quaternion(x + other.x, y + other.y, z + other.z, w + other.w);
|
||||
}
|
||||
|
||||
inline Quaternion operator- (const Quaternion& other) const {
|
||||
return Quaternion(x - other.x, y - other.y, z - other.z, w - other.w);
|
||||
}
|
||||
|
||||
inline Quaternion operator* (float s) const {
|
||||
return Quaternion(s*x, s*y, s*z, s*w);
|
||||
}
|
||||
|
||||
// inline
|
||||
Quaternion& operator*=(float fScalar);
|
||||
|
||||
// inline
|
||||
Quaternion& operator+=(const Quaternion& rkQuaternion);
|
||||
|
||||
void normalize() {
|
||||
*this *= 1.0f / sqrtf(magnitude());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
#include "Quaternion.inl"
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
Quaternion.inl
|
||||
|
||||
*/
|
||||
|
||||
namespace RBX {
|
||||
|
||||
inline Quaternion& Quaternion::operator+= (const Quaternion& rkQuaternion) {
|
||||
x += rkQuaternion.x;
|
||||
y += rkQuaternion.y;
|
||||
z += rkQuaternion.z;
|
||||
w += rkQuaternion.w;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Quaternion& Quaternion::operator*= (float fScalar) {
|
||||
x *= fScalar;
|
||||
y *= fScalar;
|
||||
z *= fScalar;
|
||||
w *= fScalar;
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#define STRING_BY_ID(id) (getStringById(id))
|
||||
|
||||
#ifdef _WIN32
|
||||
__declspec(noinline) const char* getStringById(int id);
|
||||
#elif __APPLE__ || __ANDROID__
|
||||
__attribute__((noinline)) const char* getStringById(int id);
|
||||
#else
|
||||
#error Unsupported Platform.
|
||||
#endif
|
||||
|
||||
enum StringIDs {
|
||||
ArgStringID = 0,
|
||||
LuaStringStringId = 1, //"lua"
|
||||
CommandOutStringId = 2, //"> %s"
|
||||
StudioASHXFmt = 3, //fmt
|
||||
StudioASHX = 4, //ashx
|
||||
RunningScript = 5, //Running script %s
|
||||
ExecScriptNewThread = 6,//Execute script in new thread, name: %s, identity: %u
|
||||
FullScriptCode = 7, //Full script code:\n %s
|
||||
EnableToCreateSBThread = 8, //Unable to create trusted sandbox thread
|
||||
EnableToCreateNewThread = 9, //Unable to create new thread
|
||||
ScriptStr = 10, //Script
|
||||
Rocky = 11,//rocky
|
||||
HasGamePassLuaWarning = 12, //Game passes can only be queried by a Script running on a ROBLOX game server
|
||||
NoTeleportInStudio = 13, //Teleporting while using ROBLOX Studio is not permitted
|
||||
LoadingScreenScriptPath = 14, // The path to the script that creates the loading gui
|
||||
};
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
#include "G3D/Rect2D.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
// TODO: Replace with G3D::Rect2D
|
||||
class Rect {
|
||||
public:
|
||||
typedef enum {TOP, BOTTOM, LEFT, RIGHT, CENTER, NONE} Location;
|
||||
|
||||
static bool legalX(Location loc) {return ((loc != TOP) && (loc != BOTTOM));}
|
||||
static bool legalY(Location loc) {return ((loc != LEFT) && (loc != RIGHT));}
|
||||
|
||||
Vector2 low; // top left
|
||||
Vector2 high; // bottom right
|
||||
|
||||
Rect() : low(0,0), high(0,0) {}
|
||||
|
||||
Rect(Rect2D r) : low(r.x0y0()), high(r.x1y1()) {}
|
||||
|
||||
Rect2D toRect2D() const {return Rect2D::xyxy(low, high);}
|
||||
|
||||
Rect(float left, float top, float right, float bottom) :
|
||||
low(left, top), high(right, bottom) {}
|
||||
|
||||
Rect(const Vector2& _high) :
|
||||
low(Vector2::zero()), high(_high) {}
|
||||
|
||||
Rect(const Vector2& _low, const Vector2& _high) :
|
||||
low(_low), high(_high) {}
|
||||
|
||||
static Rect fromLowSize(const Vector2& _low, const Vector2& _size) {
|
||||
return Rect(_low, _low + _size);
|
||||
}
|
||||
|
||||
static Rect xywh(float x, float y, float w, float h) {
|
||||
return Rect(x,y,x+w,y+h);
|
||||
}
|
||||
|
||||
static Rect fromCenterSize(const Vector2& _center, const Vector2& _size) {
|
||||
Vector2 halfSize = _size * 0.5f;
|
||||
return Rect(_center - halfSize, _center + halfSize);
|
||||
}
|
||||
|
||||
static Rect fromCenterSize(const Vector2& _center, float _size) {
|
||||
return fromCenterSize(_center, Vector2(_size, _size));
|
||||
}
|
||||
|
||||
void unionWith(const Rect& other);
|
||||
|
||||
void unionWith(const Vector2& point) {
|
||||
unionWith(Rect(point, point));
|
||||
}
|
||||
|
||||
bool operator== (const Rect& other) const {
|
||||
return ((low == other.low) && (high == other.high));
|
||||
}
|
||||
|
||||
bool operator!= (const Rect& other) const {
|
||||
return ((low != other.low) || (high != other.high));
|
||||
}
|
||||
|
||||
bool contains(const Vector2& xz) const {
|
||||
return ((xz.x >= low.x) && (xz.x <= high.x) && (xz.y >= low.y) && (xz.y <= high.y));
|
||||
}
|
||||
|
||||
bool pointInRect(int x, int y) const {
|
||||
return ((x >= low.x) && (x <= high.x) && (y >= low.y) && (y <= high.y));
|
||||
}
|
||||
bool pointInRect(Vector2int16 point) const {
|
||||
return pointInRect(point.x, point.y);
|
||||
}
|
||||
|
||||
Vector2 size() const {
|
||||
return (high - low);
|
||||
}
|
||||
|
||||
Vector2 center() const {
|
||||
return (low + high) * 0.5;
|
||||
}
|
||||
|
||||
Location pointInBorder(const Vector2& point, float borderRatio);
|
||||
|
||||
Vector2 positionPoint(Location xLoc, Location yLoc) const;
|
||||
|
||||
Vector2 positionPoint(const Vector2& point, Location xLoc, Location yLoc) const;
|
||||
|
||||
Rect positionChild(const Rect& child, Location xLoc, Location yLoc) const;
|
||||
|
||||
Rect inset(int dx) {
|
||||
return Rect(low.x+dx, low.y+dx, high.x-dx, high.y-dx);
|
||||
}
|
||||
Rect inset(const Vector2int16& dd) {
|
||||
return Rect(low.x+dd.x, low.y+dd.y, high.x-dd.x, high.y-dd.y);
|
||||
}
|
||||
|
||||
Vector2 clamp(const Vector2& point) {
|
||||
return point.clamp(low, high);
|
||||
}
|
||||
|
||||
static const float BORDER_RATIO;
|
||||
static const float BORDER_RATIO_DRAG;
|
||||
static const float BORDER_RATIO_THIN;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
#pragma once
|
||||
|
||||
#include "Util/Rect.h"
|
||||
#include "rbx/Debug.h"
|
||||
#include "Util/Math.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Adorn;
|
||||
|
||||
class Region2 {
|
||||
public:
|
||||
class WeightedPoint {
|
||||
public:
|
||||
Vector2 point;
|
||||
float radius;
|
||||
|
||||
WeightedPoint()
|
||||
: point(Vector2::zero())
|
||||
, radius(0.0f)
|
||||
{}
|
||||
|
||||
WeightedPoint(const Vector2& point, const float radius)
|
||||
: point(point)
|
||||
, radius(radius)
|
||||
{}
|
||||
};
|
||||
|
||||
private:
|
||||
WeightedPoint owner;
|
||||
G3D::Array<WeightedPoint> others;
|
||||
|
||||
bool findCloserOther(const Vector2& point, const float slop) const;
|
||||
|
||||
public:
|
||||
void clearEmpty() {
|
||||
owner = WeightedPoint();
|
||||
others.fastClear();
|
||||
}
|
||||
|
||||
bool isEmpty() const {
|
||||
return (owner.radius <= 0.0f);
|
||||
}
|
||||
|
||||
Region2()
|
||||
{}
|
||||
|
||||
~Region2() {}
|
||||
|
||||
void setOwner(const WeightedPoint& _owner) {
|
||||
owner = _owner;
|
||||
}
|
||||
|
||||
void appendOther(const WeightedPoint& _other) {
|
||||
others.append(_other);
|
||||
}
|
||||
|
||||
bool contains(const Vector2& pos2d, const float slop) const;
|
||||
|
||||
static float getRelativeError(const Vector2& pos2d, const WeightedPoint& owner); // go through all owner points - find best one
|
||||
|
||||
static bool pointInRange(const Vector2& pos2d, const WeightedPoint& owner, const float slop);
|
||||
|
||||
static bool closerToOtherPoint( const Vector2& pos2d,
|
||||
const WeightedPoint& owner,
|
||||
const WeightedPoint& other,
|
||||
float slop);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
#pragma once
|
||||
|
||||
#include "G3D/Vector3.h"
|
||||
#include "G3D/CoordinateFrame.h"
|
||||
|
||||
namespace RBX {
|
||||
class Extents;
|
||||
|
||||
class Region3 {
|
||||
private:
|
||||
G3D::CoordinateFrame cframe;
|
||||
Vector3 size;
|
||||
void init(const Extents &extents);
|
||||
|
||||
public:
|
||||
Region3();
|
||||
Region3(const Vector3& min, const Vector3& max);
|
||||
explicit Region3(const Extents &extents);
|
||||
|
||||
~Region3() {}
|
||||
|
||||
const G3D::CoordinateFrame& getCFrame() const { return cframe; }
|
||||
const Vector3& getSize() const { return size; }
|
||||
|
||||
Vector3 minPos() const;
|
||||
Vector3 maxPos() const;
|
||||
|
||||
inline bool operator==(const Region3& other) const {
|
||||
return (size == other.size) && (cframe == other.cframe);
|
||||
}
|
||||
|
||||
inline bool operator!=(const Region3& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
#pragma once
|
||||
|
||||
#include "G3D/Vector3int16.h"
|
||||
#include "G3DCore.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Region3int16 {
|
||||
private:
|
||||
Vector3int16 minPos;
|
||||
Vector3int16 maxPos;
|
||||
|
||||
public:
|
||||
Region3int16()
|
||||
{
|
||||
}
|
||||
|
||||
Region3int16(const Vector3int16& min, const Vector3int16& max)
|
||||
: minPos(min)
|
||||
, maxPos(max)
|
||||
{
|
||||
}
|
||||
|
||||
const Vector3int16& getMinPos() const
|
||||
{
|
||||
return minPos;
|
||||
}
|
||||
|
||||
const Vector3int16& getMaxPos() const
|
||||
{
|
||||
return maxPos;
|
||||
}
|
||||
|
||||
bool operator==(const Region3int16& other) const
|
||||
{
|
||||
return (minPos == other.minPos) && (maxPos == other.maxPos);
|
||||
}
|
||||
|
||||
bool operator!=(const Region3int16& other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
bool contains(const Vector3int16& p) const
|
||||
{
|
||||
return
|
||||
static_cast<unsigned int>(p.x - minPos.x) <= static_cast<unsigned int>(maxPos.x - minPos.x) &&
|
||||
static_cast<unsigned int>(p.y - minPos.y) <= static_cast<unsigned int>(maxPos.y - minPos.y) &&
|
||||
static_cast<unsigned int>(p.z - minPos.z) <= static_cast<unsigned int>(maxPos.z - minPos.z);
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return minPos.x > maxPos.x || minPos.y > maxPos.y || minPos.z > maxPos.z;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
#pragma once
|
||||
|
||||
#include "Util/Vector3int32.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Region3int32 {
|
||||
private:
|
||||
Vector3int32 minPos;
|
||||
Vector3int32 maxPos;
|
||||
|
||||
public:
|
||||
Region3int32();
|
||||
Region3int32(const Vector3int32& min, const Vector3int32& max);
|
||||
|
||||
~Region3int32() {}
|
||||
|
||||
Vector3int32 getMinPos() const;
|
||||
Vector3int32 getMaxPos() const;
|
||||
|
||||
inline bool operator==(const Region3int32& other) const {
|
||||
return (minPos == other.minPos) && (maxPos == other.maxPos);
|
||||
}
|
||||
|
||||
inline bool operator!=(const Region3int32& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* RobloxGoogleAnalytics.h
|
||||
* Copyright (c) 2013 ROBLOX Corp. All rights reserved.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include <rbx/signal.h>
|
||||
|
||||
namespace RBX {
|
||||
// Singleton for tracking events across Studio using Google Analytics
|
||||
// to process the data. Events are sent using the Measurement Protocol:
|
||||
// https://developers.google.com/analytics/devguides/collection/protocol/v1
|
||||
//
|
||||
// All events are posted to the server asynchronously and any calls to
|
||||
// track data should return immediately.
|
||||
|
||||
#define GA_CATEGORY_GAME "Game"
|
||||
#define GA_CATEGORY_ACTION "Action"
|
||||
#define GA_CATEGORY_ERROR "Error"
|
||||
#define GA_CATEGORY_STUDIO "Studio"
|
||||
#define GA_CATEGORY_COUNTERS "Counters"
|
||||
#define GA_CATEGORY_RIBBONBAR "RibbonBar"
|
||||
#define GA_CATEGORY_SECURITY "Security"
|
||||
#define GA_CATEGORY_STUDIO_SETTINGS "StudioSettings"
|
||||
|
||||
// timing variables
|
||||
#define GA_CLIENT_START "ClientStartTime"
|
||||
|
||||
namespace RobloxGoogleAnalytics
|
||||
{
|
||||
static const std::string kGoogleAnalyticsBaseURL = "http://www.google-analytics.com/collect";
|
||||
|
||||
// Allow for easy initialization based on a lottery number.
|
||||
// Calls setCanUseAnalytics and init.
|
||||
void lotteryInit(const std::string &accountPropertyID, size_t maxThreadScheduleSize, int lotteryThreshold, const char * productName = NULL, int robloxAnalyticsLottery = -1, const std::string &sessionKey = "sessionID=");
|
||||
|
||||
// Must be called before using the singleton.
|
||||
void init(const std::string &accountPropertyID, size_t maxThreadScheduleSize, const char * productName = NULL);
|
||||
|
||||
bool isInitialized();
|
||||
|
||||
bool getCanUseAnalytics();
|
||||
void setCanUseAnalytics();
|
||||
|
||||
void setUserID(int userID);
|
||||
void setPlaceID(int placeID);
|
||||
|
||||
// Signal sent on each call to track an analytic.
|
||||
rbx::signal<void()>& analyticTrackedSignal();
|
||||
|
||||
void setExperimentVariation(const std::string& name, int value);
|
||||
|
||||
void trackEvent(
|
||||
const char *category,
|
||||
const char *action = "custom",
|
||||
const char *label = "none",
|
||||
int value = 0,
|
||||
bool sync = false);
|
||||
|
||||
void trackEventWithoutThrottling(
|
||||
const char *category,
|
||||
const char *action = "custom",
|
||||
const char *label = "none",
|
||||
int value = 0,
|
||||
bool sync = false);
|
||||
|
||||
void trackUserTiming(
|
||||
const char *category,
|
||||
const char *variable,
|
||||
int milliseconds,
|
||||
const char *label = "none",
|
||||
bool sync = false);
|
||||
|
||||
void sendEventRoblox(const char* category,
|
||||
const char* action = "custom",
|
||||
const char* label = "none",
|
||||
int value = 0,
|
||||
bool sync = false);
|
||||
|
||||
const std::string& getSessionId();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/G3DCore.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
// Represents rotations in angles
|
||||
class RotationAngle
|
||||
{
|
||||
public:
|
||||
RotationAngle()
|
||||
: value(0)
|
||||
, sin(0)
|
||||
, cos(1)
|
||||
{
|
||||
}
|
||||
|
||||
explicit RotationAngle(float angle)
|
||||
{
|
||||
float angleRad = angle * (G3D::pi() / 180.f);
|
||||
|
||||
value = angle;
|
||||
sin = sinf(angleRad);
|
||||
cos = cosf(angleRad);
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return value == 0.f;
|
||||
}
|
||||
|
||||
float getValue() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
float getSin() const
|
||||
{
|
||||
return sin;
|
||||
}
|
||||
|
||||
float getCos() const
|
||||
{
|
||||
return cos;
|
||||
}
|
||||
|
||||
bool operator==(const RotationAngle& other) const
|
||||
{
|
||||
return value == other.value;
|
||||
}
|
||||
|
||||
bool operator!=(const RotationAngle& other) const
|
||||
{
|
||||
return value != other.value;
|
||||
}
|
||||
|
||||
RotationAngle inverse() const
|
||||
{
|
||||
RotationAngle result;
|
||||
|
||||
result.value = -value;
|
||||
result.sin = -sin;
|
||||
result.cos = cos;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
RotationAngle combine(const RotationAngle& other) const
|
||||
{
|
||||
RotationAngle result;
|
||||
|
||||
result.value = value + other.value;
|
||||
result.sin = sin * other.cos + cos * other.sin;
|
||||
result.cos = cos * other.cos - sin * other.sin;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
float value;
|
||||
float sin;
|
||||
float cos;
|
||||
};
|
||||
|
||||
class Rotation2D
|
||||
{
|
||||
public:
|
||||
Rotation2D()
|
||||
{
|
||||
}
|
||||
|
||||
Rotation2D(const RotationAngle& angle, const Vector2& center)
|
||||
: angle(angle)
|
||||
, center(center)
|
||||
{
|
||||
}
|
||||
|
||||
const RotationAngle& getAngle() const
|
||||
{
|
||||
return angle;
|
||||
}
|
||||
|
||||
const Vector2& getCenter() const
|
||||
{
|
||||
return center;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return angle.empty();
|
||||
}
|
||||
|
||||
bool operator==(const Rotation2D& other) const
|
||||
{
|
||||
return angle == other.angle && center == other.center;
|
||||
}
|
||||
|
||||
bool operator!=(const Rotation2D& other) const
|
||||
{
|
||||
return angle != other.angle || center != other.center;
|
||||
}
|
||||
|
||||
Vector2 rotate(const Vector2& p) const
|
||||
{
|
||||
if (angle.empty())
|
||||
return p;
|
||||
|
||||
Vector2 pl = p - center;
|
||||
|
||||
return center + Vector2(
|
||||
pl.x * angle.getCos() - pl.y * angle.getSin(),
|
||||
pl.y * angle.getCos() + pl.x * angle.getSin());
|
||||
}
|
||||
|
||||
Rotation2D inverse() const
|
||||
{
|
||||
return Rotation2D(angle.inverse(), center);
|
||||
}
|
||||
|
||||
private:
|
||||
RotationAngle angle;
|
||||
Vector2 center;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user