mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
GEEKING
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "Script/Script.h"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
extern const char* const sCoreScript;
|
||||
class CoreScript
|
||||
: public DescribedNonCreatable<CoreScript, BaseScript, sCoreScript, RBX::Reflection::ClassDescriptor::INTERNAL_LOCAL>
|
||||
{
|
||||
private:
|
||||
typedef DescribedNonCreatable<CoreScript, BaseScript, sCoreScript, RBX::Reflection::ClassDescriptor::INTERNAL_LOCAL> Super;
|
||||
Code code;
|
||||
|
||||
public:
|
||||
CoreScript();
|
||||
|
||||
static boost::optional<ProtectedString> fetchSource(const std::string& name);
|
||||
|
||||
virtual Code requestCode(ScriptInformationProvider* scriptInfoProvider=NULL);
|
||||
|
||||
virtual void extraErrorReporting(lua_State *thread);
|
||||
|
||||
protected:
|
||||
// Instance
|
||||
/*override*/ void onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8Tree/Instance.h"
|
||||
#include "V8Tree/Service.h"
|
||||
#include "script/ThreadRef.h"
|
||||
#include "script/ScriptContext.h"
|
||||
|
||||
struct lua_State;
|
||||
struct lua_Debug;
|
||||
struct Table;
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class Script;
|
||||
class ModuleScript;
|
||||
class DataModel;
|
||||
|
||||
namespace Scripting
|
||||
{
|
||||
class ScriptDebugger;
|
||||
|
||||
enum BreakOnErrorMode
|
||||
{
|
||||
BreakOnErrorMode_Never = 0,
|
||||
BreakOnErrorMode_AllExceptions,
|
||||
BreakOnErrorMode_UnhandledExceptions
|
||||
};
|
||||
|
||||
enum ExecutionMode
|
||||
{
|
||||
ExecutionMode_Continue = 0,
|
||||
ExecutionMode_Break
|
||||
};
|
||||
|
||||
struct ISpecialBreakpoint
|
||||
{
|
||||
virtual ~ISpecialBreakpoint() {}
|
||||
virtual bool hitTest(lua_State* L, lua_Debug *ar) = 0;
|
||||
lua_State* baseThread;
|
||||
};
|
||||
|
||||
extern const char* const sDebuggerManager;
|
||||
// Contains all data related to Lua debugging of Scripts
|
||||
class DebuggerManager
|
||||
: public DescribedNonCreatable<DebuggerManager, Instance, sDebuggerManager, Reflection::ClassDescriptor::INTERNAL_LOCAL, Security::LocalUser>
|
||||
{
|
||||
typedef DescribedNonCreatable<DebuggerManager, Instance, sDebuggerManager, Reflection::ClassDescriptor::INTERNAL_LOCAL, Security::LocalUser> Super;
|
||||
public:
|
||||
typedef boost::unordered_map<const Instance*, ScriptDebugger*> Debuggers;
|
||||
private:
|
||||
bool enabled;
|
||||
Debuggers debuggers;
|
||||
|
||||
rbx::signals::connection errorSignalConnection;
|
||||
rbx::signals::connection descendantAddedSignalConnection;
|
||||
|
||||
typedef boost::unordered_map<const Instance*, boost::shared_ptr<ScriptDebugger> > UnaddedDebuggers;
|
||||
UnaddedDebuggers unaddedDebuggers;
|
||||
|
||||
typedef boost::unordered_map<const lua_State*, ScriptDebugger*> DebuggersLookup;
|
||||
DebuggersLookup debuggersLookup;
|
||||
|
||||
RBX::DataModel *dataModel;
|
||||
BreakOnErrorMode breakOnErrorMode;
|
||||
|
||||
boost::scoped_ptr<ISpecialBreakpoint> specialBreakpoint;
|
||||
ExecutionMode executionMode;
|
||||
std::list<Lua::WeakThreadRef> pausedThreads, resumingPausedThreads, errorThreads;
|
||||
bool resuming;
|
||||
bool scriptAutoResume;
|
||||
|
||||
public:
|
||||
DebuggerManager();
|
||||
~DebuggerManager();
|
||||
|
||||
static DebuggerManager& singleton();
|
||||
|
||||
void setDataModel(RBX::DataModel *pDataModel);
|
||||
RBX::DataModel* getDataModel();
|
||||
|
||||
void enableDebugging();
|
||||
bool getEnabled() const { return enabled; }
|
||||
|
||||
BreakOnErrorMode getBreakOnErrorMode() const { return breakOnErrorMode; }
|
||||
void setBreakOnErrorMode(BreakOnErrorMode mode);
|
||||
|
||||
static Reflection::Variant readWatchValue(std::string expression, int stackFrame, lua_State* L);
|
||||
|
||||
const Debuggers& getDebuggers()
|
||||
{
|
||||
return debuggers;
|
||||
}
|
||||
shared_ptr<const Instances> getDebuggers_Reflection();
|
||||
|
||||
ScriptDebugger* findDebugger(lua_State* L);
|
||||
ScriptDebugger* findDebugger(Instance* script);
|
||||
|
||||
shared_ptr<ScriptDebugger> addDebugger(Instance* script);
|
||||
shared_ptr<Instance> addDebugger_Reflection(shared_ptr<Instance> script);
|
||||
void addDebugger(shared_ptr<ScriptDebugger> debugger);
|
||||
|
||||
void populateForLookup(lua_State* L, ScriptDebugger* debugger);
|
||||
|
||||
void pause();
|
||||
void resume();
|
||||
void stepOver();
|
||||
void stepInto();
|
||||
void stepOut();
|
||||
|
||||
void reset();
|
||||
void setScriptAutoResume(bool state) { scriptAutoResume = state; }
|
||||
|
||||
static void hook(lua_State* L, lua_Debug *ar);
|
||||
|
||||
rbx::signal<void(shared_ptr<Instance>)> debuggerAdded;
|
||||
rbx::signal<void(shared_ptr<Instance>)> debuggerRemoved;
|
||||
|
||||
protected:
|
||||
/*override*/ bool askForbidChild(const Instance* instance) const;
|
||||
/*override*/ void verifyAddChild(const Instance* newChild) const;
|
||||
/*override*/ void onChildAdded(Instance* child);
|
||||
/*override*/ void onChildRemoved(Instance* child);
|
||||
/*override*/ void onChildChanged(Instance* instance, const PropertyChanged& event);
|
||||
|
||||
void addScriptDebugger(Instance* instance);
|
||||
void onErrorSignal(lua_State* L);
|
||||
void onHook(lua_State* L, lua_Debug *ar);
|
||||
|
||||
void addUnaddedDebuggerForAddedDescendant(shared_ptr<RBX::Instance> instance);
|
||||
};
|
||||
|
||||
class DebuggerBreakpoint;
|
||||
class DebuggerWatch;
|
||||
|
||||
extern const char* const sScriptDebugger;
|
||||
// Debugs an RBX::Script
|
||||
class ScriptDebugger
|
||||
: public DescribedCreatable<ScriptDebugger, Instance, sScriptDebugger, Reflection::ClassDescriptor::PERSISTENT_HIDDEN, Security::LocalUser>
|
||||
{
|
||||
public:
|
||||
typedef boost::unordered_map<int, DebuggerBreakpoint*> Breakpoints;
|
||||
typedef std::vector<DebuggerWatch*> Watches;
|
||||
struct PausedThreadData;
|
||||
typedef boost::unordered_map<long, PausedThreadData> PausedThreads;
|
||||
private:
|
||||
typedef DescribedCreatable<ScriptDebugger, Instance, sScriptDebugger, Reflection::ClassDescriptor::PERSISTENT_HIDDEN, Security::LocalUser> Super;
|
||||
|
||||
Breakpoints breakpoints;
|
||||
Watches watches;
|
||||
|
||||
boost::scoped_ptr<ISpecialBreakpoint> specialBreakpoint;
|
||||
|
||||
shared_ptr<Instance> script;
|
||||
rbx::signals::scoped_connection scriptStartedConnection;
|
||||
rbx::signals::scoped_connection scriptStoppedConnection;
|
||||
rbx::signals::scoped_connection scriptParentChangedConnection;
|
||||
rbx::signals::scoped_connection scriptClonedConnection;
|
||||
Lua::WeakThreadRef rootThread; // The root thread of script. Set when the Script starts and reset when it stops
|
||||
|
||||
typedef boost::function<void(lua_State* L, lua_Debug *ar)> HookFunction;
|
||||
HookFunction hookFunction; // used to overload the hook function
|
||||
|
||||
Lua::WeakThreadRef pausedThread; // the thread that a breakpoint hit
|
||||
Lua::WeakThreadRef errorThread; // the thread that has error
|
||||
lua_Debug *breakpointHookData; // set for a short period of time during the hook when we encounter a breakpoint
|
||||
void* globalRawScriptPtr;
|
||||
Table* prevFuncTable;
|
||||
void* prevRawScriptPtr;
|
||||
int currentLine; // the current line when a breakpoint is hit
|
||||
bool ignoreDebuggerBreak; // whether to ignore breakpoint at the current line
|
||||
long currentThreadID;
|
||||
PausedThreads pausedThreads;
|
||||
bool rootThreadResumed;
|
||||
|
||||
public:
|
||||
ScriptDebugger()
|
||||
:currentLine(0)
|
||||
,breakpointHookData(NULL)
|
||||
,globalRawScriptPtr(NULL)
|
||||
,prevFuncTable(NULL)
|
||||
,prevRawScriptPtr(NULL)
|
||||
,ignoreDebuggerBreak(false)
|
||||
,currentThreadID(0)
|
||||
,rootThreadResumed(false)
|
||||
{}
|
||||
ScriptDebugger(Instance& script);
|
||||
~ScriptDebugger();
|
||||
|
||||
Instance* getScript() const { return script.get(); }
|
||||
|
||||
void setScript(Script* value);
|
||||
void setScript(ModuleScript* value);
|
||||
|
||||
std::string getScriptPath() const;
|
||||
void setScriptPath(std::string scriptPath);
|
||||
|
||||
void setIgnoreDebuggerBreak(bool state) { ignoreDebuggerBreak = state; }
|
||||
|
||||
DebuggerBreakpoint* findBreakpoint(int line);
|
||||
shared_ptr<DebuggerBreakpoint> setBreakpoint(int line);
|
||||
shared_ptr<Instance> setBreakpoint_Reflection(int line);
|
||||
const Breakpoints& getBreakpoints()
|
||||
{
|
||||
return breakpoints;
|
||||
}
|
||||
shared_ptr<const Instances> getBreakpoints_Reflection();
|
||||
|
||||
shared_ptr<DebuggerWatch> addWatch(std::string expression);
|
||||
shared_ptr<Instance> addWatch_Reflection(std::string expression);
|
||||
const Watches& getWatches()
|
||||
{
|
||||
return watches;
|
||||
}
|
||||
shared_ptr<const Instances> getWatches_Reflection();
|
||||
Reflection::Variant getWatchValue(DebuggerWatch* watch, int stackFrame = 0);
|
||||
Reflection::Variant getWatchValue_Reflection(shared_ptr<Instance> watch);
|
||||
|
||||
Reflection::Variant getKeyValue(std::string key, int stackFrame);
|
||||
|
||||
bool isDebugging() const
|
||||
{
|
||||
return !rootThread.empty();
|
||||
}
|
||||
|
||||
bool isPaused() const;
|
||||
|
||||
bool hasError() const
|
||||
{
|
||||
return !errorThread.empty();
|
||||
}
|
||||
|
||||
int getCurrentLine() const
|
||||
{
|
||||
return currentLine;
|
||||
}
|
||||
void pause();
|
||||
void resume();
|
||||
void resumeTo(int line);
|
||||
void stepOver();
|
||||
void stepInto();
|
||||
void stepOut();
|
||||
|
||||
struct FunctionInfo
|
||||
{
|
||||
boost::shared_ptr<RBX::Instance> script;
|
||||
int frame;
|
||||
std::string name;
|
||||
std::string what;
|
||||
std::string namewhat;
|
||||
std::string short_src;
|
||||
int currentline;
|
||||
int linedefined;
|
||||
int lastlinedefined;
|
||||
};
|
||||
typedef std::vector<FunctionInfo> Stack;
|
||||
Stack getStack();
|
||||
shared_ptr<const Reflection::ValueArray> getStack_Reflection();
|
||||
shared_ptr<const Reflection::ValueMap> getLocals(int stackIndex);
|
||||
shared_ptr<const Reflection::ValueMap> getUpvalues(int stackIndex);
|
||||
shared_ptr<const Reflection::ValueMap> getGlobals();
|
||||
void setLocal(std::string name, Reflection::Variant value, int stackFrame = 0);
|
||||
void setUpvalue(std::string name, Reflection::Variant value, int stackFrame = 0);
|
||||
void setGlobal(std::string name, Reflection::Variant value);
|
||||
|
||||
void handleError(lua_State* L);
|
||||
void updateHook();
|
||||
|
||||
ScriptContext::Result resumeThread(lua_State* L, bool evalLineHookForCurrentLine = false);
|
||||
bool handleHook(lua_State* L, lua_Debug *ar);
|
||||
bool onLineHook(lua_State* L, lua_Debug *ar);
|
||||
void debuggerBreak(lua_State* L, lua_Debug *ar);
|
||||
|
||||
struct PausedThreadData
|
||||
{
|
||||
int pausedLine;
|
||||
Lua::WeakThreadRef thread;
|
||||
|
||||
bool hasError;
|
||||
Stack callStack;
|
||||
std::string errorMessage;
|
||||
|
||||
PausedThreadData()
|
||||
:hasError(false)
|
||||
,pausedLine(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
const PausedThreads& getPausedThreads() { return pausedThreads; }
|
||||
|
||||
bool isPausedThread(long threadID);
|
||||
bool isErrorThread(long threadID);
|
||||
|
||||
bool isRootThread(long threadID);
|
||||
bool isRootThreadResumed() { return rootThreadResumed; }
|
||||
|
||||
void setCurrentThread(long threadID);
|
||||
long getCurrentThread() { return currentThreadID; }
|
||||
|
||||
rbx::signal<void(int)> encounteredBreak;
|
||||
rbx::signal<void()> resuming;
|
||||
|
||||
rbx::signal<void(shared_ptr<Instance>)> breakpointAdded;
|
||||
rbx::signal<void(shared_ptr<Instance>)> breakpointRemoved;
|
||||
rbx::signal<void(shared_ptr<Instance>)> watchAdded;
|
||||
rbx::signal<void(shared_ptr<Instance>)> watchRemoved;
|
||||
rbx::signal<void(int, std::string, Stack)> scriptErrorDetected;
|
||||
|
||||
protected:
|
||||
/*override*/ bool askForbidChild(const Instance* instance) const;
|
||||
/*override*/ void verifySetParent(const Instance* newParent) const;
|
||||
/*override*/ void verifyAddChild(const Instance* newChild) const;
|
||||
/*override*/ void onChildAdded(Instance* child);
|
||||
/*override*/ void onChildRemoved(Instance* child);
|
||||
|
||||
private:
|
||||
void onScriptStarting(lua_State* L);
|
||||
void onScriptStopped();
|
||||
void onScriptParentChanged(shared_ptr<RBX::Instance> newParent);
|
||||
void onScriptCloned(boost::shared_ptr<Instance> clonedScript);
|
||||
bool shouldBreak(DebuggerBreakpoint* bp, lua_State* L);
|
||||
bool hasDifferentScriptInstances(lua_State* L);
|
||||
void handleError(std::string errorMessage, const Stack& stack = Stack());
|
||||
void setScript(Instance* value);
|
||||
boost::shared_ptr<ScriptDebugger> createClone(boost::shared_ptr<Instance> clonedScript);
|
||||
|
||||
template<class R>
|
||||
void withPausedThreadHook(lua_State* L, lua_Debug *ar, boost::function<R(lua_State* L, lua_Debug *ar)> f, R& r, shared_ptr<std::string>& error);
|
||||
|
||||
// TODO: template specialization for R=void
|
||||
template<class R>
|
||||
R withPausedThread(boost::function<R(lua_State* L, lua_Debug *ar)> f);
|
||||
static shared_ptr<Reflection::ValueMap> readLocals(int stackIndex, lua_State* L);
|
||||
static shared_ptr<Reflection::ValueMap> readUpvalues(int stackIndex, lua_State* L);
|
||||
static shared_ptr<Reflection::ValueMap> readGlobals(lua_State* L);
|
||||
static Stack readStack(lua_State* L);
|
||||
static RBX::Instance* getScriptForLuaState(lua_State* L);
|
||||
static void updateRootThread(ScriptDebugger* scriptDebugger, lua_State *L);
|
||||
static void setLuaHook(ScriptDebugger* scriptDebugger, int hookMask, lua_State *L);
|
||||
};
|
||||
|
||||
extern const char* const sDebuggerBreakpoint;
|
||||
class DebuggerBreakpoint
|
||||
: public DescribedCreatable<DebuggerBreakpoint, Instance, sDebuggerBreakpoint, Reflection::ClassDescriptor::PERSISTENT_HIDDEN, Security::LocalUser>
|
||||
{
|
||||
bool enabled;
|
||||
int line;
|
||||
std::string condition;
|
||||
public:
|
||||
DebuggerBreakpoint();
|
||||
DebuggerBreakpoint(int line);
|
||||
~DebuggerBreakpoint();
|
||||
|
||||
int getLine() const { return line; }
|
||||
|
||||
bool isEnabled() const { return enabled; }
|
||||
|
||||
const std::string& getCondition() const { return condition; }
|
||||
|
||||
static Reflection::BoundProp<bool> prop_Enabled;
|
||||
static Reflection::BoundProp<std::string> prop_Condition;
|
||||
|
||||
protected:
|
||||
/*override*/ void verifySetParent(const Instance* newParent) const;
|
||||
/*override*/ bool askForbidChild(const Instance* instance) const { return true; }
|
||||
/*override*/ void verifyAddChild(const Instance* newChild) const
|
||||
{
|
||||
throw std::runtime_error("DebuggerBreakpoint can have no children");
|
||||
}
|
||||
private:
|
||||
void setLine(int line);
|
||||
static Reflection::BoundProp<int> prop_Line_Data;
|
||||
|
||||
};
|
||||
|
||||
extern const char* const sDebuggerWatch;
|
||||
class DebuggerWatch
|
||||
: public DescribedCreatable<DebuggerWatch, Instance, sDebuggerWatch, Reflection::ClassDescriptor::PERSISTENT, Security::LocalUser>
|
||||
{
|
||||
std::string expression;
|
||||
public:
|
||||
DebuggerWatch() {}
|
||||
DebuggerWatch(std::string expression);
|
||||
const std::string& getCondition() const { return expression; }
|
||||
void checkExpressionSyntax();
|
||||
|
||||
const std::string& getExpression() const { return expression; }
|
||||
|
||||
static Reflection::BoundProp<std::string> prop_Expression;
|
||||
|
||||
protected:
|
||||
/*override*/ void verifySetParent(const Instance* newParent) const;
|
||||
/*override*/ bool askForbidChild(const Instance* instance) const { return true; }
|
||||
/*override*/ void verifyAddChild(const Instance* newChild) const
|
||||
{
|
||||
throw std::runtime_error("DebuggerWatch can have no children");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "boost/function.hpp"
|
||||
#include "reflection/Type.h"
|
||||
|
||||
struct lua_State;
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class BaseScript;
|
||||
|
||||
namespace Scripts
|
||||
{
|
||||
typedef boost::function<void(shared_ptr<const Reflection::Tuple> results)> SuccessHandler;
|
||||
typedef boost::function<void(const char* message, const char* callStack, shared_ptr<BaseScript> source, int line)> ErrorHandler;
|
||||
struct Continuations
|
||||
{
|
||||
SuccessHandler successHandler;
|
||||
ErrorHandler errorHandler;
|
||||
bool empty() const
|
||||
{
|
||||
return successHandler.empty() && errorHandler.empty();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace Lua
|
||||
{
|
||||
class Continuations
|
||||
{
|
||||
public:
|
||||
Continuations(const Scripts::Continuations& eh);
|
||||
Continuations() {}
|
||||
boost::function<void(lua_State*)> success; // called when the thread exits via ScriptContext::resume
|
||||
boost::function<void(lua_State*)> error; // called when the thread errors via ScriptContext::resume
|
||||
private:
|
||||
static void onSuccessHandler(lua_State* thread, Scripts::SuccessHandler handler);
|
||||
static void onErrorHandler(lua_State* thread, Scripts::ErrorHandler handler);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/RunStateOwner.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class BaseScript;
|
||||
class ModuleScript;
|
||||
|
||||
// Interface for Instances that turn in-game Scripts on and off
|
||||
// Implementations can add/remove the script from ScriptContext
|
||||
class RBXInterface IScriptFilter
|
||||
{
|
||||
friend class BaseScript;
|
||||
protected:
|
||||
// If script should run - pass back the IScriptOwner who should run it, otherwise NULL
|
||||
virtual bool scriptShouldRun(BaseScript* script) = 0;
|
||||
};
|
||||
|
||||
extern const char *const sRuntimeScriptService;
|
||||
|
||||
class RuntimeScriptService
|
||||
: public DescribedNonCreatable<RuntimeScriptService, Instance, sRuntimeScriptService, Reflection::ClassDescriptor::INTERNAL_LOCAL>
|
||||
, public Service
|
||||
{
|
||||
private:
|
||||
typedef DescribedNonCreatable<RuntimeScriptService, Instance, sRuntimeScriptService, Reflection::ClassDescriptor::INTERNAL_LOCAL> Super;
|
||||
|
||||
public:
|
||||
RuntimeScriptService():isRunning(false)
|
||||
{
|
||||
}
|
||||
|
||||
void runScript(BaseScript* script);
|
||||
void releaseScript(BaseScript* script);
|
||||
|
||||
protected:
|
||||
virtual void onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider);
|
||||
private:
|
||||
rbx::signals::scoped_connection runTransitionConnection;
|
||||
std::set<weak_ptr<BaseScript> > pendingScripts; // holds Scripts that are waiting for "Run"
|
||||
std::set<weak_ptr<BaseScript> > runningScripts;
|
||||
|
||||
bool isRunning;
|
||||
|
||||
void onRunTransition(RunTransition event)
|
||||
{
|
||||
onRunState(event.newState);
|
||||
}
|
||||
void onRunState(RunState state);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
#pragma once
|
||||
|
||||
#include "reflection/Function.h"
|
||||
#include "script/LuaAtomicClasses.h"
|
||||
#include "script/LuaEnum.h"
|
||||
#include "script/ThreadRef.h"
|
||||
#include "script/LuaInstanceBridge.h"
|
||||
#include "rbx/make_shared.h"
|
||||
#include "rbx/DenseHash.h"
|
||||
#include "util/ProtectedString.h"
|
||||
#include "util/PhysicalProperties.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
// Utility function that expands a variant to a strongly-typed value
|
||||
template<typename R, typename F>
|
||||
R withVariantValue(const Reflection::Variant& value, F f)
|
||||
{
|
||||
if (value.isType<void>())
|
||||
return f();
|
||||
|
||||
if (value.isType<bool>())
|
||||
return f(value.cast<bool>());
|
||||
|
||||
if (value.isType<int>())
|
||||
return f(value.cast<int>());
|
||||
|
||||
if (value.isType<long>())
|
||||
return f(value.cast<long>());
|
||||
|
||||
if (value.isType<float>())
|
||||
return f(value.cast<float>());
|
||||
|
||||
if (value.isType<double>())
|
||||
return f(value.cast<double>());
|
||||
|
||||
if (value.isType<std::string>())
|
||||
return f(value.cast<std::string>());
|
||||
|
||||
if (value.isType<RBX::ProtectedString>())
|
||||
return f(value.cast<RBX::ProtectedString>());
|
||||
|
||||
if (value.isType< shared_ptr<Instance> >())
|
||||
return f(value.cast<shared_ptr<Instance> >());
|
||||
|
||||
if (const Reflection::EnumDescriptor* desc = Reflection::EnumDescriptor::lookupDescriptor(value.type()))
|
||||
{
|
||||
const Reflection::EnumDescriptor::Item* item = desc->lookup(value);
|
||||
if (item == NULL)
|
||||
throw RBX::runtime_error("Invalid value for enum %s", desc->name.c_str());
|
||||
return f(*item);
|
||||
}
|
||||
|
||||
if (value.isType<Lua::WeakFunctionRef>())
|
||||
return f(value.cast<Lua::WeakFunctionRef>());
|
||||
|
||||
if (value.isType<shared_ptr<const Reflection::ValueArray> >())
|
||||
return f(value.cast<shared_ptr<const Reflection::ValueArray> >());
|
||||
|
||||
if (value.isType<shared_ptr<const Reflection::ValueMap> >())
|
||||
return f(value.cast<shared_ptr<const Reflection::ValueMap> >());
|
||||
|
||||
if (value.isType<shared_ptr<const Reflection::ValueTable> >())
|
||||
return f(value.cast<shared_ptr<const Reflection::ValueTable> >());
|
||||
|
||||
if (value.isType<shared_ptr<const Instances> >())
|
||||
return f(value.cast<shared_ptr<const Instances> >());
|
||||
|
||||
if (value.isType<shared_ptr<const Reflection::Tuple> >())
|
||||
return f(value.cast<shared_ptr<const Reflection::Tuple> >());
|
||||
|
||||
if (value.isType< shared_ptr<Lua::GenericFunction> >())
|
||||
return f(value.cast< shared_ptr<Lua::GenericFunction> >());
|
||||
|
||||
if (value.isType< shared_ptr<Lua::GenericAsyncFunction> >())
|
||||
return f(value.cast< shared_ptr<Lua::GenericAsyncFunction> >());
|
||||
|
||||
if (value.isType<G3D::Vector3int16>())
|
||||
return f(value.cast<G3D::Vector3int16>());
|
||||
if (value.isType<G3D::Vector2int16>())
|
||||
return f(value.cast<G3D::Vector2int16>());
|
||||
if (value.isType<G3D::Vector3>())
|
||||
return f(value.cast<G3D::Vector3>());
|
||||
if (value.isType<RBX::Vector2>())
|
||||
return f(value.cast<G3D::Vector2>());
|
||||
if (value.isType<G3D::Rect2D>())
|
||||
return f(value.cast<G3D::Rect2D>());
|
||||
if (value.isType<PhysicalProperties>())
|
||||
return f(value.cast<PhysicalProperties>());
|
||||
if (value.isType<RBX::RbxRay>())
|
||||
return f(value.cast<RBX::RbxRay>());
|
||||
if (value.isType<G3D::CoordinateFrame>())
|
||||
return f(value.cast<G3D::CoordinateFrame>());
|
||||
if (value.isType<G3D::Color3>())
|
||||
return f(value.cast<G3D::Color3>());
|
||||
if (value.isType<BrickColor>())
|
||||
return f(value.cast<BrickColor>());
|
||||
if (value.isType<RBX::Region3>())
|
||||
return f(value.cast<RBX::Region3>());
|
||||
if( value.isType<RBX::Region3int16>())
|
||||
return f(value.cast<RBX::Region3int16>());
|
||||
if (value.isType<UDim>())
|
||||
return f(value.cast<UDim>());
|
||||
if (value.isType<UDim2>())
|
||||
return f(value.cast<UDim2>());
|
||||
if (value.isType<Faces>())
|
||||
return f(value.cast<Faces>());
|
||||
if (value.isType<Axes>())
|
||||
return f(value.cast<Axes>());
|
||||
if (value.isType<CellID>())
|
||||
return f(value.cast<CellID>());
|
||||
if (value.isType<ContentId>())
|
||||
return f(value.cast<ContentId>());
|
||||
|
||||
if (value.isType<const Reflection::PropertyDescriptor*>())
|
||||
return f(*value.cast<const Reflection::PropertyDescriptor*>());
|
||||
|
||||
if (value.isType<rbx::signals::connection>())
|
||||
return f(value.cast<rbx::signals::connection>());
|
||||
|
||||
if (value.isType<NumberSequence>())
|
||||
return f(value.cast<NumberSequence>());
|
||||
if (value.isType<ColorSequence>())
|
||||
return f(value.cast<ColorSequence>());
|
||||
if (value.isType<NumberRange>())
|
||||
return f(value.cast<NumberRange>());
|
||||
if (value.isType<NumberSequenceKeypoint>())
|
||||
return f(value.cast<NumberSequenceKeypoint>());
|
||||
if (value.isType<ColorSequenceKeypoint>())
|
||||
return f(value.cast<ColorSequenceKeypoint>());
|
||||
|
||||
RBXASSERT(0);
|
||||
return f();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace Lua {
|
||||
|
||||
class LuaArguments : public Reflection::FunctionDescriptor::Arguments
|
||||
{
|
||||
typedef DenseHashMap<const void*, bool> TablesCollection;
|
||||
static bool getRec(lua_State *L, int luaIndex, Reflection::Variant& value, bool treatNilAsMissing, TablesCollection* visitedTables = NULL);
|
||||
|
||||
const int offset;
|
||||
lua_State * const L;
|
||||
public:
|
||||
LuaArguments(lua_State *L, int offset):L(L),offset(offset) {}
|
||||
|
||||
virtual size_t size() const {
|
||||
return lua_gettop(L) - 1;
|
||||
}
|
||||
|
||||
// Gets all arguments from the stack and puts them into the ValueArray
|
||||
static shared_ptr<Reflection::Tuple> getValues(lua_State* L)
|
||||
{
|
||||
int argCount = lua_gettop(L);
|
||||
|
||||
shared_ptr<Reflection::Tuple> args(rbx::make_shared<Reflection::Tuple>(argCount));
|
||||
|
||||
for (int i = 0; i<argCount; ++i)
|
||||
{
|
||||
Reflection::Variant& v = args->values.at(i);
|
||||
bool success = RBX::Lua::LuaArguments::get(L, i+1, v, false);
|
||||
RBXASSERT(success);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
static int pushTuple(const Reflection::Tuple& arguments, lua_State* L)
|
||||
{
|
||||
return pushValues(arguments.values, L);
|
||||
}
|
||||
|
||||
// pushes all the values from the ValueArray onto the stack
|
||||
static int pushValues(const Reflection::ValueArray& arguments, lua_State* L)
|
||||
{
|
||||
int argCount = 0;
|
||||
Reflection::ValueArray::const_iterator end = arguments.end();
|
||||
for (Reflection::ValueArray::const_iterator iter = arguments.begin(); iter != end; ++iter)
|
||||
{
|
||||
argCount += push(*iter, L);
|
||||
}
|
||||
return argCount;
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
||||
// Implemenent virtual functions
|
||||
//
|
||||
// Place the value for the requested parameter in "value".
|
||||
//
|
||||
// index: 1-based index into the argument list
|
||||
// value: the value to set. If index >= size(), then value is unchanged
|
||||
/*implement*/ bool getVariant(int index, Reflection::Variant& value) const {
|
||||
const int luaIndex = index + offset;
|
||||
RBXASSERT(luaIndex>0);
|
||||
return get(L, luaIndex, value, true);
|
||||
}
|
||||
/*implement*/ bool getLong(int index, long& value) const
|
||||
{
|
||||
// All numbers in Lua are double, so just call the double version of get
|
||||
double v;
|
||||
if (getDouble(index, v))
|
||||
{
|
||||
value = G3D::iRound(v);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/*implement*/ bool getDouble(int index, double& value) const;
|
||||
/*implement*/ bool getObject(int index, shared_ptr<Reflection::DescribedBase>& value) const;
|
||||
/*implement*/ bool getBool(int index, bool& value) const;
|
||||
/*implement*/ bool getString(int index, std::string& value) const;
|
||||
/*implement*/ bool getVector3(int index, Vector3& value) const;
|
||||
/*implement*/ bool getRegion3(int index, Region3& value) const;
|
||||
/*implement*/ bool getVector3int16(int index, Vector3int16& value) const;
|
||||
/*implement*/ bool getRegion3int16(int index, Region3int16& value) const;
|
||||
/*implement*/ bool getRect(int index, Rect2D& value) const;
|
||||
/*implement*/ bool getPhysicalProperties(int index, PhysicalProperties& value) const;
|
||||
/*implement*/ bool getEnum(int index, const Reflection::EnumDescriptor& desc, int& value) const;
|
||||
//
|
||||
//////////////////////////////////////
|
||||
|
||||
// Gets a value from the Lua stack. Returns false if no value is found
|
||||
static bool get(lua_State *L, int luaIndex, Reflection::Variant& value, bool treatNilAsMissing);
|
||||
template<class _InIt>
|
||||
static int pushArray(_InIt _First, _InIt _Last, lua_State * const L) {
|
||||
lua_createtable(L, _Last - _First, 0);
|
||||
unsigned int i = 0;
|
||||
while (_First!=_Last)
|
||||
{
|
||||
int count = push(*_First, L);
|
||||
RBXASSERT(count == 1); // If not 1, then what do we do?
|
||||
lua_rawseti(L, -2, ++i);
|
||||
++_First;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int push(const Reflection::Variant& value, lua_State * const L);
|
||||
|
||||
static int pushReturnValue(const Reflection::Variant& value, lua_State * const L);
|
||||
static shared_ptr<Reflection::Tuple> convertToReturnValues(const Reflection::Variant& value);
|
||||
};
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,402 @@
|
||||
#pragma once
|
||||
|
||||
#include "Lua/LuaBridge.h"
|
||||
#include "util/G3DCore.h"
|
||||
#include "g3d/Color3.h"
|
||||
#include "g3d/CoordinateFrame.h"
|
||||
#include "g3d/Vector3.h"
|
||||
#include "g3d/Vector3int16.h"
|
||||
#include "RbxG3D/RbxRay.h"
|
||||
#include "Util/BrickColor.h"
|
||||
#include "Util/UDim.h"
|
||||
#include "Util/Region3.h"
|
||||
#include "Util/Region3int16.h"
|
||||
#include "Util/Faces.h"
|
||||
#include "Util/Axes.h"
|
||||
#include "Util/CellID.h"
|
||||
#include "util/PhysicalProperties.h"
|
||||
#include "v8datamodel/NumberSequence.h"
|
||||
#include "v8datamodel/ColorSequence.h"
|
||||
#include "v8datamodel/NumberRange.h"
|
||||
|
||||
namespace RBX { namespace Lua {
|
||||
|
||||
class CoordinateFrameBridge : public Bridge<G3D::CoordinateFrame>
|
||||
{
|
||||
friend class Bridge< G3D::CoordinateFrame >;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L);
|
||||
|
||||
static void pushCoordinateFrame(lua_State *L, const G3D::CoordinateFrame& CF)
|
||||
{
|
||||
pushNewObject(L, CF);
|
||||
}
|
||||
private:
|
||||
static int newCoordinateFrame(lua_State *L);
|
||||
static int fromEulerAnglesXYZ(lua_State *L);
|
||||
static int fromAxisAngle(lua_State *L);
|
||||
static int on_add(lua_State *L);
|
||||
static int on_sub(lua_State *L);
|
||||
static int on_mul(lua_State *L);
|
||||
static int on_inverse(lua_State *L);
|
||||
static int on_lerp(lua_State *L);
|
||||
|
||||
// Implementation of G3D::CoordinateFrame help functions
|
||||
static int on_toWorldSpace(lua_State *L);
|
||||
static int on_toObjectSpace(lua_State *L);
|
||||
static int on_pointToWorldSpace(lua_State *L);
|
||||
static int on_pointToObjectSpace(lua_State *L);
|
||||
static int on_vectorToWorldSpace(lua_State *L);
|
||||
static int on_vectorToObjectSpace(lua_State *L);
|
||||
static int on_toEulerAnglesXYZ(lua_State *L);
|
||||
static int on_components(lua_State *L);
|
||||
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class PhysicalPropertiesBridge : public Bridge<PhysicalProperties>
|
||||
{
|
||||
friend class Bridge<PhysicalProperties>;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L);
|
||||
|
||||
static void pushPhysicalProperties(lua_State *L, const PhysicalProperties& v)
|
||||
{
|
||||
if (v.getCustomEnabled() == true)
|
||||
{
|
||||
pushNewObject(L, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushnil(L);
|
||||
}
|
||||
}
|
||||
private:
|
||||
static int newPhysicalProperties(lua_State *L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class Rect2DBridge : public Bridge<G3D::Rect2D>
|
||||
{
|
||||
friend class Bridge< G3D::Rect2D >;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L);
|
||||
|
||||
static void pushRect2D(lua_State *L, const G3D::Rect2D& v)
|
||||
{
|
||||
pushNewObject(L, v);
|
||||
}
|
||||
private:
|
||||
static int newRect2D(lua_State *L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class Region3Bridge : public Bridge<RBX::Region3>
|
||||
{
|
||||
friend class Bridge< RBX::Region3 >;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L) ;
|
||||
|
||||
static void pushRegion3(lua_State *L, const RBX::Region3& v)
|
||||
{
|
||||
pushNewObject(L, v);
|
||||
}
|
||||
private:
|
||||
static int newRegion3(lua_State *L);
|
||||
static int expandToGrid(lua_State *L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class Region3int16Bridge : public Bridge<RBX::Region3int16>
|
||||
{
|
||||
friend class Bridge< RBX::Region3int16 >;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L);
|
||||
|
||||
static void pushRegion3int16(lua_State *L, const RBX::Region3int16& v)
|
||||
{
|
||||
pushNewObject(L, v);
|
||||
}
|
||||
private:
|
||||
static int newRegion3int16(lua_State *L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class Vector3Bridge : public Bridge<G3D::Vector3>
|
||||
{
|
||||
friend class Bridge< G3D::Vector3 >;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L);
|
||||
|
||||
static void pushVector3(lua_State *L, const G3D::Vector3& v)
|
||||
{
|
||||
pushNewObject(L, v);
|
||||
}
|
||||
private:
|
||||
static int newVector3(lua_State *L);
|
||||
static int newVector3FromNormalId(lua_State *L);
|
||||
static int newVector3FromAxis(lua_State *L);
|
||||
static int on_add(lua_State *L);
|
||||
static int on_sub(lua_State *L);
|
||||
static int on_mul(lua_State *L);
|
||||
static int on_div(lua_State *L);
|
||||
static int on_unm(lua_State *L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class Vector3int16Bridge : public Bridge<G3D::Vector3int16>
|
||||
{
|
||||
friend class Bridge< G3D::Vector3int16 >;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L);
|
||||
|
||||
static void pushVector3int16(lua_State *L, const G3D::Vector3int16& v)
|
||||
{
|
||||
pushNewObject(L, v);
|
||||
}
|
||||
private:
|
||||
static int newVector3int16(lua_State *L);
|
||||
static int on_add(lua_State *L);
|
||||
static int on_sub(lua_State *L);
|
||||
static int on_mul(lua_State *L);
|
||||
static int on_div(lua_State *L);
|
||||
static int on_unm(lua_State *L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class RbxRayBridge : public Bridge<RBX::RbxRay>
|
||||
{
|
||||
friend class Bridge< RBX::RbxRay >;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L);
|
||||
|
||||
static void pushRay(lua_State *L, const RBX::RbxRay& v)
|
||||
{
|
||||
pushNewObject(L, v);
|
||||
}
|
||||
private:
|
||||
static int newRbxRay(lua_State *L);
|
||||
//static int on_add(lua_State *L);
|
||||
//static int on_sub(lua_State *L);
|
||||
//static int on_mul(lua_State *L);
|
||||
//static int on_div(lua_State *L);
|
||||
//static int on_unm(lua_State *L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
|
||||
class Vector2Bridge : public Bridge<RBX::Vector2>
|
||||
{
|
||||
friend class Bridge< RBX::Vector2 >;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L);
|
||||
|
||||
static void pushVector2(lua_State *L, const RBX::Vector2& v)
|
||||
{
|
||||
pushNewObject(L, v);
|
||||
}
|
||||
private:
|
||||
static int newVector2(lua_State *L);
|
||||
static int on_add(lua_State *L);
|
||||
static int on_sub(lua_State *L);
|
||||
static int on_mul(lua_State *L);
|
||||
static int on_div(lua_State *L);
|
||||
static int on_unm(lua_State *L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class Vector2int16Bridge : public Bridge<RBX::Vector2int16>
|
||||
{
|
||||
friend class Bridge< RBX::Vector2int16 >;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L);
|
||||
|
||||
static void pushVector2int16(lua_State *L, const RBX::Vector2int16& v)
|
||||
{
|
||||
pushNewObject(L, v);
|
||||
}
|
||||
private:
|
||||
static int newVector2int16(lua_State *L);
|
||||
static int on_add(lua_State *L);
|
||||
static int on_sub(lua_State *L);
|
||||
static int on_mul(lua_State *L);
|
||||
static int on_div(lua_State *L);
|
||||
static int on_unm(lua_State *L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class Color3Bridge : public Bridge<G3D::Color3>
|
||||
{
|
||||
friend class Bridge< G3D::Color3 >;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L);
|
||||
static void pushColor3(lua_State *L, const G3D::Color3& color);
|
||||
|
||||
private:
|
||||
static int newColor3(lua_State *L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class UDimBridge : public Bridge<RBX::UDim>
|
||||
{
|
||||
friend class Bridge< RBX::UDim>;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L);
|
||||
|
||||
static void pushUDim(lua_State *L, const RBX::UDim& v)
|
||||
{
|
||||
pushNewObject(L, v);
|
||||
}
|
||||
private:
|
||||
static int newUDim(lua_State *L);
|
||||
static int on_add(lua_State *L);
|
||||
static int on_sub(lua_State *L);
|
||||
static int on_unm(lua_State *L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class UDim2Bridge : public Bridge<RBX::UDim2>
|
||||
{
|
||||
friend class Bridge< RBX::UDim2>;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L);
|
||||
|
||||
private:
|
||||
static int newUDim2 (lua_State *L);
|
||||
static int on_add(lua_State *L);
|
||||
static int on_sub(lua_State *L);
|
||||
static int on_unm(lua_State *L);
|
||||
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class FacesBridge : public Bridge<RBX::Faces>
|
||||
{
|
||||
friend class Bridge< RBX::Faces>;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L);
|
||||
|
||||
private:
|
||||
static int newFaces (lua_State *L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class AxesBridge : public Bridge<RBX::Axes>
|
||||
{
|
||||
friend class Bridge< RBX::Axes>;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L);
|
||||
|
||||
private:
|
||||
static int newAxes(lua_State *L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class BrickColorBridge : public Bridge<RBX::BrickColor>
|
||||
{
|
||||
friend class Bridge< RBX::BrickColor >;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L) ;
|
||||
|
||||
private:
|
||||
static int newBrickColor(lua_State *L);
|
||||
static int randomBrickColor(lua_State *L);
|
||||
static int paletteBrickColor(lua_State *L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
// CellID bridge for cluster access
|
||||
class CellIDBridge : public Bridge<CellID>
|
||||
{
|
||||
friend class Bridge< CellID >;
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L) ;
|
||||
|
||||
static void pushCellID(lua_State *L, const CellID& v)
|
||||
{
|
||||
pushNewObject(L, v);
|
||||
}
|
||||
private:
|
||||
static int newCellID(lua_State *L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
// Number sequence for particle props
|
||||
class NumberSequenceBridge : public Bridge<NumberSequence>
|
||||
{
|
||||
friend class Bridge< NumberSequence >;
|
||||
public:
|
||||
static void registerClassLibrary(lua_State* L);
|
||||
static void pushNumberSequence(lua_State* L, const NumberSequence& v) { pushNewObject(L, v); }
|
||||
private:
|
||||
static int newNumberSequence(lua_State* L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
// Number sequence for particle props
|
||||
class ColorSequenceBridge : public Bridge<ColorSequence>
|
||||
{
|
||||
friend class Bridge< ColorSequence >;
|
||||
public:
|
||||
static void registerClassLibrary(lua_State* L);
|
||||
static void pushColorSequence(lua_State* L, const ColorSequence& v) { pushNewObject(L, v); }
|
||||
private:
|
||||
static int newColorSequence(lua_State* L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class NumberSequenceKeypointBridge : public Bridge<NumberSequenceKeypoint>
|
||||
{
|
||||
friend class Bridge< NumberSequenceKeypoint >;
|
||||
public:
|
||||
static void registerClassLibrary(lua_State* L);
|
||||
static void pushNumberSequenceKeypoint(lua_State* L, const NumberSequenceKeypoint& v) { pushNewObject(L, v); }
|
||||
private:
|
||||
static int newNumberSequenceKeypoint(lua_State* L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class ColorSequenceKeypointBridge : public Bridge<ColorSequenceKeypoint>
|
||||
{
|
||||
friend class Bridge< ColorSequenceKeypoint >;
|
||||
public:
|
||||
static void registerClassLibrary(lua_State* L);
|
||||
static void pushColorSequenceKeypoint(lua_State* L, const ColorSequenceKeypoint& v) { pushNewObject(L, v); }
|
||||
private:
|
||||
static int newColorSequenceKeypoint(lua_State* L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
class NumberRangeBridge : public Bridge<NumberRange>
|
||||
{
|
||||
friend class Bridge< NumberRange >;
|
||||
public:
|
||||
static void registerClassLibrary(lua_State* L);
|
||||
static void pushNumberRange(lua_State* L, const NumberRange& v) { pushNewObject(L, v); }
|
||||
private:
|
||||
static int newNumberRange(lua_State* L);
|
||||
static const luaL_reg classLibrary[];
|
||||
};
|
||||
|
||||
// Specialization to implement arithmatic operators
|
||||
template<>
|
||||
void Bridge<G3D::Vector3int16>::registerClass (lua_State *L);
|
||||
|
||||
template<>
|
||||
void Bridge<G3D::Vector3>::registerClass (lua_State *L);
|
||||
|
||||
template<>
|
||||
void Bridge<RBX::Vector2>::registerClass (lua_State *L);
|
||||
|
||||
template<>
|
||||
void Bridge<G3D::CoordinateFrame>::registerClass (lua_State *L);
|
||||
|
||||
// Specialization to implement arithmatic operators
|
||||
template<>
|
||||
void Bridge<RBX::UDim>::registerClass (lua_State *L);
|
||||
|
||||
// Specialization to implement arithmatic operators
|
||||
template<>
|
||||
void Bridge<RBX::UDim2>::registerClass (lua_State *L);
|
||||
|
||||
} }
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "lauxlib.h"
|
||||
|
||||
namespace LuaOsExtension
|
||||
{
|
||||
extern const luaL_Reg registry[];
|
||||
}
|
||||
|
||||
namespace LuaMathExtension
|
||||
{
|
||||
int noise(lua_State* L);
|
||||
}
|
||||
|
||||
namespace LuaDebugExtension
|
||||
{
|
||||
extern const luaL_Reg registry[];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include "Lua/LuaBridge.h"
|
||||
#include "reflection/enumConverter.h"
|
||||
#include "rbxformat.h"
|
||||
|
||||
namespace RBX { namespace Lua {
|
||||
|
||||
class AllEnumDescriptors
|
||||
{
|
||||
};
|
||||
typedef const AllEnumDescriptors* AllEnumDescriptorsPtr;
|
||||
|
||||
// Represents a Reflection::EnumDescriptor::Item in Lua
|
||||
class Enums : public SingletonBridge<AllEnumDescriptorsPtr>
|
||||
{
|
||||
public:
|
||||
static void declareAllEnums(lua_State *L);
|
||||
static bool getValue(lua_State *L, unsigned int index, RBX::Reflection::Variant& value);
|
||||
};
|
||||
|
||||
typedef const Reflection::EnumDescriptor* EnumDescriptorPtr;
|
||||
|
||||
// Represents a Reflection::EnumDescriptor::Item in Lua
|
||||
class Enum : public SingletonBridge<EnumDescriptorPtr>
|
||||
{
|
||||
public:
|
||||
};
|
||||
|
||||
typedef const Reflection::EnumDescriptor::Item* EnumDescriptorItemPtr;
|
||||
|
||||
// Represents a Reflection::EnumDescriptor::Item in Lua
|
||||
class EnumItem : public SingletonBridge<EnumDescriptorItemPtr>
|
||||
{
|
||||
public:
|
||||
static EnumDescriptorItemPtr getItem(lua_State *L, unsigned int index) {
|
||||
return getObject(L, index);
|
||||
}
|
||||
static bool getItem(lua_State *L, unsigned int index, EnumDescriptorItemPtr& value) {
|
||||
return getValue(L, index, value);
|
||||
}
|
||||
};
|
||||
|
||||
// specialization
|
||||
template<>
|
||||
int Bridge< AllEnumDescriptorsPtr, false >::on_tostring(const AllEnumDescriptorsPtr& object, lua_State *L);
|
||||
|
||||
// specialization
|
||||
template<>
|
||||
int Bridge< EnumDescriptorPtr, false >::on_tostring(const EnumDescriptorPtr& object, lua_State *L);
|
||||
|
||||
// specialization
|
||||
template<>
|
||||
int Bridge< EnumDescriptorItemPtr, false >::on_tostring(const EnumDescriptorItemPtr& object, lua_State *L);
|
||||
|
||||
} }
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
#pragma once
|
||||
#include "Lua/LuaBridge.h"
|
||||
#include "V8Tree/Instance.h"
|
||||
|
||||
namespace RBX { namespace Lua {
|
||||
|
||||
// specialization
|
||||
template<>
|
||||
int Bridge< shared_ptr<Instance>, false >::on_tostring(const shared_ptr<Instance>& object, lua_State *L);
|
||||
|
||||
class ObjectBridge : public SharedPtrBridge<Instance>
|
||||
{
|
||||
friend class SharedPtrBridge<Instance>;
|
||||
static const luaL_reg classLibrary[];
|
||||
public:
|
||||
static int callMemberFunction(lua_State *L);
|
||||
static int callMemberYieldFunction(lua_State *L);
|
||||
|
||||
static void registerInstanceClassLibrary (lua_State *L) {
|
||||
|
||||
// Register the "new" function for Instances
|
||||
luaL_register(L, "Instance", classLibrary);
|
||||
lua_setreadonly(L, -1, true);
|
||||
lua_pop(L,1); // Pop table from stack. http://lua-users.org/lists/lua-l/2003-12/msg00139.html
|
||||
}
|
||||
|
||||
static int newInstance(lua_State *L);
|
||||
static int lockInstance(lua_State *L);
|
||||
static int unlockInstance(lua_State *L);
|
||||
|
||||
static boost::shared_ptr<Instance> getInstance(lua_State *L, unsigned int index)
|
||||
{
|
||||
return getPtr(L, index);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
void Bridge< shared_ptr<Instance>, false >::on_newindex(shared_ptr<Instance>& object, const char* name, lua_State *L);
|
||||
|
||||
} }
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include "Lua/LuaBridge.h"
|
||||
|
||||
namespace RBX {
|
||||
namespace Lua {
|
||||
|
||||
class Library
|
||||
{
|
||||
std::string libraryName;
|
||||
public:
|
||||
Library(std::string libraryName)
|
||||
:libraryName(libraryName)
|
||||
{};
|
||||
|
||||
const std::string& getLibraryName() const { return libraryName; }
|
||||
bool operator ==(const Library& other) const
|
||||
{
|
||||
return this->libraryName == other.libraryName;
|
||||
}
|
||||
};
|
||||
// Represents a Reflection::EnumDescriptor::Item in Lua
|
||||
class LibraryBridge : public Bridge<Library>
|
||||
{
|
||||
public:
|
||||
static void registerClassLibrary (lua_State *L);
|
||||
static int find(lua_State *L, const std::string& libraryName);
|
||||
static void push(lua_State *L, const Library& item);
|
||||
static void saveLibraryResult(lua_State *L, int results, std::string libraryName);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/Memory.h"
|
||||
#include "boost/pool/object_pool.hpp"
|
||||
#include "boost/iostreams/filter/gzip.hpp"
|
||||
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class LuaAllocator
|
||||
{
|
||||
private:
|
||||
size_t heapSize;
|
||||
size_t heapCount;
|
||||
size_t maxHeapSize;
|
||||
size_t maxHeapCount;
|
||||
|
||||
// memory pools
|
||||
std::vector<boost::pool<>*> memPools;
|
||||
|
||||
public:
|
||||
LuaAllocator(bool usePool = false);
|
||||
~LuaAllocator();
|
||||
|
||||
static size_t heapLimit; // maximum heap size allowed. 0 == no limit
|
||||
|
||||
void clearHeapMax();
|
||||
void getHeapStats(size_t& heapSize, size_t& heapCount, size_t& maxHeapSize, size_t& maxHeapCount) const;
|
||||
void getHeapStats(size_t& heapSize, size_t& heapCount) const;
|
||||
|
||||
bool hasSpace(const long diff);
|
||||
virtual void* alloc(void *ptr, size_t osize, size_t nsize);
|
||||
static void * alloc(void *ud, void *ptr, size_t osize, size_t nsize);
|
||||
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8DataModel/GlobalSettings.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
extern const char *const sLuaSettings;
|
||||
class LuaSettings
|
||||
: public GlobalAdvancedSettingsItem<LuaSettings, sLuaSettings>
|
||||
{
|
||||
public:
|
||||
LuaSettings();
|
||||
int gcPause;
|
||||
int gcStepMul;
|
||||
double defaultWaitTime;
|
||||
double smallestWaitTime;
|
||||
|
||||
int gcLimit; //Ideal limit above which we trigger aggressive garbage collection, in average KB per gcFrequency
|
||||
int gcFrequency; //How many heartbeats between maunal GC steps
|
||||
|
||||
bool areScriptStartsReported;
|
||||
float waitingThreadsBudget; // 0..1 A percentage
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include "Lua/LuaBridge.h"
|
||||
#include "reflection/object.h"
|
||||
#include "Reflection/Event.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class Instance;
|
||||
namespace Lua
|
||||
{
|
||||
struct EventInstance
|
||||
{
|
||||
const Reflection::EventDescriptor* descriptor;
|
||||
// We use a weak pointer because references to a Event shouldn't lock the source of the event.
|
||||
// If the source has been collected, then connecting to the Event will return an empty connection.
|
||||
weak_ptr<Instance> source;
|
||||
|
||||
bool operator== (const EventInstance& other) const
|
||||
{
|
||||
if (descriptor != other.descriptor)
|
||||
return false;
|
||||
|
||||
shared_ptr<Instance> l = source.lock();
|
||||
if (!l)
|
||||
return false;
|
||||
|
||||
shared_ptr<Instance> l2 = other.source.lock();
|
||||
if (!l2)
|
||||
return false;
|
||||
|
||||
return l == l2;
|
||||
}
|
||||
};
|
||||
|
||||
// specialization
|
||||
template<>
|
||||
int Bridge<EventInstance>::on_tostring(const EventInstance& object, lua_State *L);
|
||||
|
||||
class EventBridge : public Bridge<EventInstance>
|
||||
{
|
||||
public:
|
||||
static int connect(lua_State *L);
|
||||
|
||||
static int wait(lua_State *L);
|
||||
};
|
||||
|
||||
class SignalConnectionBridge : public Bridge< rbx::signals::connection >
|
||||
{
|
||||
friend class Bridge< rbx::signals::connection >;
|
||||
static int disconnect(lua_State *L);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include "Util/AsyncHttpQueue.h"
|
||||
#include "Util/ContentId.h"
|
||||
#include "Util/ProtectedString.h"
|
||||
#include "V8Tree/Instance.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
|
||||
class ContentProvider;
|
||||
|
||||
extern const char* const sLuaSourceContainer;
|
||||
class LuaSourceContainer
|
||||
: public DescribedNonCreatable<LuaSourceContainer, Instance, sLuaSourceContainer>
|
||||
{
|
||||
public:
|
||||
enum RemoteSourceLoadState
|
||||
{
|
||||
NotAttemptedToLoad,
|
||||
Loaded,
|
||||
FailedToLoad
|
||||
};
|
||||
|
||||
static void loadLinkedScripts(shared_ptr<ContentProvider> cp, Instance* root, AsyncHttpQueue::ResultJob jobType, boost::function<void()> callback);
|
||||
static void loadLinkedScriptsForInstances(shared_ptr<ContentProvider> cp, Instances& instances, AsyncHttpQueue::ResultJob jobType, boost::function<void()> callback);
|
||||
static void blockingLoadLinkedScripts(ContentProvider* cp, Instance* root);
|
||||
static void blockingLoadLinkedScriptsForInstances(ContentProvider* cp, Instances& instances);
|
||||
static Reflection::RemoteEventDesc<LuaSourceContainer, void()> event_requestLock;
|
||||
|
||||
LuaSourceContainer();
|
||||
|
||||
const ContentId& getScriptId() const;
|
||||
void setScriptId(const ContentId& contentId);
|
||||
const ProtectedString& getCachedRemoteSource() const;
|
||||
void setCachedRemoteSource(const ProtectedString& value);
|
||||
int getCachedRemoteSourceLoadState() const;
|
||||
void setCachedRemoteSourceLoadState(int value);
|
||||
Instance* getCurrentEditor() const;
|
||||
void setCurrentEditor(Instance* newEditor);
|
||||
virtual void fireSourceChanged() {};
|
||||
|
||||
rbx::remote_signal<void()> requestLock;
|
||||
rbx::remote_signal<void(bool)> lockGrantedOrNot;
|
||||
|
||||
protected:
|
||||
virtual void onScriptIdChanged() {}
|
||||
void processRemoteEvent(const Reflection::EventDescriptor& descriptor, const Reflection::EventArguments& args, const SystemAddress& source) override;
|
||||
|
||||
private:
|
||||
struct LinkedScriptLoadData
|
||||
{
|
||||
rbx::atomic<int> scriptCount;
|
||||
boost::function<void()> callbackWhenDone;
|
||||
shared_ptr<Instance> context;
|
||||
AsyncHttpQueue::ResultJob jobType;
|
||||
|
||||
boost::mutex scriptApplyResultClosuresMutex;
|
||||
std::vector<boost::function<void()> > scriptApplyResultClosures;
|
||||
};
|
||||
|
||||
static void linkedSourceCountingVisitor(shared_ptr<Instance> descendant, int* counter);
|
||||
static void linkedSourceLoadedHandler(weak_ptr<LuaSourceContainer> weakScript, AsyncHttpQueue::RequestResult result,
|
||||
shared_ptr<const std::string> loadedSource, shared_ptr<LinkedScriptLoadData> metadata);
|
||||
static void updateScriptInstancesUnderWriteLock(DataModel* dm, shared_ptr<LinkedScriptLoadData> metadata);
|
||||
static void linkedSourceFetchingVisitor(shared_ptr<Instance> descendant, shared_ptr<ContentProvider> cp,
|
||||
AsyncHttpQueue::ResultJob jobType, shared_ptr<LinkedScriptLoadData> metadata);
|
||||
|
||||
ContentId scriptId;
|
||||
ProtectedString cachedRemoteSource;
|
||||
RemoteSourceLoadState cachedRemoteSourceLoadState;
|
||||
weak_ptr<Instance> currentEditor;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
#pragma once
|
||||
|
||||
#if (defined(_WIN32) || (defined(__APPLE__) && !defined(RBX_PLATFORM_IOS))) && !defined(RBX_STUDIO_BUILD)
|
||||
#define RBX_SECURE_DOUBLE
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define RBX_ALIGN(s) _declspec(align(s))
|
||||
#else
|
||||
#define RBX_ALIGN(s) __attribute__((__aligned__(s)))
|
||||
#endif
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <string>
|
||||
#if defined(RBX_SECURE_DOUBLE)
|
||||
#include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
#ifndef RBX_STUDIO_BUILD
|
||||
#define LUAVM_SECURE
|
||||
#endif
|
||||
|
||||
// Utilities for shuffling fields and enum values
|
||||
#define LUAVM_SHUFFLE_COMMA ,
|
||||
|
||||
#ifdef LUAVM_SECURE
|
||||
#define LUAVM_SHUFFLE2(sep,a0,a1) a1 sep a0
|
||||
#define LUAVM_SHUFFLE3(sep,a0,a1,a2) a1 sep a2 sep a0
|
||||
#define LUAVM_SHUFFLE4(sep,a0,a1,a2,a3) a3 sep a1 sep a0 sep a2
|
||||
#define LUAVM_SHUFFLE5(sep,a0,a1,a2,a3,a4) a4 sep a0 sep a2 sep a1 sep a3
|
||||
#define LUAVM_SHUFFLE6(sep,a0,a1,a2,a3,a4,a5) a3 sep a5 sep a2 sep a0 sep a1 sep a4
|
||||
#define LUAVM_SHUFFLE7(sep,a0,a1,a2,a3,a4,a5,a6) a2 sep a3 sep a0 sep a4 sep a6 sep a1 sep a5
|
||||
#define LUAVM_SHUFFLE8(sep,a0,a1,a2,a3,a4,a5,a6,a7) a7 sep a0 sep a5 sep a6 sep a3 sep a1 sep a2 sep a4
|
||||
#define LUAVM_SHUFFLE9(sep,a0,a1,a2,a3,a4,a5,a6,a7,a8) a2 sep a6 sep a4 sep a7 sep a1 sep a8 sep a0 sep a3 sep a5
|
||||
#else
|
||||
#define LUAVM_SHUFFLE2(sep,a0,a1) a0 sep a1
|
||||
#define LUAVM_SHUFFLE3(sep,a0,a1,a2) a0 sep a1 sep a2
|
||||
#define LUAVM_SHUFFLE4(sep,a0,a1,a2,a3) a0 sep a1 sep a2 sep a3
|
||||
#define LUAVM_SHUFFLE5(sep,a0,a1,a2,a3,a4) a0 sep a1 sep a2 sep a3 sep a4
|
||||
#define LUAVM_SHUFFLE6(sep,a0,a1,a2,a3,a4,a5) a0 sep a1 sep a2 sep a3 sep a4 sep a5
|
||||
#define LUAVM_SHUFFLE7(sep,a0,a1,a2,a3,a4,a5,a6) a0 sep a1 sep a2 sep a3 sep a4 sep a5 sep a6
|
||||
#define LUAVM_SHUFFLE8(sep,a0,a1,a2,a3,a4,a5,a6,a7) a0 sep a1 sep a2 sep a3 sep a4 sep a5 sep a6 sep a7
|
||||
#define LUAVM_SHUFFLE9(sep,a0,a1,a2,a3,a4,a5,a6,a7,a8) a0 sep a1 sep a2 sep a3 sep a4 sep a5 sep a6 sep a7 sep a8
|
||||
#endif
|
||||
|
||||
// Utility class for obfuscating fields of primitive types
|
||||
// WARNING: this will give incorrect results if T = float.
|
||||
template <typename T> class LuaVMValue
|
||||
{
|
||||
public:
|
||||
operator const T() const
|
||||
{
|
||||
#ifdef LUAVM_SECURE
|
||||
return (T)((uintptr_t)storage + reinterpret_cast<uintptr_t>(this));
|
||||
#else
|
||||
return storage;
|
||||
#endif
|
||||
}
|
||||
|
||||
void operator=(const T& value)
|
||||
{
|
||||
#ifdef LUAVM_SECURE
|
||||
storage = (T)((uintptr_t)value - reinterpret_cast<uintptr_t>(this));
|
||||
#else
|
||||
storage = value;
|
||||
#endif
|
||||
}
|
||||
|
||||
const T operator->() const
|
||||
{
|
||||
return operator const T();
|
||||
}
|
||||
|
||||
private:
|
||||
T storage;
|
||||
};
|
||||
|
||||
// Encoding/decoding lineinfo
|
||||
#if defined(LUAVM_SECURE)
|
||||
#define LUAVM_ENCODELINE(line, pc) ((line) ^ ((pc) << 8))
|
||||
#define LUAVM_DECODELINE(line, pc) ((line) ^ ((pc) << 8))
|
||||
#else
|
||||
#define LUAVM_ENCODELINE(line, pc) (line)
|
||||
#define LUAVM_DECODELINE(line, pc) (line)
|
||||
#endif
|
||||
|
||||
// Encoding/decoding instructions
|
||||
#if defined(LUAVM_SECURE)
|
||||
#define LUAVM_ENCODEINSN(insn, key) ((insn) * key)
|
||||
#define LUAVM_DECODEINSN(insn, key) ((insn).v * key)
|
||||
#else
|
||||
#define LUAVM_ENCODEINSN(insn, key) (insn)
|
||||
#define LUAVM_DECODEINSN(insn, key) (insn).v
|
||||
#endif
|
||||
|
||||
typedef unsigned int (*RbxOpEncoder)(unsigned int i, int pc, unsigned key);
|
||||
|
||||
// Utility class
|
||||
struct lua_State;
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class ProtectedString;
|
||||
}
|
||||
|
||||
// Core scripts have a fixed key
|
||||
// Don't use these except in LuaVM*.cpp!
|
||||
// These are defines to make sure they don't end up in an executable by complete accident
|
||||
#define LUAVM_INTERNAL_CORE_ENCODE_KEY 641
|
||||
#define LUAVM_INTERNAL_CORE_DECODE_KEY 6700417
|
||||
|
||||
// Constants for key values
|
||||
#define LUAVM_KEY_DUMMY 1
|
||||
#define LUAVM_KEY_INVALID 0
|
||||
#define LUAVM_MODKEY_DUMMY 1
|
||||
|
||||
namespace LuaVM
|
||||
{
|
||||
// Utilities for working with regular scripts
|
||||
std::string compile(const std::string& source);
|
||||
|
||||
std::string compileLegacy(const std::string& source);
|
||||
|
||||
int load(lua_State* L, const RBX::ProtectedString& source, const char* chunkname, unsigned int modkey = 1);
|
||||
|
||||
unsigned int getKey();
|
||||
|
||||
// Utilities for working with core scripts
|
||||
std::string compileCore(const std::string& source);
|
||||
|
||||
unsigned int getKeyCore();
|
||||
unsigned int getModKeyCore();
|
||||
|
||||
// Controls whether replication uses bytecode or source code
|
||||
bool useSecureReplication();
|
||||
|
||||
// Controls whether scripts can be compiled from source code
|
||||
bool canCompileScripts();
|
||||
|
||||
// Gets embedded bytecode for core scripts/libraries
|
||||
std::string getBytecodeCore(const std::string& name);
|
||||
|
||||
//const ref
|
||||
boost::unordered_map<std::string, std::string> getBytecodeCoreModules();
|
||||
|
||||
// Old Encoding Scheme
|
||||
unsigned int rbxOldEncode(unsigned int i, int pc, unsigned int key);
|
||||
|
||||
// Dual-Affine-Xor Encoding
|
||||
unsigned int rbxDaxEncode(unsigned int i, int pc, unsigned int key);
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if defined(RBX_SECURE_DOUBLE)
|
||||
// Note that users who can find a value can still change magnitude or sign easily.
|
||||
|
||||
// sse2+ only
|
||||
class LuaSecureDouble
|
||||
{
|
||||
private:
|
||||
double storage;
|
||||
public:
|
||||
static RBX_ALIGN(16) int luaXorMask[4];
|
||||
|
||||
operator const double() const
|
||||
{
|
||||
__m128d xmmKey = _mm_load_pd((double*)(luaXorMask));
|
||||
__m128d xmmData = _mm_load_sd(&storage);
|
||||
__m128d xmmResult = _mm_xor_pd(xmmData, xmmKey );
|
||||
return _mm_cvtsd_f64(xmmResult);
|
||||
}
|
||||
|
||||
void operator=(const double& value)
|
||||
{
|
||||
__m128d xmmKey = _mm_load_pd((double*)(luaXorMask));
|
||||
__m128d xmmData = _mm_load_sd(&value);
|
||||
__m128d xmmResult = _mm_xor_pd(xmmData, xmmKey );
|
||||
storage = _mm_cvtsd_f64(xmmResult);
|
||||
}
|
||||
|
||||
static void initDouble();
|
||||
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,98 @@
|
||||
#pragma once
|
||||
|
||||
#include "Reflection/reflection.h"
|
||||
#include "Script/ThreadRef.h"
|
||||
#include "Script/LuaSourceContainer.h"
|
||||
#include "Util/ProtectedString.h"
|
||||
#include "V8Tree/Instance.h"
|
||||
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
|
||||
extern const char* const sModuleScript;
|
||||
class ModuleScript
|
||||
: public DescribedCreatable<ModuleScript, LuaSourceContainer, sModuleScript>
|
||||
{
|
||||
public:
|
||||
static const Reflection::PropDescriptor<ModuleScript, ProtectedString> prop_Source;
|
||||
|
||||
enum ScriptSetupState
|
||||
{
|
||||
NotRunYet = 0,
|
||||
Running = 1,
|
||||
CompletedError = 2,
|
||||
CompletedSuccess = 3
|
||||
};
|
||||
|
||||
class PerVMState
|
||||
{
|
||||
public:
|
||||
PerVMState();
|
||||
virtual ~PerVMState();
|
||||
|
||||
int getResultRegistryIndex() const;
|
||||
|
||||
// Destroy the current result index and replace it with index.
|
||||
void reassignResultRegistryIndex(int newIndex);
|
||||
|
||||
void setRunning(boost::intrusive_ptr<Lua::WeakThreadRef::Node> node);
|
||||
void setCompletedError();
|
||||
void setCompletedSuccess(lua_State* globalStateContainingResult, int resultRegistryIndex);
|
||||
ScriptSetupState getCurrentState() const;
|
||||
|
||||
void addYieldedImporter(Lua::WeakThreadRef L);
|
||||
void getAndClearYieldedImporters(std::vector<Lua::WeakThreadRef>* out);
|
||||
|
||||
void cleanupAndResetState();
|
||||
void resetState();
|
||||
private:
|
||||
ScriptSetupState scriptLoadingState;
|
||||
boost::intrusive_ptr<Lua::WeakThreadRef::Node> node;
|
||||
lua_State* globalStateContainingResult;
|
||||
int resultRegistryIndex;
|
||||
std::vector<Lua::WeakThreadRef> yieldedImporters;
|
||||
|
||||
void releaseReferenceIfCompletedSuccessfully();
|
||||
void releaseScriptNodeIfPresent();
|
||||
};
|
||||
|
||||
ModuleScript();
|
||||
|
||||
// Instance
|
||||
bool askSetParent(const Instance* instance) const override { return true; }
|
||||
|
||||
ProtectedString getSource() const;
|
||||
void setSource(const ProtectedString& newText);
|
||||
|
||||
std::string requestHash() const;
|
||||
|
||||
PerVMState& vmState(lua_State* vm);
|
||||
|
||||
// Try to get rid of this method once new play button is launched.
|
||||
static void cleanupAndResetState(const weak_ptr<ModuleScript> module);
|
||||
|
||||
// Reset the state of the module script without destroying its result index.
|
||||
void resetState();
|
||||
|
||||
void setReloadRequested(bool reload) { reloadRequested = reload; }
|
||||
bool getReloadRequested() const { return reloadRequested; }
|
||||
|
||||
void fireSourceChanged() override;
|
||||
|
||||
rbx::signal<void(lua_State*)> starting;
|
||||
|
||||
protected:
|
||||
void onScriptIdChanged() override;
|
||||
|
||||
private:
|
||||
ProtectedString source;
|
||||
bool reloadRequested;
|
||||
typedef boost::unordered_map<lua_State*, PerVMState> VMStateMap;
|
||||
VMStateMap stateMap;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,122 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct lua_State;
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class DataModel;
|
||||
class Instance;
|
||||
|
||||
namespace ScriptAnalyzer
|
||||
{
|
||||
// Don't change codes for the existing warnings - they have a corresponding wiki anchor tag in http://wiki.watrbx.wtf/index.php?title=Script_Analysis
|
||||
enum WarningCode
|
||||
{
|
||||
Warning_Unknown = 0,
|
||||
|
||||
Warning_UnknownGlobal = 1,
|
||||
Warning_DeprecatedGlobal = 2,
|
||||
Warning_GlobalUsedAsLocal = 3,
|
||||
Warning_LocalShadow = 4,
|
||||
Warning_SameLineStatement = 5,
|
||||
Warning_MultiLineStatement = 6,
|
||||
Warning_UnknownType = 7,
|
||||
Warning_DotCall = 8,
|
||||
Warning_UnknownMember = 9,
|
||||
Warning_BuiltinGlobalWrite = 10,
|
||||
Warning_Placeholder = 11,
|
||||
|
||||
Warning_Internal
|
||||
};
|
||||
|
||||
struct Position
|
||||
{
|
||||
unsigned int line, column;
|
||||
|
||||
Position(unsigned int line, unsigned int column)
|
||||
: line(line)
|
||||
, column(column)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct Location
|
||||
{
|
||||
Position begin, end;
|
||||
|
||||
Location()
|
||||
: begin(0, 0)
|
||||
, end(0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
Location(const Position& begin, const Position& end)
|
||||
: begin(begin)
|
||||
, end(end)
|
||||
{
|
||||
}
|
||||
|
||||
Location(const Position& begin, unsigned int length)
|
||||
: begin(begin)
|
||||
, end(begin.line, begin.column + length)
|
||||
{
|
||||
}
|
||||
|
||||
Location(const Location& begin, const Location& end)
|
||||
: begin(begin.begin)
|
||||
, end(end.end)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct Error
|
||||
{
|
||||
Location location;
|
||||
std::string text;
|
||||
};
|
||||
|
||||
struct Warning
|
||||
{
|
||||
WarningCode code;
|
||||
Location location;
|
||||
std::string text;
|
||||
|
||||
Warning (WarningCode code, Location location, std::string text)
|
||||
: code(code)
|
||||
, location(location)
|
||||
, text(text)
|
||||
{}
|
||||
};
|
||||
|
||||
struct IntellesenseResult
|
||||
{
|
||||
IntellesenseResult()
|
||||
: name("")
|
||||
, isLocal(false)
|
||||
, isFunction(false)
|
||||
, location(Position(0,0) , Position(0,0))
|
||||
{}
|
||||
|
||||
std::string name;
|
||||
bool isLocal;
|
||||
bool isFunction;
|
||||
Location location;
|
||||
std::vector<IntellesenseResult> children;
|
||||
};
|
||||
|
||||
struct Result
|
||||
{
|
||||
boost::optional<Error> error;
|
||||
std::vector<Warning> warnings;
|
||||
std::vector<IntellesenseResult> intellesenseAnalysis;
|
||||
};
|
||||
|
||||
Result analyze(DataModel* dm, shared_ptr<Instance> script, const std::string& code);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,466 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8Tree/Service.h"
|
||||
#include "Util/ProtectedString.h"
|
||||
#include "util/runstateowner.h"
|
||||
#include "Script/IScriptFilter.h"
|
||||
#include "script/ThreadRef.h"
|
||||
#include "script/ExitHandlers.h"
|
||||
#include "Security/SecurityContext.h"
|
||||
#include "Util/AsyncHttpQueue.h"
|
||||
#include "util/RunningAverage.h"
|
||||
#include "rbx/RunningAverage.h"
|
||||
|
||||
#define BOOST_DATE_TIME_NO_LIB
|
||||
#include "boost/date_time/posix_time/posix_time.hpp"
|
||||
|
||||
struct lua_State;
|
||||
struct lua_Debug;
|
||||
|
||||
LOGGROUP(ScriptContext)
|
||||
LOGGROUP(ScriptContextRemove)
|
||||
LOGGROUP(ScriptContextAdd)
|
||||
LOGGROUP(ScriptContextClose)
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class LuaSourceContainer;
|
||||
class LuaAllocator;
|
||||
class LibraryService;
|
||||
class ModuleScript;
|
||||
class ModelInstance;
|
||||
namespace Stats
|
||||
{
|
||||
class Item;
|
||||
}
|
||||
namespace Lua
|
||||
{
|
||||
class YieldingThreads;
|
||||
class WeakFunctionRef;
|
||||
}
|
||||
namespace Network
|
||||
{
|
||||
class Player;
|
||||
}
|
||||
class BaseScript;
|
||||
class CoreScript;
|
||||
class ScriptStats;
|
||||
class LuaStatsItem;
|
||||
|
||||
void registerScriptDescriptors();
|
||||
|
||||
extern const char* const sScriptContext;
|
||||
class ScriptContext
|
||||
: public DescribedCreatable<ScriptContext, Instance, sScriptContext, Reflection::ClassDescriptor::INTERNAL_LOCAL>
|
||||
, public Service
|
||||
, public IScriptFilter
|
||||
{
|
||||
friend class LuaStatsItem;
|
||||
friend class GcJob;
|
||||
friend class WaitingScriptsJob;
|
||||
|
||||
public:
|
||||
static const int hookCount;
|
||||
|
||||
struct ScriptStartOptions
|
||||
{
|
||||
struct LuaSyntaxError : std::runtime_error
|
||||
{
|
||||
LuaSyntaxError(int lineNumber, std::exception& source)
|
||||
:std::runtime_error(source.what())
|
||||
,lineNumber(lineNumber)
|
||||
{
|
||||
}
|
||||
int lineNumber;
|
||||
};
|
||||
|
||||
RBX::Security::Identities identity;
|
||||
Scripts::Continuations continuations;
|
||||
boost::function<std::string(const std::string&)> filter; // may throw a LuaSyntaxError
|
||||
|
||||
ScriptStartOptions():identity(RBX::Security::GameScript_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
typedef DescribedCreatable<ScriptContext, Instance, sScriptContext, Reflection::ClassDescriptor::INTERNAL_LOCAL> Super;
|
||||
|
||||
class ScriptImpersonator : public RBX::Security::Impersonator
|
||||
{
|
||||
public:
|
||||
ScriptImpersonator(lua_State *thread);
|
||||
};
|
||||
|
||||
struct GlobalState
|
||||
{
|
||||
GlobalState()
|
||||
: state(0)
|
||||
, gcCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
lua_State* state;
|
||||
|
||||
RunningAverage<double> gcAllocAvg; // average lua memory allocation per luaGcFrequency in KB
|
||||
int gcCount;
|
||||
};
|
||||
|
||||
typedef boost::array<GlobalState, RBX::Security::COUNT_VM_Classes> GlobalStates; // separate Lua top-level states
|
||||
GlobalStates globalStates;
|
||||
Lua::WeakThreadRef commandLineSandbox;
|
||||
std::set<BaseScript*> scripts;
|
||||
RBX::Time nextPendingScripts;
|
||||
struct ScriptStart
|
||||
{
|
||||
shared_ptr<BaseScript> script;
|
||||
ScriptStartOptions options;
|
||||
};
|
||||
std::vector<ScriptStart> pendingScripts; // scripts waiting to be executed
|
||||
std::vector<ScriptStart> loadingScripts; // scripts waiting to be executed
|
||||
|
||||
// An obfuscated pointer to a location near where the object was created.
|
||||
// copying the object becomes detectable.
|
||||
// https://en.wikipedia.org/wiki/Feistel_cipher
|
||||
// the "update" method might be targeted even if it is obfuscated.
|
||||
struct SecurityAnchor
|
||||
{
|
||||
size_t value[2];
|
||||
FORCEINLINE void update(const void* ptr)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
size_t localValue[2] = {reinterpret_cast<size_t>(ptr), ~reinterpret_cast<size_t>(ptr)};
|
||||
localValue[0] ^= localValue[1]*RBX_BUILDSEED | 20151112;
|
||||
localValue[1] ^= localValue[0]*20151112 | RBX_BUILDSEED;
|
||||
value[0] = localValue[0];
|
||||
value[1] = localValue[1];
|
||||
#endif
|
||||
}
|
||||
|
||||
FORCEINLINE bool checkAnchor(const void* ptr) const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
size_t localValue[2] = {value[0], value[1]};
|
||||
localValue[1] ^= localValue[0]*20151112 | RBX_BUILDSEED;
|
||||
localValue[0] ^= localValue[1]*RBX_BUILDSEED | 20151112;
|
||||
return !((reinterpret_cast<size_t>(ptr)+localValue[1])
|
||||
^ (~reinterpret_cast<size_t>(ptr)+localValue[0]));
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
SecurityAnchor securityAnchor;
|
||||
|
||||
shared_ptr<RunService> runService;
|
||||
|
||||
boost::scoped_ptr<Lua::YieldingThreads> yieldEvent; // collects all threads that have yielded, and periodically resumes them
|
||||
|
||||
struct WaitingThread
|
||||
{
|
||||
Lua::ThreadRef thread;
|
||||
shared_ptr<const Reflection::Tuple> arguments;
|
||||
};
|
||||
rbx::safe_queue<WaitingThread> waitingThreads;
|
||||
|
||||
bool robloxPlace;
|
||||
bool scriptsDisabled; // == don't run the scripts contained in BaseScript objects
|
||||
bool preventNewConnection;
|
||||
|
||||
shared_ptr<LuaStatsItem> statsItem;
|
||||
bool collectScriptStats;
|
||||
shared_ptr<ScriptStats> scriptStats;
|
||||
std::set<weak_ptr<ModuleScript> > loadedModules;
|
||||
|
||||
int startScriptReentrancy;
|
||||
|
||||
rbx::atomic<int> timedoutCount;
|
||||
Time::Interval timoutSpan; // The time that is allowed per heartbeat before scripts stop running (0 means no timeouts)
|
||||
Time timoutTime; // The system time when we should time-out scripts
|
||||
rbx::atomic<int> timedout; // == scripts should stop running
|
||||
boost::scoped_ptr<boost::thread> timeoutThread;
|
||||
boost::mutex timeoutMutex;
|
||||
volatile bool endTimoutThread;
|
||||
CEvent checkTimeout;
|
||||
|
||||
struct AssetModuleInfo
|
||||
{
|
||||
enum State
|
||||
{
|
||||
NotFetchedYet = 0,
|
||||
Fetching,
|
||||
Fetched,
|
||||
Failed
|
||||
};
|
||||
State state;
|
||||
std::vector<Lua::WeakThreadRef> yieldedImporters;
|
||||
shared_ptr<ModuleScript> module;
|
||||
shared_ptr<ModelInstance> root;
|
||||
AssetModuleInfo()
|
||||
: state(NotFetchedYet)
|
||||
{}
|
||||
};
|
||||
typedef boost::unordered_map<int, AssetModuleInfo> LoadedAssetModules;
|
||||
LoadedAssetModules loadedAssetModules;
|
||||
|
||||
Time luaGcStartTime;
|
||||
RunningAverage<double> avgLuaGcInterval; // in msec
|
||||
RunningAverage<double> avgLuaGcTime; // in msec
|
||||
|
||||
RunningAverageTimeInterval<> resumedThreads;
|
||||
RunningAverage<> throttlingThreads; // 1 if threads are being deffered
|
||||
|
||||
bool statesClosed;
|
||||
|
||||
public:
|
||||
ScriptContext();
|
||||
virtual ~ScriptContext();
|
||||
|
||||
///////////////////////////////////////////////////
|
||||
// IScriptFilter
|
||||
/*override*/ virtual bool scriptShouldRun(BaseScript* script);
|
||||
|
||||
static void setAdminScriptPath(const std::string& newPath);
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// Reflection API
|
||||
static Reflection::BoundProp<bool> propScriptsDisabled;
|
||||
static Reflection::BoundProp<int> propLuaGcLimit;
|
||||
static Reflection::BoundProp<int> propLuaGcFrequency;
|
||||
static Reflection::BoundProp<int> propLuaGcStepSize;
|
||||
void setTimeout(double seconds);
|
||||
void setCollectScriptStats(bool);
|
||||
// Core & Starter Scripts
|
||||
void addStarterScript(int assetId);
|
||||
void addCoreScript(int assetId, shared_ptr<Instance> parent, std::string name);
|
||||
void addCoreScriptLocal(std::string scriptName, shared_ptr<Instance> parent);
|
||||
// Experimental error signal for catching errors server-side
|
||||
rbx::signal<void(std::string, std::string, shared_ptr<Instance>)> errorSignal;
|
||||
// A temporary signals used for diagnostic purposes
|
||||
rbx::signal<void(shared_ptr<Instance>, std::string, shared_ptr<Instance>)> camelCaseViolation;
|
||||
rbx::signal<void(lua_State*)> scriptErrorDetected;
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// Configuration
|
||||
void setRobloxPlace(bool robloxPlace);
|
||||
void initializeLuaStateSandbox(Lua::WeakThreadRef& threadRef, lua_State* parentState, Security::Identities identity);
|
||||
void setKeys(unsigned int scriptKey, unsigned int coreScriptModKey);
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// Helpers and utilities
|
||||
Reflection::Variant evaluateStudioCommandItem(const char* itemToEvaluate, shared_ptr<RBX::LuaSourceContainer> script);
|
||||
static bool checkSyntax(const std::string& code, int& line, std::string& errorMessage);
|
||||
static lua_State* getGlobalState(lua_State* thread);
|
||||
static ScriptContext& getContext(lua_State* thread);
|
||||
static void printCallStack(lua_State* thread, std::string* output = NULL, bool dontPrint = false);
|
||||
static std::string extractCallStack(lua_State* thread, shared_ptr<BaseScript>& source, int& line);
|
||||
// Shutdown helpers
|
||||
bool shouldPreventNewConnections() { return preventNewConnection; }
|
||||
void setPreventNewConnections() { preventNewConnection = true; }
|
||||
void closeStates(bool resettingSimulation); // Closes down all threads
|
||||
bool haveStatesClosed() { return statesClosed; }
|
||||
void cleanupModules();
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Script Instance API
|
||||
// Called by IScriptOwner implementers
|
||||
void addScript(weak_ptr<BaseScript> script, ScriptStartOptions startOptions = ScriptStartOptions()); // checks pointer validity
|
||||
void removeScript(weak_ptr<BaseScript> script);
|
||||
size_t numScripts() {return scripts.size();}
|
||||
bool hasScript(BaseScript* script) {return (scripts.find(script) != scripts.end());}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// Calls that make lua run/resume
|
||||
void executeInNewThread(RBX::Security::Identities identity, const ProtectedString& script, const char* name);
|
||||
std::auto_ptr<Reflection::Tuple> executeInNewThread(RBX::Security::Identities identity, const ProtectedString& script, const char* name, const Reflection::Tuple& arguments);
|
||||
void executeInNewThreadWithExtraGlobals(RBX::Security::Identities identity,
|
||||
const ProtectedString& script, const char* name,
|
||||
const std::map<std::string, shared_ptr<Instance> >& extraGlobals);
|
||||
|
||||
// Calls a function
|
||||
Reflection::Tuple callInNewThread(Lua::WeakFunctionRef& function, const Reflection::Tuple& arguments);
|
||||
|
||||
// Thread-safe call:
|
||||
void scheduleResume(Lua::ThreadRef thread, shared_ptr<const Reflection::Tuple> arguments);
|
||||
typedef enum { Success, Yield, Error } Result;
|
||||
// Resumes the thread. Reports errors and queues yielding threads for later execution
|
||||
// NOTE: The caller is reponsible for balancing the stack
|
||||
Result resume(RBX::Lua::ThreadRef thread, int narg);
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// Stats
|
||||
void scriptResumedFromEvent() { resumedThreads.sample(); }
|
||||
|
||||
size_t getThreadCount() const;
|
||||
shared_ptr<const Reflection::Tuple> getHeapStats(bool clearHighwaterMark);
|
||||
shared_ptr<const Reflection::Tuple> getScriptStats(); // deprecated. Don't use it anymore
|
||||
shared_ptr<const Reflection::ValueArray> getScriptStatsNew();
|
||||
|
||||
struct ScriptStat
|
||||
{
|
||||
std::string hash;
|
||||
std::string name;
|
||||
Instances scripts;
|
||||
double activity;
|
||||
unsigned int invocationCount;
|
||||
};
|
||||
void getScriptStatsTyped(std::vector<ScriptStat>& result);
|
||||
|
||||
double getAvgLuaGcTime() { return avgLuaGcTime.value(); }
|
||||
double getAvgLuaGcInterval() { return avgLuaGcInterval.value(); }
|
||||
|
||||
void reloadModuleScript(shared_ptr<ModuleScript> moduleScript);
|
||||
|
||||
bool checkSecurityAnchorValid() const
|
||||
{
|
||||
return securityAnchor.checkAnchor(&this->securityAnchor);
|
||||
}
|
||||
|
||||
protected:
|
||||
/*override*/ void onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider);
|
||||
private:
|
||||
rbx::signals::scoped_connection heartbeatConnection;
|
||||
|
||||
boost::scoped_ptr<LuaAllocator> allocator;
|
||||
|
||||
shared_ptr<TaskScheduler::Job> gcJob;
|
||||
shared_ptr<TaskScheduler::Job> waitingScriptsJob;
|
||||
void onHeartbeat(const Heartbeat& heartbeat);
|
||||
void stepGc();
|
||||
void resumeWaitingScripts(Time expirationTime);
|
||||
|
||||
static void sandboxThread(lua_State* thread);
|
||||
static void setThreadIdentityAndSandbox(lua_State* thread, RBX::Security::Identities identity, shared_ptr<BaseScript> script);
|
||||
static RBX::Security::Identities getThreadIdentity(lua_State* thread);
|
||||
|
||||
// Executes a script, throws an std::exception on error
|
||||
// The script is spawned from the global root thread, but it is "sandboxed" to the extent that global declarations
|
||||
// don't affect other threads
|
||||
// If globalStateToExecuteIn is NULL we get the global state to execute in by our current identity, which is the first arg to this function
|
||||
void executeInNewThread(RBX::Security::Identities identity, const ProtectedString& script, const char* name,
|
||||
boost::function1<size_t, lua_State*> pushArguments,
|
||||
boost::function2<void, lua_State*, size_t> readImmediateResults,
|
||||
Scripts::Continuations continuations,
|
||||
lua_State* globalStateToExecuteIn = NULL,
|
||||
const std::map<std::string, shared_ptr<Instance> >* extraGlobals = NULL,
|
||||
unsigned int modkey = 1);
|
||||
|
||||
// Resumes the thread (expects the top of the stack to contain a function)
|
||||
// Throws an std::exception if the thread throws a error
|
||||
void resumeWithArgs(Lua::ThreadRef thread, shared_ptr<const Reflection::Tuple> arguments);
|
||||
void resume(Lua::ThreadRef thread, boost::function1<size_t, lua_State*> pushArguments, boost::function2<void, lua_State*, size_t> readResults);
|
||||
|
||||
void onChangedScriptEnabled(const Reflection::PropertyDescriptor&);
|
||||
void onCheckTimeout();
|
||||
void onHook(lua_State *L, lua_Debug *ar);
|
||||
|
||||
struct ScriptStatInformation
|
||||
{
|
||||
ScriptStatInformation()
|
||||
{}
|
||||
std::string name;
|
||||
Instances scripts;
|
||||
};
|
||||
std::map<std::string, ScriptStatInformation> scriptHashInfo;
|
||||
|
||||
// Functions exposed in the Lua environment:
|
||||
public:
|
||||
static void hook(lua_State *L, lua_Debug *ar);
|
||||
void reportError(lua_State* thread);
|
||||
|
||||
lua_State* getGlobalState(RBX::Security::Identities identity);
|
||||
|
||||
private:
|
||||
static int print(lua_State *L);
|
||||
static int doPrint(lua_State *thread, const MessageType& messageType = MESSAGE_OUTPUT);
|
||||
static int crash(lua_State *L);
|
||||
static int tick(lua_State* thread);
|
||||
static int rbxTime(lua_State* thread);
|
||||
static int time(lua_State* thread);
|
||||
static int wait(lua_State* thread);
|
||||
static int delay(lua_State* thread);
|
||||
static int ypcall(lua_State* thread);
|
||||
void on_ypcall_success(Lua::WeakThreadRef caller, lua_State* functor);
|
||||
void on_ypcall_failure(Lua::WeakThreadRef caller, lua_State* functor);
|
||||
static int spawn(lua_State* thread);
|
||||
static int printidentity(lua_State* thread);
|
||||
static int loadfile(lua_State* thread);
|
||||
static int loadstring(lua_State* thread);
|
||||
static int notImplemented(lua_State* thread);
|
||||
static int dofile(lua_State* thread);
|
||||
static int settings(lua_State* thread);
|
||||
static int usersettings(lua_State* thread);
|
||||
static int pluginmanager(lua_State* thread);
|
||||
static int debuggermanager(lua_State *thread);
|
||||
static int loadLibrary(lua_State* L);
|
||||
static int loadRobloxLibrary(lua_State* L);
|
||||
static int requireModuleScript(lua_State* L);
|
||||
static int stats(lua_State* thread);
|
||||
static int version(lua_State* thread);
|
||||
static int statsitemvalue(lua_State* thread);
|
||||
|
||||
static int requireModuleScriptFromInstance(lua_State* L, shared_ptr<ModuleScript> moduleScript);
|
||||
static int requireModuleScriptFromAssetId(lua_State* L, int assetId);
|
||||
static void moduleContentLoaded(AsyncHttpQueue::RequestResult result, shared_ptr<Instances> instances,
|
||||
ScriptContext& sc, Security::Identities identity, lua_State* globalState, AssetModuleInfo* info);
|
||||
static void moduleContentLinkedSourcesResolved(shared_ptr<Instances> instances,
|
||||
shared_ptr<ModuleScript> foundModuleScript, ScriptContext& sc, Security::Identities identity,
|
||||
lua_State* globalState, AssetModuleInfo* info);
|
||||
void startRunningModuleScript(Security::Identities identity, lua_State* globalState, shared_ptr<ModuleScript> moduleScript);
|
||||
static void requireModuleScriptSuccessContinuation(shared_ptr<ModuleScript> moduleScript,
|
||||
lua_State* threadRunningModuleCode);
|
||||
static void requireModuleScriptErrorContinuation(shared_ptr<ModuleScript> moduleScript,
|
||||
lua_State* threadRunningModuleCode);
|
||||
|
||||
static void reloadModuleScriptInternal(lua_State* globalState, shared_ptr<ModuleScript> moduleScript);
|
||||
|
||||
static void reloadModuleScriptSuccessContinuation(shared_ptr<ModuleScript> moduleScript,
|
||||
lua_State* reloadThread,
|
||||
int oldResultRegistryIndex);
|
||||
|
||||
static void reloadModuleScriptErrorContinuation(shared_ptr<ModuleScript> moduleScript,
|
||||
lua_State* reloadThread);
|
||||
|
||||
static int warn(lua_State *L);
|
||||
static void validateThreadAccess(lua_State* L);
|
||||
static int resumeImpl(lua_State* L, int nargs);
|
||||
|
||||
int camelCaseViolationCount;
|
||||
rbx::signals::connection camelCaseViolationConnection;
|
||||
void onCamelCaseViolation(shared_ptr<Instance> object, std::string memberName, shared_ptr<Instance> script);
|
||||
|
||||
friend class BaseScript;
|
||||
void disassociateState(BaseScript* script);
|
||||
|
||||
bool openState(size_t idx);
|
||||
void closeState(lua_State* globalState);
|
||||
|
||||
void startScript(ScriptStart scriptStart);
|
||||
static void eraseScript(std::vector<ScriptContext::ScriptStart>& container, BaseScript* script);
|
||||
void startPendingScripts();
|
||||
|
||||
unsigned int coreScriptModKey;
|
||||
};
|
||||
|
||||
#ifdef _DEBUG
|
||||
class StackBalanceCheck
|
||||
{
|
||||
const int oldTop;
|
||||
lua_State *thread;
|
||||
bool cancelled;
|
||||
public:
|
||||
StackBalanceCheck(lua_State *thread);
|
||||
~StackBalanceCheck();
|
||||
void cancel() { cancelled = true; }
|
||||
};
|
||||
#define RBXASSERT_BALLANCED_LUA_STACK(L) StackBalanceCheck stackBalanceCheck(L)
|
||||
#define RBXASSERT_BALLANCED_LUA_STACK2(L) StackBalanceCheck stackBalanceCheck2(L)
|
||||
#define CANCEL_BALLANCED_LUA_STACK_CHECK() stackBalanceCheck.cancel()
|
||||
#define CANCEL_BALLANCED_LUA_STACK_CHECK2() stackBalanceCheck2.cancel()
|
||||
#else
|
||||
#define RBXASSERT_BALLANCED_LUA_STACK(L) ((void)0)
|
||||
#define RBXASSERT_BALLANCED_LUA_STACK2(L) ((void)0)
|
||||
#define CANCEL_BALLANCED_LUA_STACK_CHECK() ((void)0)
|
||||
#define CANCEL_BALLANCED_LUA_STACK_CHECK2() ((void)0)
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "util/runstateowner.h"
|
||||
#include "g3d/Array.h"
|
||||
#include "boost/any.hpp"
|
||||
#include "boost/shared_ptr.hpp"
|
||||
#include "lua/luabridge.h"
|
||||
#include "script/threadref.h"
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
struct lua_State;
|
||||
class ThreadInfo;
|
||||
|
||||
|
||||
|
||||
namespace RBX {
|
||||
class Instance;
|
||||
class ScriptContext;
|
||||
|
||||
namespace Lua {
|
||||
|
||||
class YieldingThreads
|
||||
{
|
||||
ScriptContext* context;
|
||||
|
||||
struct WaitingThread
|
||||
{
|
||||
boost::intrusive_ptr<WeakThreadRef> thread;
|
||||
RBX::Time waitTime;
|
||||
RBX::Time resumeTime;
|
||||
WaitingThread(lua_State *L, RBX::Time::Interval requestedDelay)
|
||||
:thread(new WeakThreadRef(L)),
|
||||
waitTime(RBX::Time::now<RBX::Time::Precise>())
|
||||
{
|
||||
resumeTime = waitTime + requestedDelay;
|
||||
}
|
||||
|
||||
bool operator <(const WaitingThread& other) const
|
||||
{
|
||||
return this->resumeTime > other.resumeTime;
|
||||
}
|
||||
};
|
||||
typedef std::priority_queue< WaitingThread > WaitThreadRefs;
|
||||
|
||||
// Lua refs to threads that are waiting on the event
|
||||
WaitThreadRefs waitingThreads;
|
||||
|
||||
public:
|
||||
YieldingThreads(ScriptContext* context);
|
||||
|
||||
// Hooking up consumers:
|
||||
void queueWaiter(lua_State *L);
|
||||
void queueWaiter(lua_State *L, LUA_NUMBER delay);
|
||||
|
||||
void resume(double wallTime, Time expirationTime, bool& throttling);
|
||||
|
||||
std::size_t waiterCount() const;
|
||||
|
||||
private:
|
||||
friend class ScriptContext;
|
||||
void clearAllSinks();
|
||||
};
|
||||
|
||||
// specialization
|
||||
template<>
|
||||
int Bridge<rbx::signals::connection>::on_tostring(const rbx::signals::connection& object, lua_State *L);
|
||||
|
||||
template<>
|
||||
int Bridge<boost::intrusive_ptr<class WeakThreadRef::Node> >::on_tostring(const boost::intrusive_ptr<class WeakThreadRef::Node>& object, lua_State *L);
|
||||
|
||||
template<>
|
||||
int Bridge< shared_ptr<GenericFunction> >::on_tostring(const shared_ptr<GenericFunction>& object, lua_State *L);
|
||||
|
||||
template<>
|
||||
int Bridge< shared_ptr<GenericAsyncFunction> >::on_tostring(const shared_ptr<GenericAsyncFunction>& object, lua_State *L);
|
||||
|
||||
} }
|
||||
@@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
#include "rbx/RunningAverage.h"
|
||||
#include "boost/weak_ptr.hpp"
|
||||
#include "util/Utilities.h"
|
||||
#include "V8DataModel/Stats.h"
|
||||
#include "script/ScriptContext.h"
|
||||
#include <stack>
|
||||
#include <map>
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
|
||||
class ScriptStats
|
||||
{
|
||||
public:
|
||||
struct StatCollection
|
||||
{
|
||||
boost::shared_ptr<ActivityMeter<2> > activity;
|
||||
boost::shared_ptr<InvocationMeter<2> > invocations;
|
||||
};
|
||||
typedef std::map<std::string, StatCollection> ScriptActivityMeterMap;
|
||||
|
||||
protected:
|
||||
ScriptActivityMeterMap scriptActivityMap;
|
||||
|
||||
std::stack<std::string> scriptStack;
|
||||
|
||||
void stopCollection(const std::string& scriptHash);
|
||||
void startCollection(const std::string& scriptHash, bool firstTime);
|
||||
public:
|
||||
|
||||
ScriptStats();
|
||||
|
||||
void scriptResumeStarted(const std::string& scriptHash);
|
||||
void scriptResumeStopped(const std::string& scriptHash);
|
||||
|
||||
const ScriptActivityMeterMap& getScriptActivityMap() const { return scriptActivityMap; }
|
||||
};
|
||||
|
||||
class LuaStatsItem : public Stats::Item
|
||||
{
|
||||
ScriptContext* scriptContext;
|
||||
Stats::Item* averageGcInterval;
|
||||
Stats::Item* averageGcTime;
|
||||
Stats::Item* resumedThreads;
|
||||
Stats::Item* deferredThreads;
|
||||
|
||||
public:
|
||||
LuaStatsItem(ScriptContext* context) : scriptContext(context)
|
||||
{
|
||||
setName("Lua");
|
||||
}
|
||||
|
||||
static shared_ptr<LuaStatsItem> create(ScriptContext* context)
|
||||
{
|
||||
shared_ptr<LuaStatsItem> result = Creatable<Instance>::create<LuaStatsItem>(context);
|
||||
result->init();
|
||||
return result;
|
||||
}
|
||||
|
||||
void init();
|
||||
|
||||
virtual void update();
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
#pragma once
|
||||
|
||||
#include "rbx/intrusive_ptr_target.h"
|
||||
#include "boost/intrusive_ptr.hpp"
|
||||
#include "rbx/boost.hpp"
|
||||
#include "rbx/threadsafe.h"
|
||||
#include "reflection/type.h"
|
||||
|
||||
struct lua_State;
|
||||
|
||||
using boost::shared_ptr;
|
||||
|
||||
LOGGROUP(WeakThreadRef)
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace Lua {
|
||||
|
||||
void dumpThreadRefCounts();
|
||||
|
||||
// Used internally
|
||||
namespace detail {
|
||||
class LiveThreadRef
|
||||
: public rbx::quick_intrusive_ptr_target<LiveThreadRef>
|
||||
, public Diagnostics::Countable<LiveThreadRef>
|
||||
, boost::noncopyable
|
||||
{
|
||||
lua_State* L;
|
||||
int threadId;
|
||||
friend class WeakThreadRef;
|
||||
friend class ThreadRef;
|
||||
public:
|
||||
// Do not create this. It is an internal class
|
||||
LiveThreadRef (lua_State* thread);
|
||||
~LiveThreadRef();
|
||||
bool empty() const {
|
||||
return L == NULL;
|
||||
}
|
||||
lua_State* thread() const {
|
||||
return L;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
// You get this by calling lock() on WeakThreadRef
|
||||
class ThreadRef
|
||||
: public Diagnostics::Countable<ThreadRef>
|
||||
{
|
||||
boost::intrusive_ptr<detail::LiveThreadRef> liveThreadRef;
|
||||
friend class WeakThreadRef;
|
||||
ThreadRef (detail::LiveThreadRef* liveThreadRef):liveThreadRef(liveThreadRef) {}
|
||||
public:
|
||||
ThreadRef() {}
|
||||
ThreadRef(lua_State* thread)
|
||||
:liveThreadRef(new detail::LiveThreadRef(thread)) {}
|
||||
lua_State* get() const {
|
||||
return liveThreadRef ? liveThreadRef->thread() : NULL;
|
||||
}
|
||||
operator lua_State*() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
bool empty() const {
|
||||
return liveThreadRef && liveThreadRef->thread() != NULL;
|
||||
}
|
||||
};
|
||||
|
||||
// Registers a weak reference to a thread, ensuring that it isn't collected (sometimes)
|
||||
class WeakThreadRef
|
||||
: public rbx::quick_intrusive_ptr_target<WeakThreadRef>
|
||||
, boost::noncopyable
|
||||
, public Diagnostics::Countable<WeakThreadRef>
|
||||
{
|
||||
// TODO: boost::mutex would be safer
|
||||
typedef rbx::spin_mutex Mutex;
|
||||
static Mutex sync;
|
||||
public:
|
||||
class Node
|
||||
: public rbx::quick_intrusive_ptr_target<Node>
|
||||
, boost::noncopyable
|
||||
{
|
||||
friend class WeakThreadRef;
|
||||
WeakThreadRef* first;
|
||||
public:
|
||||
Node():first(0) {}
|
||||
~Node();
|
||||
static boost::intrusive_ptr<Node> create(lua_State* thread);
|
||||
static Node* get(lua_State* thread);
|
||||
|
||||
// Clear all refs to thread and its children
|
||||
void eraseAllRefs();
|
||||
|
||||
template<class Func>
|
||||
void forEachRefs(Func func)
|
||||
{
|
||||
for (WeakThreadRef* ref = first; ref!=NULL; ref = ref->next)
|
||||
{
|
||||
func(ref->lock());
|
||||
}
|
||||
}
|
||||
};
|
||||
friend class Node;
|
||||
private:
|
||||
WeakThreadRef* previous;
|
||||
WeakThreadRef* next;
|
||||
boost::intrusive_ptr<detail::LiveThreadRef> liveThreadRef;
|
||||
void addRef(lua_State* L);
|
||||
void addToNode();
|
||||
void removeFromNode();
|
||||
protected:
|
||||
Node* node;
|
||||
virtual void removeRef();
|
||||
lua_State* thread() const {
|
||||
return threadDangerous();
|
||||
}
|
||||
public:
|
||||
WeakThreadRef():node(0), previous(0), next(0) {}
|
||||
WeakThreadRef(lua_State* thread);
|
||||
WeakThreadRef(const WeakThreadRef& other);
|
||||
WeakThreadRef& operator=(const WeakThreadRef& other);
|
||||
virtual ~WeakThreadRef();
|
||||
|
||||
bool operator==(const WeakThreadRef& other) const;
|
||||
bool operator!=(const WeakThreadRef& other) const;
|
||||
void reset();
|
||||
bool empty() const {
|
||||
return liveThreadRef ? liveThreadRef->thread()==0 : true;
|
||||
}
|
||||
ThreadRef lock()
|
||||
{
|
||||
return ThreadRef(liveThreadRef.get());
|
||||
}
|
||||
lua_State* threadDangerous() const {
|
||||
return liveThreadRef ? liveThreadRef->thread() : NULL;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// A function that takes any number of arguments and returns a tuple
|
||||
typedef boost::function<shared_ptr<const Reflection::Tuple>(shared_ptr<const Reflection::Tuple>)> GenericFunction;
|
||||
|
||||
class IAsyncResult
|
||||
{
|
||||
public:
|
||||
// This may throw
|
||||
virtual boost::shared_ptr<const Reflection::Tuple> getValue() = 0;
|
||||
virtual ~IAsyncResult() {}
|
||||
};
|
||||
// A function that takes any number of arguments and returns the result through a callback
|
||||
typedef boost::function<void(shared_ptr<const Reflection::Tuple>, boost::function<void(IAsyncResult*)>)> GenericAsyncFunction;
|
||||
|
||||
class WeakFunctionRef : public WeakThreadRef
|
||||
{
|
||||
private:
|
||||
int functionId;
|
||||
typedef WeakThreadRef Super;
|
||||
public:
|
||||
WeakFunctionRef():functionId(0) {}
|
||||
|
||||
WeakFunctionRef(lua_State* thread, int index); // Constructs a FunctionRef from the Lua stack
|
||||
|
||||
virtual ~WeakFunctionRef();
|
||||
|
||||
// Copy:
|
||||
WeakFunctionRef(const WeakFunctionRef& other);
|
||||
WeakFunctionRef& operator=(const WeakFunctionRef& other);
|
||||
|
||||
// Query:
|
||||
bool operator==(const WeakFunctionRef& other) const;
|
||||
bool operator!=(const WeakFunctionRef& other) const;
|
||||
|
||||
friend WeakFunctionRef lua_tofunction(lua_State* L);
|
||||
friend void lua_pushfunction(lua_State* L, const WeakFunctionRef& function);
|
||||
protected:
|
||||
virtual void removeRef();
|
||||
};
|
||||
|
||||
// Operations with Lua
|
||||
WeakFunctionRef lua_tofunction(lua_State* L, int index);
|
||||
void lua_pushfunction(lua_State* L, const WeakFunctionRef& function);
|
||||
void lua_pushfunction(lua_State* L, shared_ptr<GenericFunction> function);
|
||||
void lua_pushfunction(lua_State* L, shared_ptr<GenericAsyncFunction> function);
|
||||
|
||||
} }
|
||||
@@ -0,0 +1,192 @@
|
||||
#pragma once
|
||||
|
||||
#include "V8Tree/Instance.h"
|
||||
#include "Script/ThreadRef.h"
|
||||
#include "Util/ScriptInformationProvider.h"
|
||||
#include "Util/ProtectedString.h"
|
||||
#include "script/LuaSourceContainer.h"
|
||||
#include "rbx/atomic.h"
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/flyweight.hpp>
|
||||
|
||||
struct lua_State;
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class IScriptOwner;
|
||||
class ScriptContext;
|
||||
class RuntimeScriptService;
|
||||
class ScriptInformationProvider;
|
||||
class ContentProvider;
|
||||
|
||||
namespace Network
|
||||
{
|
||||
class Player;
|
||||
}
|
||||
|
||||
typedef ContentId ScriptId;
|
||||
extern const char* const sBaseScript;
|
||||
class BaseScript
|
||||
: public DescribedNonCreatable<BaseScript, LuaSourceContainer, sBaseScript>
|
||||
{
|
||||
private:
|
||||
typedef DescribedNonCreatable<BaseScript, LuaSourceContainer, sBaseScript> Super;
|
||||
|
||||
public:
|
||||
class Slot;
|
||||
|
||||
// Used for development only. It allows you to load CoreScripts from your local disk
|
||||
static std::string adminScriptsPath;
|
||||
static bool hasCoreScriptReplacements();
|
||||
|
||||
void restartScript();
|
||||
protected:
|
||||
RuntimeScriptService* workspace;
|
||||
|
||||
///////////////////////////////////
|
||||
// Instance
|
||||
/*override*/ void onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider);
|
||||
/*override*/ void onAncestorChanged(const AncestorChanged& event);
|
||||
/*override*/ void onScriptIdChanged();
|
||||
|
||||
private:
|
||||
static const std::string emptyString;
|
||||
|
||||
weak_ptr<RBX::Network::Player> localPlayer;
|
||||
|
||||
bool disabled;
|
||||
bool badLinkedScript;
|
||||
|
||||
RuntimeScriptService* computeNewWorkspace();
|
||||
|
||||
public:
|
||||
struct Code
|
||||
{
|
||||
bool loaded;
|
||||
boost::flyweight<ProtectedString> script;
|
||||
|
||||
Code()
|
||||
:loaded(false)
|
||||
{}
|
||||
Code(const boost::flyweight<ProtectedString>& script)
|
||||
:loaded(true)
|
||||
,script(script)
|
||||
{}
|
||||
};
|
||||
BaseScript();
|
||||
~BaseScript();
|
||||
|
||||
|
||||
static const Reflection::PropDescriptor<BaseScript, ScriptId> prop_SourceCodeId;
|
||||
|
||||
weak_ptr<RBX::Network::Player> getLocalPlayer() { return localPlayer; }
|
||||
void setLocalPlayer(const shared_ptr<RBX::Network::Player>& localPlayer) { this->localPlayer = localPlayer; }
|
||||
|
||||
// Thread management
|
||||
boost::intrusive_ptr<Lua::WeakThreadRef::Node> threadNode;
|
||||
rbx::signal<void(lua_State*)> starting;
|
||||
rbx::signal<void()> stopped;
|
||||
|
||||
bool isDisabled() const { return disabled; }
|
||||
static const Reflection::PropDescriptor<BaseScript, bool> prop_Disabled;
|
||||
|
||||
virtual Code requestCode(ScriptInformationProvider* scriptInfoProvider=NULL);
|
||||
|
||||
virtual void extraErrorReporting(lua_State *thread) {}
|
||||
|
||||
//Properties
|
||||
bool getDisabled() const { return disabled; }
|
||||
void setDisabled(bool value);
|
||||
|
||||
virtual const std::string& requestHash() const;
|
||||
};
|
||||
// A BaseScript is started when a containing IScriptOwner sends it to the ScriptContext service
|
||||
extern const char* const sScript;
|
||||
class Script
|
||||
: public DescribedCreatable<Script, BaseScript, sScript>
|
||||
{
|
||||
private:
|
||||
typedef DescribedCreatable<Script, BaseScript, sScript> Super;
|
||||
|
||||
private:
|
||||
boost::flyweight<ProtectedString> embeddedSource;
|
||||
std::string embeddedSourceHash;
|
||||
|
||||
public:
|
||||
Script();
|
||||
~Script();
|
||||
|
||||
static const Reflection::PropDescriptor<Script, ProtectedString> prop_EmbeddedSourceCode;
|
||||
|
||||
/*override*/ XmlElement* writeXml(const boost::function<bool(Instance*)>& isInScope, RBX::CreatorRole creatorRole)
|
||||
{
|
||||
return Super::writeXml(isInScope, creatorRole);
|
||||
}
|
||||
|
||||
/*override*/ bool askSetParent(const Instance* instance) const
|
||||
{
|
||||
// Scripts can be anywhere
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isCodeEmbedded() const { return getScriptId().isNull(); }
|
||||
|
||||
/*override*/ Code requestCode(ScriptInformationProvider* scriptInfoProvider=NULL);
|
||||
|
||||
/*override*/ const std::string& requestHash() const;
|
||||
|
||||
void setEmbeddedCode(const ProtectedString& value);
|
||||
const boost::flyweight<ProtectedString>& getEmbeddedCode() const;
|
||||
const ProtectedString& getEmbeddedCodeSafe() const;
|
||||
/*override*/ int getPersistentDataCost() const;
|
||||
/*override*/ void fireSourceChanged();
|
||||
|
||||
private:
|
||||
std::string getHash() { return requestHash(); }
|
||||
|
||||
static const Reflection::BoundFuncDesc<Script, std::string()> func_GetHash;
|
||||
};
|
||||
|
||||
// Only runs on a local machine if either
|
||||
// a) Inside a tool which is inside a local character
|
||||
// b) Inside the local backpack
|
||||
|
||||
// Local scripts have the full power of a normal script, but can also interact with the Mouse.
|
||||
// While they are currently run client side, this is a large security hole that will have to be addressed.
|
||||
// The plan is to have them execute server side, but with an adapter taking the place of the "Mouse" object and abstracting it per-user
|
||||
//
|
||||
// A better name would be GuiScript or UserScript, if we could redo this work.
|
||||
extern const char* const sLocalScript;
|
||||
class LocalScript
|
||||
: public DescribedCreatable<LocalScript, Script, sLocalScript>
|
||||
{
|
||||
public:
|
||||
|
||||
LocalScript();
|
||||
~LocalScript() {}
|
||||
};
|
||||
|
||||
class BaseScript::Slot
|
||||
{
|
||||
rbx::signals::connection connection;
|
||||
public:
|
||||
// A Slot must keep a reference to its connection, because it
|
||||
// must be capable of disconnecting itself.
|
||||
void assignConnection(const rbx::signals::connection& connection)
|
||||
{
|
||||
this->connection = connection;
|
||||
}
|
||||
protected:
|
||||
Slot()
|
||||
{
|
||||
}
|
||||
~Slot()
|
||||
{
|
||||
// TODO: Disconnect here???
|
||||
}
|
||||
void disconnect()
|
||||
{
|
||||
connection.disconnect();
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user