Files
starruler-linux/source/game/scripts/bind_general.cpp
T
2018-07-17 14:15:37 +02:00

1363 lines
42 KiB
C++

#ifdef _MSC_VER
#include <Windows.h>
#endif
#include "binds.h"
#include "constants.h"
#include "str_util.h"
#include "obj/object.h"
#include "util/random.h"
#include "scripts/context_cache.h"
#include "../source/as_scriptengine.h"
#include "../source/as_scriptobject.h"
#include "../../as_addons/include/scriptarray.h"
#include "main/initialization.h"
#include "main/references.h"
#include "main/logging.h"
#include "main/tick.h"
#include "main/version.h"
#include "main/game_platform.h"
#include "util/format.h"
#include "files.h"
#include <algorithm>
#include "main/console.h"
#include "network/network_manager.h"
#include <string>
#include <limits.h>
#include <limits>
#ifdef __GNUC__
#include <unistd.h>
#endif
extern unsigned reportVersion;
extern bool isLoadedGame, gameEnding;
extern int SAVE_VERSION, START_VERSION;
int FindCubicRoots(const double coeff[4], double x[3]);
int FindQuarticRoots(const double coeff[5], double x[4]);
const bool _TRUE = true;
const bool _FALSE = false;
const int _INT_MAX = INT_MAX;
const int _INT_MIN = INT_MIN;
const unsigned _UINT_MAX = UINT_MAX;
const float _F_INFINITY = std::numeric_limits<float>::infinity();
const double _D_INFINITY = std::numeric_limits<double>::infinity();
const std::string _BUILD_NAME(BUILD_VERSION);
#ifdef NSTEAM
const bool isSteamBuild = false;
#else
const bool isSteamBuild = true;
#endif
extern double frameTime_s;
namespace scripts {
double getExactTime() {
return devices.driver->getAccurateTime();
}
double getGameTime() {
return devices.driver->getGameTime();
}
double getFrameGameTime() {
return frameTime_s;
}
double getFrameTime() {
return devices.driver->getFrameTime();
}
double getFrameLength() {
return realFrameLen;
}
unsigned getBasicTime() {
return unsigned(devices.driver->getTime());
}
double getGameSpeed() {
return devices.driver->getGameSpeed();
}
void setGameSpeed(double speed) {
if(devices.network->isClient) {
scripts::throwException("Cannot set game speed on client.");
return;
}
if(devices.network->isServer) {
if(devices.network->isSerializing())
return;
devices.network->setGameSpeed(speed);
}
return devices.driver->setGameSpeed(speed);
}
static bool mpClient() {
return devices.network->isClient;
}
static bool mpServer() {
return devices.network->isServer;
}
static bool isTestScripts() {
return game_state == GS_Test_Scripts;
}
static bool isModdedGame() {
if(devices.mods.activeMods.size() == 0)
return true;
return devices.mods.activeMods.size() > 1 || devices.mods.activeMods[0] != devices.mods.getMod("base");
}
static unsigned mpGalaxiesInFlight() {
return devices.network->galaxiesInFlight;
}
static bool mpIsSerializing() {
return devices.network->isSerializing();
}
static void mpConnect(const std::string& address, int port, const std::string& password) {
devices.network->connect(address, port, password, true);
}
static void mpDisconnect() {
devices.network->disconnect();
devices.network->resetNetState();
}
static bool mpIsConnected() {
return devices.network->isClient && devices.network->connected;
}
static bool mpIsConnecting() {
return devices.network->isClient && devices.network->client && !devices.network->connected;
}
static void mpSetPassword(const std::string& pwd) {
devices.network->setPassword(pwd);
}
template<class T>
T sqr(T x) {
return x*x;
}
static std::string localize(const std::string& str, bool requireHash, bool doUnescape) {
return devices.locale.localize(str, requireHash, doUnescape);
}
static std::string getStackTrace(bool verbose) {
return getStackTrace(asGetActiveContext(), verbose);
}
static void logExc(bool verbose) {
auto* ctx = asGetActiveContext();
if(ctx) {
error("Script Exception: %s", ctx->GetExceptionString());
error(getStackTrace(asGetActiveContext(), verbose));
}
}
static bool scriptFuncSplit(const std::string& input, std::string* name, CScriptArray* arguments, bool strip) {
std::vector<std::string> args;
if(!funcSplit(input, *name, args, strip))
return false;
arguments->Resize(args.size());
for(unsigned i = 0, cnt = args.size(); i < cnt; ++i)
*(std::string*)arguments->At(i) = args[i];
return true;
}
#define a(n) const std::string& a##n
#define v(n) a##n
std::string format_1(const std::string& text, a(1)) {
return format(text.c_str(), v(1));
}
std::string format_2(const std::string& text, a(1), a(2)) {
return format(text.c_str(), v(1), v(2));
}
std::string format_3(const std::string& text, a(1), a(2), a(3)) {
return format(text.c_str(), v(1), v(2), v(3));
}
std::string format_4(const std::string& text, a(1), a(2), a(3), a(4)) {
return format(text.c_str(), v(1), v(2), v(3), v(4));
}
std::string format_5(const std::string& text, a(1), a(2), a(3), a(4), a(5)) {
return format(text.c_str(), v(1), v(2), v(3), v(4), v(5));
}
std::string format_n(const std::string& text, CScriptArray* arguments) {
FormatArg argbuf[32];
unsigned argn = arguments->GetSize();
for(unsigned i = 0; i < argn && i < 32; ++i)
argbuf[i] = FormatArg(*(const std::string*)arguments->At(i));
std::string output;
format(output, text.c_str(), argn, argbuf);
return output;
}
template<class T>
T absceil(T a) {
return a > 0 ? ceil(a) : floor(a);
}
template<class T>
T absfloor(T a) {
return a > 0 ? floor(a) : ceil(a);
}
template<class T>
T scr_max(T a, T b) {
return a < b ? b : a;
}
template<class T, class S>
T scr_mix_max(T a, S b) {
return a < (T)b ? (T)b : a;
}
template<class T>
T scr_min(T a, T b) {
return b < a ? b : a;
}
template<class T, class S>
T scr_mix_min(T a, S b) {
return (T)b < a ? (T)b : a;
}
template<class T>
T clamp(T val, T _min, T _max) {
if(val < _min)
return _min;
if(val > _max)
return _max;
return val;
}
void QuarticRoots(double a, double b, double c, double d, double e, CScriptArray& out) {
double coeffs[5] = {e,d,c,b,a};
double roots[4];
int rootCount = FindQuarticRoots(coeffs, roots);
out.Resize((asUINT)rootCount);
for(int i = 0; i < rootCount; ++i)
*(double*)out.At(i) = roots[i];
}
const double straightDot = 0.99999;
//Special case of quadratic root solution for newtonian motion
double lowerQuadratic(double a, double b, double c) {
double det = b*b - 4.0*a*c;
if(det < 0.0)
return 1000.0;
double d = sqrt(det);
double r = (-b - d) / (2.0 * a);
if(r > 0.0)
return r;
else
return 1000.0;
}
double newtonArrivalTime(double a, const vec3d& p, const vec3d& v) {
if(a < 1.0e-4 || a != a)
a = 1.0e-4;
double dist = p.getLength();
double speed = v.getLengthSQ();
if(speed < 0.004)
return sqrt(4.0 * dist / a);
speed = sqrt(speed);
double velDot = 1.0;
if(dist > 0.001)
velDot = v.dot(p) / (dist * speed);
if(velDot > straightDot) {
//We must accelerate up to the target speed before hitting the point
// d = 1/2 a * t^2 (where t = v/a)
double accelDist = 0.5 * speed * speed / a;
if(accelDist > dist) {
return lowerQuadratic(-a, 2.0 * speed, dist - accelDist);
}
else {
//We have enough distance
//Accelerate until we must decelerate
double totalTime = sqrt(4.0 * (dist - accelDist) / a);
return totalTime + (speed / a);
}
}
else if(velDot < -straightDot) {
double deccelTime = speed / a;
double deccelDist = deccelTime * speed * 0.5;
//We either need to slow down, or accelerate to a maximum velocity
if(deccelDist < dist) {
double totalTime = sqrt(4.0 * (deccelDist + dist) / a);
return totalTime - (speed / a);
}
else {
return deccelTime + sqrt(4.0 * (deccelDist - dist) / a);
}
}
else {
vec3d linearVel = p.normalized(speed * velDot);
vec3d latVel = v - linearVel;
vec3d zero;
double aToward = 0.7;
double rangeLow = 0.0001, rangeHigh = 0.9999;
double t = 0, leastErr = 99999999.0;
for(unsigned i = 0; i < 15; ++i) {
double aLat = sqrt(1.0 - (aToward * aToward));
double tToward = newtonArrivalTime(aToward * a, p, linearVel);
double tLat = newtonArrivalTime(aLat * a, zero, latVel);
double err = abs(tToward - tLat);
if(err < leastErr) {
leastErr = err;
t = (tToward + tLat) * 0.5;
}
if(err < 0.02)
break;
else if(tToward > tLat) {
rangeLow = aToward;
aToward = (rangeLow + rangeHigh) * 0.5;
}
else {
rangeHigh = aToward;
aToward = (rangeLow + rangeHigh) * 0.5;
}
}
return t;
}
}
void throwScriptError(const std::string& str) {
scripts::throwException(str.c_str());
}
void _print(bool v) {
if(v)
print("true");
else
print("false");
}
void _print(int v) {
std::string str =toString<int>(v);
print(str);
}
void _print(unsigned v) {
std::string str =toString<unsigned>(v);
print(str);
}
void _print(float v) {
std::string str =toString<float>(v);
print(str);
}
void _print(double v) {
std::string str =toString<double>(v);
print(str);
}
void _print() {
//Does nothing
}
void _print(void* ptr, int typeId) {
auto* eng = asGetActiveContext()->GetEngine();
auto* type = eng->GetTypeInfoById(typeId);
if(ptr != nullptr && (typeId & asTYPEID_SCRIPTOBJECT))
type = ((asIScriptObject*)ptr)->GetObjectType();
print("%s at %p", type->GetName(), ptr);
}
std::string strPointer(void* ptr, int typeId) {
auto* eng = asGetActiveContext()->GetEngine();
auto* type = eng->GetTypeInfoById(typeId);
if(ptr != nullptr && (typeId & asTYPEID_SCRIPTOBJECT))
type = ((asIScriptObject*)ptr)->GetObjectType();
std::stringstream ss;
ss << '[';
ss << type->GetName();
ss << " at 0x";
ss << std::hex << (size_t)ptr;
ss << ']';
return ss.str();
}
std::string dbgStr(void* ptr, int typeId) {
auto* eng = asGetActiveContext()->GetEngine();
return getScriptVariable(ptr, typeId, true, eng);
}
void dbgOut(void* ptr, int typeId, const std::string& prefix) {
auto* eng = asGetActiveContext()->GetEngine();
std::string err;
if(!prefix.empty()) {
err += prefix;
err += " ";
}
err += eng->GetTypeDeclaration(typeId);
err += " ";
err += getScriptVariable(ptr, typeId, true, eng);
error(err);
}
void dbgAll(const std::string& prefix) {
if(!prefix.empty()) {
error( "########################################");
error(prefix);
}
error(getStackVariables(asGetActiveContext()));
if(!prefix.empty()) {
error( "########################################");
}
}
int getRefCnt(void* ptr, int typeId) {
if(ptr != nullptr && (typeId & asTYPEID_SCRIPTOBJECT))
return (int)((asCScriptObject*)ptr)->GetRefCount();
return -1;
}
long long dbgAddress(void* ptr, int typeId) {
return (long long)ptr;
}
#ifdef WIN_MODE
bool isWindows = true;
#else
bool isWindows = false;
#endif
#ifdef LIN_MODE
bool isLinux = true;
#else
bool isLinux = false;
#endif
#ifdef MAC_MODE
bool isMac = true;
#else
bool isMac = false;
#endif
static std::string archName = ARCH_NAME;
static unsigned archBits = ARCH_BITS;
template<class T>
static T wrap_toNumber(const std::string& str) {
return toNumber<T>(str);
}
static bool wrap_toBool(const std::string& str) {
return toBool(str);
}
static vec3d toVec3d(const std::string& str) {
vec3d v;
int count = sscanf(str.c_str(), " ( %lf , %lf , %lf", &v.x, &v.y, &v.z);
if(count == 3)
return v;
else
return vec3d();
}
static void addConsComm(std::string& name, asIScriptObject* obj) {
Manager* man = getActiveManager();
asIScriptFunction* conCommandFunc = (asIScriptFunction*)man->engine->GetUserData(EDID_consoleCommand);
if(!obj || !conCommandFunc) {
throwException("Unbound function called.");
return;
}
obj->AddRef();
Console::ConsoleFunction f;
f.line = [obj,man,conCommandFunc](std::string& line) -> bool {
Call cl = man->call(conCommandFunc);
cl.setObject(obj);
cl.push(&line);
cl.call();
return true;
};
f.destruct = [obj]() -> bool {
obj->Release();
return true;
};
console.addCommand(name, f);
}
static bool strIsWhitespace(const std::string& str, const std::string& substr) {
return str.find_first_not_of(" \t\n\r") == std::string::npos;
}
static bool strContains(const std::string& str, const std::string& substr) {
return str.find(substr) != std::string::npos;
}
static bool strContainsNC(const std::string& str, const std::string& substr) {
return strfind_nocase(str, substr) != -1;
}
static bool startsWith(const std::string& str, const std::string& substr) {
if(substr.size() > str.size())
return false;
return str.compare(0, substr.size(), substr) == 0;
}
static bool endsWith(const std::string& str, const std::string& substr) {
if(substr.size() > str.size())
return false;
return str.compare(str.size() - substr.size(), substr.size(), substr) == 0;
}
static bool startsWithNC(const std::string& str, const std::string& substr) {
return streq_nocase(str, substr, 0, substr.size());
}
static bool endsWithNC(const std::string& str, const std::string& substr) {
return streq_nocase(str, substr, str.size() - substr.size(), substr.size());
}
static bool strEq_s(const std::string& str, const std::string& substr, int index) {
if(substr.size() > str.size())
return false;
return str.compare(index, substr.size(), substr) == 0;
}
static bool strEq_sl(const std::string& str, const std::string& substr, int index, int length) {
if(substr.size() > str.size())
return false;
return str.compare(index, length, substr) == 0;
}
static bool strEqNC_s(const std::string& str, const std::string& substr, int index) {
return streq_nocase(str, substr, index);
}
static bool strEqNC_sl(const std::string& str, const std::string& substr, int index, int length) {
return streq_nocase(str, substr, index, length);
}
static std::string getCurModule() {
auto* ctx = asGetActiveContext();
auto* func = ctx->GetFunction(ctx->GetCallstackSize() - 1);
return std::string(func->GetModuleName());
}
void copyToClipboard(const std::string& str) {
devices.driver->setClipboard(str);
}
std::string readFromClipboard() {
return devices.driver->getClipboard();
}
static void toggleConsole() {
console.toggle();
}
static double angleDiff(double a, double b) {
double diff = a - b;
if(diff < -pi) {
do {
diff += twopi;
} while(diff < -pi);
}
else if(diff > pi) {
do {
diff -= twopi;
} while(diff > pi);
}
return diff;
}
static bool isCloudActive() {
return devices.cloud != nullptr;
}
static void inviteCloudFriend() {
if(devices.cloud)
devices.cloud->inviteFriend();
}
static std::string getCloudNickname() {
if(devices.cloud == nullptr)
return "";
return devices.cloud->getNickname();
}
static bool inCloudLobby() {
if(devices.cloud == nullptr)
return false;
return devices.cloud->getLobby() != 0;
}
static void enterCloudQueue(const std::string& type, unsigned players, const std::string& version) {
if(devices.cloud == nullptr)
return;
devices.cloud->enterQueue(type, players, version);
}
static bool cloudQueueReady() {
if(devices.cloud == nullptr)
return false;
return devices.cloud->queueReady();
}
static bool cloudQueueRequest() {
if(devices.cloud == nullptr)
return false;
return devices.cloud->queueRequest();
}
static void cloudQLeave() {
if(devices.cloud)
devices.cloud->leaveQueue();
}
static void cloudQAccept() {
if(devices.cloud)
devices.cloud->acceptQueue();
}
static void cloudQReject() {
if(devices.cloud)
devices.cloud->rejectQueue();
}
static double cloudQTime() {
if(devices.cloud == nullptr)
return 0;
return (double)devices.cloud->remainingTime() / 1000.0;
}
static unsigned cloudQPlayers() {
if(devices.cloud == nullptr)
return 0;
return devices.cloud->queueTotalPlayers();
}
static bool cloudInQ() {
if(devices.cloud == nullptr)
return false;
return devices.cloud->inQueue();
}
static bool cloudQWaiting(unsigned& ready, unsigned& cap) {
ready = 0;
cap = 0;
if(devices.cloud == nullptr)
return false;
return devices.cloud->queuePlayerWait(ready, cap);
}
void cloudCreateItem(const std::string& folder) {
if(!devices.cloud) return;
if(!isAccessible(folder)) return;
devices.cloud->createCloudItem(folder);
}
void cloudCloseItem() {
if(devices.cloud) devices.cloud->closeItem();
}
bool cloudItemReady() {
if(!devices.cloud)
return false;
return devices.cloud->isItemActive();
}
unsigned long long cloudItemID() {
if(!devices.cloud)
return 0;
return devices.cloud->getItemID();
}
void cloudItemTitle(const std::string& title) {
if(!devices.cloud) return;
devices.cloud->setItemTitle(title);
}
void cloudItemDesc(const std::string& desc) {
if(!devices.cloud) return;
devices.cloud->setItemDescription(desc);
}
void cloudItemFolder(const std::string& folder) {
if(!devices.cloud) return;
if(!isAccessible(folder)) return;
devices.cloud->setItemContents(folder);
}
void cloudItemImage(const std::string& image) {
if(!devices.cloud) return;
if(!isAccessible(image)) return;
devices.cloud->setItemImage(devices.mods.resolve(image));
}
void cloudItemTags(CScriptArray& sTags) {
if(!devices.cloud) return;
std::vector<std::string> tags;
tags.reserve(sTags.GetSize());
for(unsigned i = 0; i < sTags.GetSize(); ++i)
tags.push_back(*(std::string*)sTags.At(i));
devices.cloud->setItemTags(tags);
}
void cloudItemVisible() {
if(!devices.cloud) return;
devices.cloud->setItemVisibility();
}
void cloudItemCommit(const std::string& log) {
if(!devices.cloud) return;
devices.cloud->commitItem(log);
}
double cloudItemProgress() {
if(!devices.cloud)
return 0;
return devices.cloud->getUploadProgress();
}
bool cloudItemUploading() {
if(!devices.cloud)
return false;
return devices.cloud->isItemUpdating();
}
void cloudLegal() {
if(devices.cloud) devices.cloud->openURL("http://steamcommunity.com/sharedfiles/workshoplegalagreement");
}
#ifdef _MSC_VER
threads::threadreturn threadcall openURL(void* arg) {
std::string* pStr = (std::string*)arg;
ShellExecute(NULL, "open", pStr->c_str(), NULL, NULL, SW_SHOW);
delete pStr;
return 0;
}
#endif
static void openBrowser(const std::string& url) {
if(!startsWithNC(url, "http://") && !startsWithNC(url, "https://"))
return;
if(devices.cloud) {
devices.cloud->openURL(url);
return;
}
#ifdef __GNUC__
if(fork() == 0) {
execlp("xdg-open", "xdg-open", url.c_str(), (char*)nullptr);
exit(1);
}
#else
threads::createThread(openURL, new std::string(url));
#endif
}
static void openFileManager(const std::string& folder) {
if(!isDirectory(folder) || !isAccessible(folder))
return;
#ifdef __GNUC__
if(fork() == 0) {
execlp("xdg-open", "xdg-open", folder.c_str(), (char*)nullptr);
exit(1);
}
#else
threads::async([folder]() -> int {
ShellExecute(NULL, "explore", folder.c_str(), NULL, NULL, SW_SHOWNORMAL);
return 0;
});
#endif
}
#ifdef _DEBUG
static void scrAssert(void* ptr, int tid) {
assert(false);
}
#endif
static void dumpGC() {
auto* ctx = asGetActiveContext();
auto* eng = (asCScriptEngine*)ctx->GetEngine();
ENTERCRITICALSECTION(eng->gc.gcCritical);
for(unsigned i = 0, cnt = eng->gc.gcOldObjects.GetLength(); i < cnt; ++i) {
auto* type = eng->gc.gcOldObjects[i].type;
auto* mod = type->GetModule();
if(mod)
print("%s::%s", type->GetModule()->GetName(), type->GetName());
else
print("::%s", type->GetName());
}
for(unsigned i = 0, cnt = eng->gc.gcNewObjects.GetLength(); i < cnt; ++i) {
auto* type = eng->gc.gcNewObjects[i].type;
auto* mod = type->GetModule();
if(mod)
print("%s::%s", type->GetModule()->GetName(), type->GetName());
else
print("::%s", type->GetName());
}
LEAVECRITICALSECTION(eng->gc.gcCritical);
}
void RegisterGeneralBinds(bool server, bool shadow) {
//Debugging functions
bind("void print(const string &)", asFUNCTIONPR(print,(const std::string&),void));
bind("void info(const string &)", asFUNCTIONPR(info,(const std::string&),void));
bind("void warn(const string &)", asFUNCTIONPR(warn,(const std::string&),void));
bind("void error(const string &)", asFUNCTIONPR(error,(const std::string&),void));
bind("void throw(const string &)", asFUNCTION(throwScriptError));
bind("void dumpGC()", asFUNCTION(dumpGC));
bind("string getStackTrace(bool verbose = false)", asFUNCTIONPR(getStackTrace, (bool), std::string));
bind("string get___module__()", asFUNCTION(getCurModule));
bind("void openBrowser(const string& url)", asFUNCTION(openBrowser))
doc("Open a URI in the user's configured browser.", "URI to open.");
bind("void openFileManager(const string& folder)", asFUNCTION(openFileManager))
doc("Open a folder in the user's configured file manager.", "Folder to open.");
bindGlobal("uint errorVersion", &reportVersion)
doc("Value reported to Steam when an exception occurs.");
bind("bool hasDLC(const string& name)", asFUNCTION(hasDLC));
#ifdef _DEBUG
//Use temporarily while debugging to break from scripts
bind("void __break(?&)", asFUNCTION(scrAssert));
#endif
//Bind all the locales
{
Namespace ns("locale");
foreach(it, devices.locale.localizations)
bindGlobal(format("::string $1", it->first).c_str(), it->second);
}
//Platform detection
bindGlobal("bool isWindows", &isWindows);
bindGlobal("bool isLinux", &isLinux);
bindGlobal("bool isMac", &isMac);
bindGlobal("uint ArchBits", &archBits);
bindGlobal("string ArchName", &archName);
//Global game state
bindGlobal("bool isLoadedSave", &isLoadedGame);
bindGlobal("int SAVE_VERSION", &SAVE_VERSION);
bindGlobal("int START_VERSION", &START_VERSION);
bindGlobal("bool game_running", &game_running);
bindGlobal("bool game_ending", &gameEnding)
doc("True while the game is being cleaned up for exit.");
bindGlobal("bool inGalaxyCreation", &Object::GALAXY_CREATION);
//Maximums
bindGlobal("int INT_MAX", (void*)&_INT_MAX);
bindGlobal("int INT_MIN", (void*)&_INT_MIN);
bindGlobal("uint UINT_MAX", (void*)&_UINT_MAX);
bindGlobal("double INFINITY", (void*)&_D_INFINITY);
bindGlobal("float FLOAT_INFINITY", (void*)&_F_INFINITY);
bindGlobal("const string BUILD_VERSION", (void*)&_BUILD_NAME);
bindGlobal("const bool IS_STEAM_BUILD", (void*)&isSteamBuild);
//Engine detection
if(server) {
bindGlobal("bool isServer", (void*)&_TRUE);
bindGlobal("bool isClient", (void*)&_FALSE);
}
else {
bindGlobal("bool isServer", (void*)&_FALSE);
bindGlobal("bool isClient", (void*)&_TRUE);
}
if(shadow)
bindGlobal("bool isShadow", (void*)&_TRUE);
else
bindGlobal("bool isShadow", (void*)&_FALSE);
//Networking detection
bind("bool get_mpClient()", asFUNCTION(mpClient));
bind("bool get_mpServer()", asFUNCTION(mpServer));
bind("uint get_mpGalaxiesInFlight()", asFUNCTION(mpGalaxiesInFlight));
bind("bool get_mpIsSerializing()", asFUNCTION(mpIsSerializing));
bind("bool get_isScriptDebug()", asFUNCTION(isTestScripts));
bind("bool get_isModdedGame()", asFUNCTION(isModdedGame));
if(!server && !shadow) {
bind("void mpConnect(const string& address, int port = 2048, const string& password = \"\")", asFUNCTION(mpConnect));
bind("void mpDisconnect()", asFUNCTION(mpDisconnect));
bind("bool mpIsConnected()", asFUNCTION(mpIsConnected));
bind("bool mpIsConnecting()", asFUNCTION(mpIsConnecting));
bind("void mpSetPassword(const string& str)", asFUNCTION(mpSetPassword));
}
//Timing functions
bind("double getExactTime()", asFUNCTION(getExactTime))
doc("Returns nanosecond-accurate system time in seconds (slow).", "");
bind("double get_gameTime()", asFUNCTION(getGameTime))
doc("Returns the current game clock, updated periodically, in seconds.", "");
bind("double get_frameGameTime()", asFUNCTION(getFrameGameTime))
doc("Returns the current frame's game time, updated every frame, in seconds.", "");
bind("double get_frameTime()", asFUNCTION(getFrameTime))
doc("Returns the current frame time in seconds.", "");
bind("double get_frameLength()", asFUNCTION(getFrameLength))
doc("Returns the timespan represented by this frame in seconds.", "");
bind("uint get_systemTime()", asFUNCTION(getBasicTime))
doc("Returns millisecond-accurate system time in milliseconds.", "");
bind("double get_gameSpeed()", asFUNCTION(getGameSpeed));
bind("void set_gameSpeed(double speed)", asFUNCTION(setGameSpeed));
//Randomness
bind("double randomd()", asFUNCTIONPR(randomd, (), double))
doc("Generate a random double value.", "Random value from [0.0,1.0).");
bind("double randomd(double min, double max)", asFUNCTIONPR(randomd, (double, double), double))
doc("Generate a random double value.", "Minimum return.", "Maximum return (non-inclusive).", "Random value from [min,max).");
bind("float randomf()", asFUNCTIONPR(randomf, (), float))
doc("Generate a random float value.", "Random value from [0.f,1.f).");
bind("float randomf(float min, float max)", asFUNCTIONPR(randomf, (float, float), float))
doc("Generate a random float value.", "Minimum return.", "Maximum return (non-inclusive).", "Random value from [min,max).");
bind("uint randomi()", asFUNCTIONPR(randomi, (), unsigned))
doc("Generate a random uint value.", "Random value from 0 to UINT_MAX, inclusive.");
bind("int randomi(int min, int max)", asFUNCTIONPR(randomi, (int, int), int))
doc("Generate a random int value.", "Minimum return.", "Maximum return (inclusive).", "Random value from min to max, inclusive.");
bind("uint sysRandomi()", asFUNCTION(sysRandomi))
doc("Attempts to generate a high-quality random number. May fall back to a weaker random generation. Slow.", "");
bind("double normald(double min, double max, int steps = 3)", asFUNCTION(normald))
doc("Generates an approximately normally distributed value within a range, within an average return at the mean of min and max.", "Minimum return", "Maximum return (non-inclusive)", "Number of steps to iterate (more is a tighter distribution)", "Random value from [min,max)");
bind("vec3d random3d(double radius = 1.0)", asFUNCTIONPR(random3d, (double), vec3d))
doc("Generates a random 3D rotation, uniformly distributed over a sphere surface.",
"Radius of sphere.", "Random rotation vector.");
bind("vec2d random2d(double radius = 1.0)", asFUNCTIONPR(random2d, (double), vec2d))
doc("Generates a random 2D rotation, uniformly distributed over a circle's circumference.",
"Radius of circle.", "Random rotation vector.");
bind("vec3d random3d(double minRadius, double maxRadius)", asFUNCTIONPR(random3d, (double, double), vec3d))
doc("Generates a random 3D rotation, distributed evenly on the volume between minRadius and maxRadius.",
"Minimum radius of the vector.", "Maximum radius of the vector.", "Random rotation vector.");
bind("vec2d random2d(double minRadius, double maxRadius)", asFUNCTIONPR(random2d, (double, double), vec2d))
doc("Generates a random 2D rotation, distributed evenly on the area between minRadius and maxRadius.",
"Minimum radius of the vector.", "Maximum radius of the vector.", "Random rotation vector.");
//Math
bind("double sqr(double)", asFUNCTION(sqr<double>));
bind("float sqr(float)", asFUNCTION(sqr<float>));
bind("int sqr(int)", asFUNCTION(sqr<int>));
bind("double max(double, double)", asFUNCTION(scr_max<double>));
bind("int max(int, int)", asFUNCTION(scr_max<int>));
bind("uint max(uint, uint)", asFUNCTION(scr_max<unsigned>));
bind("uint max(uint, int)", asFUNCTION((scr_mix_max<unsigned,int>)));
bind("int max(int, uint)", asFUNCTION((scr_mix_max<int,unsigned>)));
bind("double min(double, double)", asFUNCTION(scr_min<double>));
bind("int min(int, int)", asFUNCTION(scr_min<int>));
bind("uint min(uint, uint)", asFUNCTION(scr_min<unsigned>));
bind("uint min(uint, int)", asFUNCTION((scr_mix_min<unsigned,int>)));
bind("int min(int, uint)", asFUNCTION((scr_mix_min<int,unsigned>)));
bind("double clamp(double value, double minimum, double maximum)", asFUNCTION(clamp<double>))
doc("Clamps the value to within the specified range.", "", "", "", "");
bind("int clamp(int value, int minimum, int maximum)", asFUNCTION(clamp<int>))
doc("Clamps the value to within the specified range.", "", "", "", "");
bind("int abs(int)", asFUNCTIONPR(abs, (int), int));
bind("double absceil(double)", asFUNCTION(absceil<double>));
bind("float absceil(float)", asFUNCTION(absceil<float>));
bind("double absfloor(double)", asFUNCTION(absfloor<double>));
bind("float absfloor(float)", asFUNCTION(absfloor<float>));
bind("double angleDiff(double a, double b)", asFUNCTION(angleDiff));
bind("void quarticRoots(double a, double b, double c, double d, double e, array<double>& roots)", asFUNCTION(QuarticRoots))
doc("Calculates all real roots of a quartic polynomial.", "Coefficient A", "Coefficient B", "Coefficient C", "Coefficient D", "Coefficient E", "Array to return roots in.");
bind("double newtonArrivalTime(double accel, const vec3d& offset, const vec3d& relativeVelocity)", asFUNCTION(newtonArrivalTime));
//String manipulation
bind("void u8append(string&, int)", asFUNCTION(u8append));
bind("int u8pos(const string &in, int, int)", asFUNCTION(u8pos));
bind("int u8get(const string &in, int)", asFUNCTION(u8get));
bind("void u8next(const string &in, int&, int&)", asFUNCTION(u8next));
bind("void u8prev(const string &in, int&, int&)", asFUNCTION(u8prev));
bind("int u8(int)", asFUNCTION(u8prev));
bind("void appendRoman(int num, const string& str)", asFUNCTIONPR(romanNumerals, (unsigned, std::string&), void));
bind("void toLowercase(string&)", asFUNCTION(toLowercase));
bind("void toUppercase(string&)", asFUNCTION(toUppercase));
bind("uint8 uppercase(uint8)", asFUNCTION(uppercase));
bind("uint8 lowercase(uint8)", asFUNCTION(lowercase));
bind("string unescape(const string&in)", asFUNCTION(unescape));
bind("string escape(const string&in)", asFUNCTION(escape));
bind("string localize(const string& in, bool requireHash = false, bool doUnescape = true)", asFUNCTION(localize));
bind("Color toColor(const string& in)", asFUNCTION(toColor));
bind("string toString(double num, uint precision = 5)", asFUNCTION(toString<double>));
bind("string toString(float num, uint precision = 5)", asFUNCTION(toString<float>));
bind("string toString(int num, uint precision = 5)", asFUNCTION(toString<int>));
bind("string toString(uint num, uint precision = 5)", asFUNCTION(toString<unsigned>));
bind("string toString(Color color)", asFUNCTION(toString<Color>));
bind("string standardize(double value, bool showIntegral = false, bool roundUp = false)", asFUNCTION(standardize));
bind("bool funcSplit(const string& input, string&out funcName, array<string>& arguments, bool strip = true)", asFUNCTION(scriptFuncSplit));
bind("float toFloat(const string &in str)", asFUNCTION(wrap_toNumber<float>));
bind("double toDouble(const string &in str)", asFUNCTION(wrap_toNumber<double>));
bind("int toInt(const string &in str)", asFUNCTION(wrap_toNumber<int>));
bind("uint toUInt(const string &in str)", asFUNCTION(wrap_toNumber<unsigned>));
bind("bool toBool(const string &in str)", asFUNCTION(wrap_toBool));
bind("vec3d toVec3d(const string &in str)", asFUNCTION(toVec3d))
doc("Parses a vec3d printed by vec3d::toString()", "", "");
//Add stuff to string
ClassBind str("string");
str.addExternMethod("bool toBool() const", asFUNCTION(wrap_toBool));
str.addExternMethod("int toInt() const", asFUNCTION(wrap_toNumber<int>));
str.addExternMethod("uint toUint() const", asFUNCTION(wrap_toNumber<unsigned>));
str.addExternMethod("float toFloat() const", asFUNCTION(wrap_toNumber<float>));
str.addExternMethod("double toDouble() const", asFUNCTION(wrap_toNumber<double>));
str.addExternMethod("vec3d toVec3d() const", asFUNCTION(toVec3d));
str.addExternMethod("string trimmed() const", asFUNCTIONPR(trim, (const std::string&), std::string));
str.addExternMethod("string& paragraphize(const string& parSep, const string& lineSep, bool startsParagraph = false)", asFUNCTION(paragraphize));
str.addExternMethod("string& replace(const string& replace, const string& with)", asFUNCTION(replace));
str.addExternMethod("string replaced(const string& replace, const string& with) const", asFUNCTION(replaced));
str.addExternMethod("bool isWhitespace() const", asFUNCTION(strIsWhitespace));
str.addExternMethod("bool contains(const string &in) const", asFUNCTION(strContains));
str.addExternMethod("bool contains_nocase(const string &in) const", asFUNCTION(strContainsNC));
str.addExternMethod("int findFirst_nocase(const string &in, uint start = 0) const", asFUNCTION(strfind_nocase));
str.addExternMethod("bool startswith(const string &in) const", asFUNCTION(startsWith));
str.addExternMethod("bool endswith(const string &in) const", asFUNCTION(endsWith));
str.addExternMethod("bool startswith_nocase(const string &in) const", asFUNCTION(startsWithNC));
str.addExternMethod("bool endswith_nocase(const string &in) const", asFUNCTION(endsWithNC));
str.addExternMethod("bool equals(const string &in, int start) const", asFUNCTION(strEq_s));
str.addExternMethod("bool equals(const string &in, int start, int length) const", asFUNCTION(strEq_sl));
str.addExternMethod("bool equals_nocase(const string &in, int start = 0) const", asFUNCTION(strEqNC_s));
str.addExternMethod("bool equals_nocase(const string &in, int start, int length) const", asFUNCTION(strEqNC_sl));
if(!server) {
bind("void setClipboard(const string &in)", asFUNCTION(copyToClipboard));
bind("string getClipboard()", asFUNCTION(readFromClipboard));
}
//Adding console commands
InterfaceBind ccomm("ConsoleCommand");
classdoc(ccomm, "Interface to implement for script console commands.");
asIScriptFunction* pConsoleCommand;
ccomm.addMethod("void execute(const string& args)", &pConsoleCommand)
doc("Called whenever this command was invoked, with all extra text passed to the command.", "Additional text passed after the command.");
getEngine()->SetUserData(pConsoleCommand, EDID_consoleCommand);
bind("void addConsoleCommand(const string& name, ConsoleCommand@ comm)", asFUNCTION(addConsComm))
doc("Registers a script console command.", "Command name to use the command.", "Instance of a command to call.");
bind("void toggleConsole()", asFUNCTION(toggleConsole));
//Constants
bindGlobal("const double e", (void*)&e);
bindGlobal("const double pi", (void*)&pi);
bindGlobal("const double twopi", (void*)&twopi);
//Special print functions are used by the console
//to print the resulting values of a command line
bind("void print(bool)", asFUNCTIONPR(_print, (bool), void));
bind("void print(int)", asFUNCTIONPR(_print, (int), void));
bind("void print(uint)", asFUNCTIONPR(_print, (unsigned), void));
bind("void print(float)", asFUNCTIONPR(_print, (float), void));
bind("void print(double)", asFUNCTIONPR(_print, (double), void));
bind("void print(const ?&)", asFUNCTIONPR(_print, (void*, int), void));
bind("void print()", asFUNCTIONPR(_print, (), void));
bind("void printTrace(bool verbose = false)", asFUNCTION(logExc));
bind("uint64 addressof(const ?&)", asFUNCTION(dbgAddress));
bind("string addrstr(const ?&)", asFUNCTION(strPointer));
bind("string dbgstr(const ?&)", asFUNCTION(dbgStr));
bind("void dbg(const ?&, const string& prefix = \"\")", asFUNCTION(dbgOut));
bind("void dbg(const string& prefix = \"\")", asFUNCTION(dbgAll));
bind("int refcnt(const ?&)", asFUNCTION(getRefCnt));
//Locale access
bind("string format(const string &in fmt, const string &in)", asFUNCTION(format_1))
doc("Replaces $n in fmt with the related argument.", "Format to use.", "$1", "Formatted string.");
bind("string format(const string &in fmt, const string &in, const string &in)", asFUNCTION(format_2))
doc("Replaces $n in fmt with the related argument.", "Format to use.", "$1", "$2", "Formatted string.");
bind("string format(const string &in fmt, const string &in, const string &in, const string &in)", asFUNCTION(format_3))
doc("Replaces $n in fmt with the related argument.", "Format to use.", "$1", "$2", "$3", "Formatted string.");
bind("string format(const string &in fmt, const string &in, const string &in, const string &in, const string &in)", asFUNCTION(format_4))
doc("Replaces $n in fmt with the related argument.", "Format to use.", "$1", "$2", "$3", "$4", "Formatted string.");
bind("string format(const string &in fmt, const string &in, const string &in, const string &in, const string &in, const string &in)", asFUNCTION(format_5))
doc("Replaces $n in fmt with the related argument.", "Format to use.", "$1", "$2", "$3", "$4", "$5", "Formatted string.");
bind("string format(const string &in fmt, const array<string>& args)", asFUNCTION(format_n))
doc("Replaces $n in fmt with the related argument.", "Format to use.", "Arguments.", "Formatted string.");
//Cloud stuff
{
Namespace ns("cloud");
bind("bool get_isActive()", asFUNCTION(isCloudActive));
bind("bool get_inLobby()", asFUNCTION(inCloudLobby));
bind("string getNickname()", asFUNCTION(getCloudNickname));
bind("void inviteFriend()", asFUNCTION(inviteCloudFriend));
bind("void enterQueue(const string& type, uint players, const string& version)", asFUNCTION(enterCloudQueue));
bind("bool get_isQueueReady()", asFUNCTION(cloudQueueReady));
bind("bool get_queueRequest()", asFUNCTION(cloudQueueRequest));
bind("bool get_inQueue()", asFUNCTION(cloudInQ));
bind("void leaveQueue()", asFUNCTION(cloudQLeave));
bind("void acceptQueue()", asFUNCTION(cloudQAccept));
bind("void rejectQueue()", asFUNCTION(cloudQReject));
bind("int queueTimer()", asFUNCTION(cloudQTime));
bind("uint get_queuePlayers()", asFUNCTION(cloudQPlayers));
bind("bool getQueuePlayerWait(uint &out ready, uint &out cap)", asFUNCTION(cloudQWaiting));
bind("void prepItem(const string& folder)", asFUNCTION(cloudCreateItem))
doc("Prepares an item for updating or creation. Wait a few frames for cloud::itemReady to be true.");
bind("void closeItem()", asFUNCTION(cloudCloseItem));
bind("bool get_itemReady()", asFUNCTION(cloudItemReady));
bind("uint64 get_itemID()", asFUNCTION(cloudItemID));
bind("void set_itemTitle(const string&)", asFUNCTION(cloudItemTitle));
bind("void set_itemDescription(const string&)", asFUNCTION(cloudItemDesc));
bind("void setItemContent(const string& folder)", asFUNCTION(cloudItemFolder));
bind("void setItemImage(const string& filename)", asFUNCTION(cloudItemImage));
bind("void setItemTags(array<string>& tags)", asFUNCTION(cloudItemTags));
bind("void setItemPublic()", asFUNCTION(cloudItemVisible));
bind("void commitItem(const string& changelog)", asFUNCTION(cloudItemCommit));
bind("double get_uploadProgress()", asFUNCTION(cloudItemProgress));
bind("bool get_isUploading()", asFUNCTION(cloudItemUploading));
bind("void openLegalPrompt()", asFUNCTION(cloudLegal));
}
//Key actions
EnumBind ka("KeyAction");
ka["KA_Pressed"] = os::KA_Pressed;
ka["KA_Released"] = os::KA_Released;
ka["KA_Repeated"] = os::KA_Repeated;
//Key constants
EnumBind kc("KeyCode");
for(unsigned int i = 0; i < 26; ++i) {
std::string keyName = "KEY_";
keyName.push_back(char('A' + i));
std::string logicalName = "KEY_LOGICAL_";
logicalName.push_back(char('A' + i));
kc[keyName] = os::KEY_A + i;
kc[logicalName] = devices.driver->getKeyForChar('A'+i);
}
kc["KEY_ESC"] = os::KEY_ESC;
kc["KEY_F1"] = os::KEY_F1;
kc["KEY_F2"] = os::KEY_F2;
kc["KEY_F3"] = os::KEY_F3;
kc["KEY_F4"] = os::KEY_F4;
kc["KEY_F5"] = os::KEY_F5;
kc["KEY_F6"] = os::KEY_F6;
kc["KEY_F7"] = os::KEY_F7;
kc["KEY_F8"] = os::KEY_F8;
kc["KEY_F9"] = os::KEY_F9;
kc["KEY_F10"] = os::KEY_F10;
kc["KEY_F11"] = os::KEY_F11;
kc["KEY_F12"] = os::KEY_F12;
kc["KEY_F13"] = os::KEY_F13;
kc["KEY_F14"] = os::KEY_F14;
kc["KEY_F15"] = os::KEY_F15;
kc["KEY_F16"] = os::KEY_F16;
kc["KEY_F17"] = os::KEY_F17;
kc["KEY_F18"] = os::KEY_F18;
kc["KEY_F19"] = os::KEY_F19;
kc["KEY_F20"] = os::KEY_F20;
kc["KEY_F21"] = os::KEY_F21;
kc["KEY_F22"] = os::KEY_F22;
kc["KEY_F23"] = os::KEY_F23;
kc["KEY_F24"] = os::KEY_F24;
kc["KEY_F25"] = os::KEY_F25;
kc["KEY_UP"] = os::KEY_UP;
kc["KEY_DOWN"] = os::KEY_DOWN;
kc["KEY_LEFT"] = os::KEY_LEFT;
kc["KEY_RIGHT"] = os::KEY_RIGHT;
kc["KEY_LSHIFT"] = os::KEY_LSHIFT;
kc["KEY_RSHIFT"] = os::KEY_RSHIFT;
kc["KEY_LCTRL"] = os::KEY_LCTRL;
kc["KEY_RCTRL"] = os::KEY_RCTRL;
kc["KEY_LALT"] = os::KEY_LALT;
kc["KEY_RALT"] = os::KEY_RALT;
kc["KEY_TAB"] = os::KEY_TAB;
kc["KEY_ENTER"] = os::KEY_ENTER;
kc["KEY_BACKSPACE"] = os::KEY_BACKSPACE;
kc["KEY_INSERT"] = os::KEY_INSERT;
kc["KEY_DEL"] = os::KEY_DEL;
kc["KEY_PAGEUP"] = os::KEY_PAGEUP;
kc["KEY_PAGEDOWN"] = os::KEY_PAGEDOWN;
kc["KEY_HOME"] = os::KEY_HOME;
kc["KEY_END"] = os::KEY_END;
kc["KEY_KP_0"] = os::KEY_KP_0;
kc["KEY_KP_1"] = os::KEY_KP_1;
kc["KEY_KP_2"] = os::KEY_KP_2;
kc["KEY_KP_3"] = os::KEY_KP_3;
kc["KEY_KP_4"] = os::KEY_KP_4;
kc["KEY_KP_5"] = os::KEY_KP_5;
kc["KEY_KP_6"] = os::KEY_KP_6;
kc["KEY_KP_7"] = os::KEY_KP_7;
kc["KEY_KP_8"] = os::KEY_KP_8;
kc["KEY_KP_9"] = os::KEY_KP_9;
kc["KEY_KP_DIVIDE"] = os::KEY_KP_DIVIDE;
kc["KEY_KP_MULTIPLY"] = os::KEY_KP_MULTIPLY;
kc["KEY_KP_SUBTRACT"] = os::KEY_KP_SUBTRACT;
kc["KEY_KP_ADD"] = os::KEY_KP_ADD;
kc["KEY_KP_DECIMAL"] = os::KEY_KP_DECIMAL;
kc["KEY_KP_EQUAL"] = os::KEY_KP_EQUAL;
kc["KEY_KP_ENTER"] = os::KEY_KP_ENTER;
kc["KEY_NUM_LOCK"] = os::KEY_NUM_LOCK;
kc["KEY_CAPS_LOCK"] = os::KEY_CAPS_LOCK;
kc["KEY_SCROLL_LOCK"] = os::KEY_SCROLL_LOCK;
kc["KEY_PAUSE"] = os::KEY_PAUSE;
kc["KEY_LSUPER"] = os::KEY_LSUPER;
kc["KEY_RSUPER"] = os::KEY_RSUPER;
kc["KEY_MENU"] = os::KEY_MENU;
}
};
int FindCubicRoots(const double coeff[4], double x[3]) {
/* Adjust coefficients */
double a1 = coeff[2] / coeff[3];
double a2 = coeff[1] / coeff[3];
double a3 = coeff[0] / coeff[3];
double Q = (a1 * a1 - 3 * a2) / 9;
double R = (2 * a1 * a1 * a1 - 9 * a1 * a2 + 27 * a3) / 54;
double Qcubed = Q * Q * Q;
double d = Qcubed - R * R;
/* Three real roots */
if (d>=0)
{
double theta = acos(R / sqrt(Qcubed));
double sqrtQ = sqrt(Q);
x[0] = -2 * sqrtQ * cos( theta / 3) - a1 / 3;
x[1] = -2 * sqrtQ * cos((theta + 2 * pi) / 3) - a1 / 3;
x[2] = -2 * sqrtQ * cos((theta + 4 * pi) / 3) - a1 / 3;
return (3);
}
/* One real root */
else
{
double e = pow(sqrt(-d) + fabs(R), 1. / 3.);
if (R > 0) e = -e;
x[0] = (e + Q / e) - a1 / 3.;
return (1);
}
}
int FindQuarticRoots(const double coeff[5], double x[4]) {
/* Adjust coefficients */
double a1 = coeff[3] / coeff[4];
double a2 = coeff[2] / coeff[4];
double a3 = coeff[1] / coeff[4];
double a4 = coeff[0] / coeff[4];
/* Reduce to solving cubic equation */
double q = a2 - a1*a1*3/8;
double r = a3 - a1*a2/2 + a1*a1*a1/8;
double s = a4 - a1*a3/4 + a1*a1*a2/16 - 3*a1*a1*a1*a1/256;
double coeff_cubic[4];
double roots_cubic[3];
double positive_root;
coeff_cubic[3] = 1;
coeff_cubic[2] = q/2;
coeff_cubic[1] = (q*q-4*s)/16;
coeff_cubic[0] = -r*r/64;
int nRoots = FindCubicRoots(coeff_cubic,roots_cubic);
for (int i=0; i<nRoots; i++)
if (roots_cubic[i]>0) {
positive_root = roots_cubic[i];
break; //ADDED
}
/* Reduce to solving two quadratic equations */
double k = sqrt(positive_root);
double l = 2*k*k + q/2 - r/(4*k);
double m = 2*k*k + q/2 + r/(4*k);
nRoots = 0;
if (k*k-l>0)
{
x[nRoots+0] = -k - sqrt(k*k-l) - a1/4;
x[nRoots+1] = -k + sqrt(k*k-l) - a1/4;
nRoots += 2;
}
if (k*k-m>0)
{
x[nRoots+0] = +k - sqrt(k*k-m) - a1/4;
x[nRoots+1] = +k + sqrt(k*k-m) - a1/4;
nRoots += 2;
}
return nRoots;
}