mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
fahhh
This commit is contained in:
Binary file not shown.
@@ -140,6 +140,9 @@
|
||||
<OutDir>bin\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='NoOpt|Win32'">
|
||||
<IncludePath>$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSDK_IncludePath);$(CONTRIB_PATH)\boost_1_56_0\lib;</IncludePath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
@@ -302,6 +305,11 @@ cmd /c "exit /b 0"</Command>
|
||||
<TreatWarningAsError>false</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='NoOpt|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>$(CONTRIB_PATH)\boost_1_56_0\lib;$(CONTRIB_PATH)\boost_1_56_0\;</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(CONTRIB_PATH)\w3c-libwww-5.4.0\Library\src\HTList.c">
|
||||
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='ReleaseStudio|Win32'">Level1</WarningLevel>
|
||||
|
||||
@@ -27,8 +27,6 @@ list(APPEND SOURCES ${libwww_ROOT}/HTParse.c)
|
||||
set_source_files_properties(${libwww_ROOT}/HTParse.c PROPERTIES COMPILE_FLAGS "${libwww_cflags}")
|
||||
list(APPEND SOURCES ${libwww_ROOT}/HTString.c)
|
||||
set_source_files_properties(${libwww_ROOT}/HTString.c PROPERTIES COMPILE_FLAGS "${libwww_cflags}")
|
||||
list(APPEND SOURCES ${libwww_ROOT}/HTTrace.c)
|
||||
set_source_files_properties(${libwww_ROOT}/HTTrace.c PROPERTIES COMPILE_FLAGS "${libwww_cflags}")
|
||||
|
||||
if(UNIX)
|
||||
list(APPEND SOURCES util/Unix/ProgramMemoryChecker.cpp)
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#v4.0:v110:false
|
||||
NoOpt|Win32|F:\Trunk2012\BuildWatrbx\|
|
||||
NoOpt|Win32|J:\Trunk2012\Client\|
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,199 @@
|
||||
/* Copyright 2003-2006 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Gui/Gui.h"
|
||||
#include "Util/RunStateOwner.h"
|
||||
#include "V8DataModel/ChatService.h"
|
||||
#include "Util/UDim.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class SafeChat;
|
||||
class GuiObject;
|
||||
class BillboardGui;
|
||||
class ModelInstance;
|
||||
|
||||
namespace Network {
|
||||
class Player;
|
||||
class Players;
|
||||
class ChatMessage;
|
||||
}
|
||||
|
||||
class ChatLine {
|
||||
protected:
|
||||
static float ComputeBubbleLifetime(const std::string& msg, bool isSelf);
|
||||
|
||||
public:
|
||||
static const char* ELIPSES;
|
||||
static const int CchMaxChatMessageLength; // max chat message length, including null terminator and elipses.
|
||||
enum BubbleColor
|
||||
{
|
||||
WHITE,
|
||||
BLUE,
|
||||
GREEN,
|
||||
RED,
|
||||
};
|
||||
|
||||
enum ChatType
|
||||
{
|
||||
PLAYER_CHAT,
|
||||
PLAYER_TEAM_CHAT,
|
||||
PLAYER_WHISPER_CHAT,
|
||||
|
||||
GAME_MESSAGE,
|
||||
PLAYER_GAME_CHAT,
|
||||
BOT_CHAT,
|
||||
};
|
||||
|
||||
std::string message;
|
||||
const BubbleColor bubbleColor;
|
||||
const ChatType chatType;
|
||||
float startTime;
|
||||
float bubbleDieDelay;
|
||||
bool isLocalPlayer;
|
||||
boost::weak_ptr<Instance> origin;
|
||||
|
||||
const Instance* getOrigin() const { return origin.lock().get(); }
|
||||
|
||||
ChatLine(ChatType chatType, const std::string& message, float startTime, BubbleColor bubbleColor, bool isLocalPlayer);
|
||||
virtual ~ChatLine() {}
|
||||
|
||||
bool isPlayerChat() const
|
||||
{
|
||||
switch(chatType)
|
||||
{
|
||||
case PLAYER_CHAT:
|
||||
case PLAYER_TEAM_CHAT:
|
||||
case PLAYER_WHISPER_CHAT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class PlayerChatLine : public ChatLine {
|
||||
public:
|
||||
|
||||
static const char* ROBLOXNAME;
|
||||
Color3 userColor;
|
||||
|
||||
std::string user;
|
||||
float historyDieDelay;
|
||||
|
||||
const ModelInstance* getCharacter() const;
|
||||
|
||||
PlayerChatLine(ChatType chatType, boost::shared_ptr<Network::Player> player, const std::string& message, float startTime, bool isLocalPlayer);
|
||||
};
|
||||
class GameChatLine: public ChatLine
|
||||
{
|
||||
public:
|
||||
GameChatLine(boost::shared_ptr<Instance> origin, const std::string& message, float startTime, bool isLocalPlayer, BubbleColor bubbleColor);
|
||||
};
|
||||
|
||||
struct CharacterChats
|
||||
{
|
||||
CharacterChats()
|
||||
: isVisible(false)
|
||||
, isMoving(false)
|
||||
{}
|
||||
std::deque<boost::shared_ptr<ChatLine> > fifo;
|
||||
bool isVisible;
|
||||
bool isMoving;
|
||||
weak_ptr<BillboardGui> billboardGui;
|
||||
};
|
||||
|
||||
class ChatOutput
|
||||
: public GuiItem
|
||||
{
|
||||
private:
|
||||
static const int kMaxTextSize = 16;
|
||||
static const int kMaxCharsInLine = 20;
|
||||
|
||||
void createBillboardGuiHelper(Instance* instance, bool character);
|
||||
|
||||
void renderBubbleImposters(Adorn* adorn, weak_ptr<const Instance> owner, weak_ptr<PartInstance> head);
|
||||
void renderBubbles(Adorn* adorn, weak_ptr<const Instance> owner, weak_ptr<PartInstance> head, bool playerAndGameChat,
|
||||
Vector3 extentsOffset, Vector3 studsOffset);
|
||||
typedef GuiItem Super;
|
||||
static const int MaxChatBubblesPerPlayer;
|
||||
static const int MaxChatLinesPerBubble;
|
||||
|
||||
RBX::Network::Players* players;
|
||||
std::map<ChatLine::BubbleColor, shared_ptr<GuiObject> > chatBubble;
|
||||
std::map<ChatLine::BubbleColor, shared_ptr<GuiObject> > chatBubbleWithTail;
|
||||
std::map<ChatLine::BubbleColor, shared_ptr<GuiObject> > scalingChatBubbleWithTail;
|
||||
|
||||
struct ScalingInfo
|
||||
{
|
||||
Vector2 scalingCutoff;
|
||||
UDim2 fixedPosition;
|
||||
UDim2 fixedSize;
|
||||
|
||||
UDim2 scalingPosition;
|
||||
UDim2 scalingSize;
|
||||
|
||||
UDim2 getPosition(Vector2 size)
|
||||
{
|
||||
|
||||
return UDim2(size.x < scalingCutoff.x ? scalingPosition.x : fixedPosition.x,
|
||||
size.y < scalingCutoff.y ? scalingPosition.y : fixedPosition.y);
|
||||
}
|
||||
UDim2 getSize(Vector2 size)
|
||||
{
|
||||
return UDim2(size.x < scalingCutoff.x ? scalingSize.x : fixedSize.x,
|
||||
size.y < scalingCutoff.y ? scalingSize.y : fixedSize.y);
|
||||
}
|
||||
|
||||
ScalingInfo(Vector2 scalingCutoff, UDim2 fixedPosition, UDim2 fixedSize, UDim2 scalingPosition, UDim2 scalingSize)
|
||||
:scalingCutoff(scalingCutoff)
|
||||
,fixedPosition(fixedPosition)
|
||||
,fixedSize(fixedSize)
|
||||
,scalingPosition(scalingPosition)
|
||||
,scalingSize(scalingSize)
|
||||
{}
|
||||
ScalingInfo()
|
||||
{}
|
||||
};
|
||||
std::map<ChatLine::BubbleColor, ScalingInfo> scalingInfo;
|
||||
|
||||
std::map<ChatLine::BubbleColor, shared_ptr<GuiObject> > chatPlaceholder;
|
||||
|
||||
std::deque<boost::shared_ptr<ChatLine> > fifo;
|
||||
typedef std::map<const Instance*, CharacterChats> CharacterChatMap;
|
||||
CharacterChatMap characterSortedMsg;
|
||||
float time;
|
||||
|
||||
void acceleratedBubbleDecay(ChatLine* line, float wallStep, bool isMoving, bool isVisible);
|
||||
|
||||
void removeOldest();
|
||||
bool removeExpired();
|
||||
|
||||
bool bubbleChatEnabled();
|
||||
|
||||
std::string SanitizeChatLine(const std::string& msg); // truncate and make safe.
|
||||
|
||||
// Instance
|
||||
/*override*/ void onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider);
|
||||
|
||||
// Listener
|
||||
rbx::signals::scoped_connection heartbeatConnection;
|
||||
rbx::signals::scoped_connection playerChatMessageConnection;
|
||||
rbx::signals::scoped_connection gameChatMessageConnection;
|
||||
void onHeartbeat(const Heartbeat& heartbeat);
|
||||
|
||||
void onPlayerChatMessage(const Network::ChatMessage& event);
|
||||
void onGameChatMessage(boost::shared_ptr<Instance> origin, const std::string& message, ChatService::ChatColor color);
|
||||
|
||||
// GuiItem
|
||||
/*override*/ void render2d(Adorn* adorn);
|
||||
/*override*/ void render2d_bubbleStyle(Adorn* adorn, bool playerBubbleChat);
|
||||
|
||||
public:
|
||||
ChatOutput();
|
||||
~ChatOutput();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,59 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Gui/GuiDraw.h"
|
||||
|
||||
#include "GfxBase/Adorn.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class UnifiedImageWidget : public UnifiedWidget
|
||||
{
|
||||
protected:
|
||||
GuiDrawImage guiImageDraw;
|
||||
std::string imageName;
|
||||
unsigned imageState;
|
||||
public:
|
||||
UnifiedImageWidget(const std::string& imageName, int imageState)
|
||||
: imageName(imageName)
|
||||
, imageState(imageState)
|
||||
{
|
||||
}
|
||||
|
||||
Gui::WidgetState getWidgetState() const;
|
||||
|
||||
/*override*/ void render2dMe(Adorn* adorn);
|
||||
/*override*/ void setSize(const Vector2& _size) {guiImageDraw.setImageSize(_size);}
|
||||
/*override*/ Vector2 getSize(Canvas canvas) const {return guiImageDraw.getImageSize();}
|
||||
};
|
||||
|
||||
class ChatButton : public UnifiedImageWidget
|
||||
{
|
||||
private:
|
||||
/*override*/ bool isVisible() const;
|
||||
public:
|
||||
ChatButton(const std::string& imageName, unsigned imageState)
|
||||
: UnifiedImageWidget(imageName, imageState)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class ChatWidget : public UnifiedWidget
|
||||
{
|
||||
private:
|
||||
typedef UnifiedWidget Super;
|
||||
std::string findMenuString(GuiItem* item);
|
||||
|
||||
std::string code;
|
||||
|
||||
// Unified Widget
|
||||
/*override*/ void onMenuStateChanged();
|
||||
|
||||
/*override*/ GuiResponse process(const shared_ptr<InputObject>& event);
|
||||
|
||||
public:
|
||||
ChatWidget(const std::string& text, std::string code);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "Gui/GUI.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class EquationDisplay : public TextDisplay {
|
||||
private:
|
||||
std::string equation;
|
||||
|
||||
protected:
|
||||
// TextDisplay
|
||||
std::string getLabel() const;
|
||||
|
||||
public:
|
||||
EquationDisplay(
|
||||
const std::string& title,
|
||||
const std::string& equation);
|
||||
|
||||
EquationDisplay(
|
||||
const std::string& title,
|
||||
const std::string& label,
|
||||
const std::string& equation);
|
||||
|
||||
/*override*/ void render2d(Adorn* adorn);
|
||||
};
|
||||
} // namespace
|
||||
+268
@@ -0,0 +1,268 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8DataModel/InputObject.h"
|
||||
#include "Gui/GuiEvent.h"
|
||||
#include "Gui/Layout.h"
|
||||
#include "V8Tree/Instance.h"
|
||||
#include "GfxBase/Type.h"
|
||||
#include "GfxBase/Adorn.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
|
||||
extern const char* const sGuiItem;
|
||||
class GuiItem : public DescribedNonCreatable<GuiItem, Instance, sGuiItem>
|
||||
{
|
||||
private:
|
||||
typedef Instance Super;
|
||||
shared_ptr<GuiItem> focus; // TODO: It should be safe to make this a bald pointer, since focus is always a child
|
||||
Vector2 guiSize;
|
||||
|
||||
GuiResponse processNonFocus(const shared_ptr<InputObject>& event);
|
||||
void switchFocus(GuiItem* item);
|
||||
|
||||
// Instance
|
||||
/*override*/ void onDescendantRemoving(const shared_ptr<Instance>& instance);
|
||||
/*override*/ bool askAddChild(const Instance* instance) const {
|
||||
return Instance::fastDynamicCast<GuiItem>(instance)!=0;
|
||||
}
|
||||
/*override*/ const RBX::Name& getClassName() const {return RBX::Name::getNullName(); }
|
||||
|
||||
protected:
|
||||
GuiItem* getFocus() {return focus.get();}
|
||||
void loseFocus() {
|
||||
if (focus) {
|
||||
focus->onLoseFocus();
|
||||
}
|
||||
focus.reset();
|
||||
}
|
||||
|
||||
Rect getMyRect(Canvas canvas) const; // myPosition, myPosition + mySize
|
||||
|
||||
Rect2D getMyRect2D(Canvas canvas) const {
|
||||
return getMyRect(canvas).toRect2D();
|
||||
}
|
||||
|
||||
void label2d(
|
||||
Adorn* adorn,
|
||||
const std::string& label,
|
||||
const Color4& fill,
|
||||
const Color4& border,
|
||||
Text::XAlign align = Text::XALIGN_LEFT) const;
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// GUI Item virtuals
|
||||
|
||||
virtual void onLoseFocus() {}
|
||||
virtual bool canLoseFocus() {return false;} // in general, Gui Items don't lose focus while processing
|
||||
|
||||
// standard virtual overrides....
|
||||
virtual Vector2 getPosition(Canvas canvas) const {
|
||||
RBXASSERT(getGuiParent());
|
||||
return getGuiParent()->getChildPosition(this, canvas);
|
||||
}
|
||||
|
||||
virtual Vector2 getChildPosition(const GuiItem* child, Canvas canvas) const { // This should always be override if ever used
|
||||
RBXASSERT(0);
|
||||
return Vector2::zero();
|
||||
}
|
||||
|
||||
// used internally - could these be protected?
|
||||
virtual int getFontSize() const {return 12;}
|
||||
|
||||
virtual bool isVisible() const {return true;}
|
||||
|
||||
virtual std::string getTitle() {return getName();}
|
||||
|
||||
public:
|
||||
virtual Vector2 getSize(Canvas canvas) const {return getGuiSize();}
|
||||
|
||||
virtual GuiResponse process(const shared_ptr<InputObject>& event);
|
||||
|
||||
virtual void render2d(Adorn* adorn) {}
|
||||
|
||||
|
||||
GuiItem();
|
||||
~GuiItem();
|
||||
|
||||
void addGuiItem(shared_ptr<GuiItem> guiItem) {guiItem->setParent(this);}
|
||||
|
||||
void setGuiSize(const Vector2& size) {guiSize = size;}
|
||||
const Vector2& getGuiSize() const {return guiSize;}
|
||||
|
||||
GuiItem* getGuiParent();
|
||||
const GuiItem* getGuiParent() const;
|
||||
GuiItem* getGuiItem(int index);
|
||||
const GuiItem* getGuiItem(int index) const;
|
||||
|
||||
static const Color4& disabledFill();
|
||||
static const Color4& translucentBackdrop();// background of the palette
|
||||
static const Color4& menuSelect();
|
||||
};
|
||||
|
||||
extern const char* const sGuiRoot;
|
||||
|
||||
class GuiRoot :
|
||||
public Reflection::Described<GuiRoot, sGuiRoot, GuiItem, Reflection::ClassDescriptor::INTERNAL_LOCAL, RBX::Security::LocalUser>
|
||||
{
|
||||
public:
|
||||
GuiRoot();
|
||||
|
||||
/*override*/ void render2d(Adorn* adorn);
|
||||
|
||||
void render2dItem(Adorn* adorn, GuiItem* guiItem);
|
||||
|
||||
// GuiItem
|
||||
/*override*/ Vector2 getSize(Canvas canvas) const {
|
||||
// shouldn't be called - implies item doesn't know it's top level
|
||||
RBXASSERT(false);
|
||||
return canvas.size;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool askSetParent(const Instance* instance) const {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class TopMenuBar : public GuiItem {
|
||||
private:
|
||||
void init();
|
||||
|
||||
protected:
|
||||
Color4 backdropColor;
|
||||
Layout::Style layoutStyle;
|
||||
bool visible;
|
||||
|
||||
/*override*/ Vector2 getChildPosition(const GuiItem* child, Canvas canvas) const;
|
||||
|
||||
public:
|
||||
TopMenuBar() {init();}
|
||||
TopMenuBar(
|
||||
const std::string& _title,
|
||||
Layout::Style layoutStyle,
|
||||
bool translucentBackdrop = false);
|
||||
TopMenuBar(
|
||||
const std::string& _title,
|
||||
Layout::Style _layoutStyle,
|
||||
Color4 _backdropColor);
|
||||
|
||||
/*override*/ GuiResponse process(const shared_ptr<InputObject>& event);
|
||||
/*override*/ void render2d(Adorn* adorn);
|
||||
/*override*/ Vector2 getSize(Canvas canvas) const;
|
||||
/*override*/ bool isVisible() const {return visible;}
|
||||
|
||||
void setVisible(bool _set) {visible = _set;}
|
||||
};
|
||||
|
||||
|
||||
|
||||
class RelativePanel : public TopMenuBar {
|
||||
protected:
|
||||
Rect::Location xLocation;
|
||||
Rect::Location yLocation;
|
||||
Vector2int16 offset;
|
||||
|
||||
void init(const Layout& layout);
|
||||
|
||||
public:
|
||||
RelativePanel() {init(Layout());}
|
||||
RelativePanel(const Layout& layout) {init(layout);}
|
||||
|
||||
virtual Vector2 getPosition(Canvas canvas) const;
|
||||
};
|
||||
|
||||
// This will become the new unified widget - menu, button, all...
|
||||
//
|
||||
|
||||
class UnifiedWidget : public GuiItem {
|
||||
public:
|
||||
enum MenuState {NOTHING, HOVER, SHOWN_APPEARING, SHOWN}; // + focus if child is shown
|
||||
|
||||
private:
|
||||
typedef GuiItem Super;
|
||||
MenuState menuState;
|
||||
|
||||
GuiResponse processShown_InTitle(const shared_ptr<InputObject>& event);
|
||||
GuiResponse processShown_OutOfTitle(const shared_ptr<InputObject>& event);
|
||||
|
||||
GuiResponse processNothing(const shared_ptr<InputObject>& event);
|
||||
GuiResponse processHover(const shared_ptr<InputObject>& event);
|
||||
GuiResponse processShown(const shared_ptr<InputObject>& event);
|
||||
GuiResponse processKey(const shared_ptr<InputObject>& event);
|
||||
|
||||
void render2dChildren(Adorn* adorn);
|
||||
|
||||
/*override*/ Vector2 getChildPosition(const GuiItem* child, Canvas canvas) const;
|
||||
/*override*/ bool canLoseFocus() {return true;}
|
||||
/*override*/ void onLoseFocus();
|
||||
/*override*/ int getFontSize() const {return 8;}
|
||||
|
||||
void init();
|
||||
|
||||
protected:
|
||||
bool showChildren() {return (menuState >= SHOWN_APPEARING);}
|
||||
|
||||
virtual void onMenuStateChanged() {}
|
||||
virtual Vector2 firstChildPosition(Canvas canvas) const;
|
||||
virtual Vector2 childOffset() const;
|
||||
virtual void render2dMe(Adorn* adorn);
|
||||
|
||||
public:
|
||||
UnifiedWidget() {init();}
|
||||
UnifiedWidget(const std::string& title);
|
||||
|
||||
MenuState getMenuState() const {return menuState;}
|
||||
void setMenuState(MenuState value);
|
||||
|
||||
/*override*/ GuiResponse process(const shared_ptr<InputObject>& event);
|
||||
/*override*/ void render2d(Adorn* adorn);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class TextDisplay : public GuiItem {
|
||||
private:
|
||||
typedef GuiItem Super;
|
||||
|
||||
void init();
|
||||
|
||||
protected:
|
||||
std::string label;
|
||||
int fontSize;
|
||||
Color4 fontColor;
|
||||
Color4 borderColor;
|
||||
Text::XAlign align;
|
||||
bool visible;
|
||||
|
||||
/*override*/ int getFontSize() const {return fontSize;}
|
||||
/*override*/ bool isVisible() const {return visible;}
|
||||
|
||||
const std::string& getLabel() const {return label;}
|
||||
|
||||
public:
|
||||
TextDisplay() {init();}
|
||||
TextDisplay(const std::string& title, const std::string& _label);
|
||||
|
||||
/*override*/ void render2d(Adorn* adorn);
|
||||
/*override*/ Vector2 getSize(Canvas canvas) const;
|
||||
|
||||
void setLabel(const std::string& _label) {label = _label;}
|
||||
void setFontSize(int _fontSize) {
|
||||
fontSize = _fontSize;
|
||||
setGuiSize(Vector2(fontSize*10.0f, fontSize*2.0f));
|
||||
}
|
||||
void setFontColor(const Color4& _color) {fontColor = _color;}
|
||||
void setBorderColor(const Color4& _color) {borderColor = _color;}
|
||||
void setAlign(Text::XAlign _align) {align = _align;}
|
||||
void setVisible(bool _visible) {visible = _visible;}
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,76 @@
|
||||
/* Copyright 2003-2006 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8DataModel/GuiCore.h"
|
||||
#include "V8Xml/Reference.h"
|
||||
#include "Util/TextureId.h"
|
||||
#include "GfxBase/TextureProxyBase.h"
|
||||
#include "GfxBase/Adorn.h"
|
||||
#include "rbx/signal.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Adorn;
|
||||
|
||||
class GuiDrawImage
|
||||
{
|
||||
public:
|
||||
enum ImageState
|
||||
{
|
||||
NORMAL = 0x1,
|
||||
HOVER = 0x2,
|
||||
DOWN = 0x4,
|
||||
DISABLE = 0x8,
|
||||
SELECTED = 0x10,
|
||||
SELECTED_HOVER = 0x20,
|
||||
SELECTED_DOWN = 0x40,
|
||||
ALL = 0x7F
|
||||
};
|
||||
private:
|
||||
TextureId currentTexture;
|
||||
TextureId loadingTexture;
|
||||
RBX::TextureProxyBaseRef disable;
|
||||
RBX::TextureProxyBaseRef normal;
|
||||
RBX::TextureProxyBaseRef hover;
|
||||
RBX::TextureProxyBaseRef down;
|
||||
RBX::TextureProxyBaseRef selected;
|
||||
RBX::TextureProxyBaseRef selectedHover;
|
||||
RBX::TextureProxyBaseRef selectedDown;
|
||||
mutable Vector2 size;
|
||||
rbx::signals::scoped_connection unbindResourceSignalHint;
|
||||
|
||||
void OnUnbindResourceSignalHint();
|
||||
|
||||
void draw(Adorn* adorn, const RBX::TextureProxyBaseRef& texture, const Rect& rect, const Vector2& texul, const Vector2& texbr, const Color4& color,
|
||||
const Rect& clipRect, const Color4& behind, const Color4& inFront);
|
||||
|
||||
void draw(Adorn* adorn, const RBX::TextureProxyBaseRef& texture, const Rect& rect, const Vector2& texul, const Vector2& texbr, const Color4& color,
|
||||
const Rotation2D& rotation, const Color4& behind, const Color4& inFront);
|
||||
|
||||
template <typename Modifier>
|
||||
void render2dImpl(Adorn* adorn, bool enabled, const Rect& rect, const Vector2& texul, const Vector2& texbr, const Color4& color,
|
||||
const Modifier& modifier, Gui::WidgetState state, bool isSelected);
|
||||
|
||||
void tryCreateTextureProxy(Adorn *adorn, const std::string& contentString, const std::string& context, RBX::TextureProxyBaseRef& textureRef, bool& isWaiting);
|
||||
public:
|
||||
GuiDrawImage() : size(Vector2(0,0)) {}
|
||||
GuiDrawImage(Adorn *adorn, const std::string& textureName, unsigned imageState) {setImageFromName(adorn, textureName, imageState);}
|
||||
|
||||
void render2d(Adorn* adorn, bool enabled, const Rect& rect,
|
||||
Gui::WidgetState state, bool isSelected);
|
||||
void render2d(Adorn* adorn, bool enabled, const Rect& rect, const Vector2& texul, const Vector2& texbr, const Color4& color, const Rotation2D& rotation,
|
||||
Gui::WidgetState state, bool isSelected);
|
||||
void render2d(Adorn* adorn, bool enabled, const Rect& rect, const Vector2& texul, const Vector2& texbr, const Color4& color, const Rect& clipRect,
|
||||
Gui::WidgetState state, bool isSelected);
|
||||
|
||||
void setImageSize(const Vector2& _size);
|
||||
Vector2 getImageSize() const;
|
||||
|
||||
bool setImage(Adorn* adorn, const TextureId& textureId, unsigned imageState, Vector2* outSize = NULL, Instance* contextInstance = NULL, const char* context = "");
|
||||
bool setImageFromName(Adorn* adorn, const std::string& textureName, unsigned imageState, Instance* contextInstance = NULL, const char* context = "");
|
||||
|
||||
void computeUV(Vector2& uvtl, Vector2& uvbr, const Vector2& imageRectOffset, const Vector2& imageRectSize, const Vector2& imageSize);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,62 @@
|
||||
/* Copyright 2003-2015 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "v8tree/Instance.h"
|
||||
|
||||
LOGGROUP(GuiTargetLifetime)
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class GuiResponse
|
||||
{
|
||||
private:
|
||||
enum ResponseType {NOT_SUNK, SUNK};
|
||||
enum FinishedType {NOT_FINISHED, FINISHED};
|
||||
enum MouseOverType {NOT_MOUSE_OVER, MOUSE_OVER};
|
||||
|
||||
ResponseType response;
|
||||
FinishedType finished;
|
||||
MouseOverType mouseWasOver;
|
||||
weak_ptr<Instance> target;
|
||||
|
||||
GuiResponse(ResponseType response, FinishedType finished, MouseOverType mouseWasOver, Instance* newTarget)
|
||||
: response(response)
|
||||
, finished(finished)
|
||||
, mouseWasOver(mouseWasOver)
|
||||
, target(weak_from(newTarget))
|
||||
{}
|
||||
|
||||
GuiResponse(ResponseType response)
|
||||
: response(response)
|
||||
, finished(NOT_FINISHED)
|
||||
, mouseWasOver(NOT_MOUSE_OVER)
|
||||
{}
|
||||
|
||||
public:
|
||||
GuiResponse()
|
||||
: response(NOT_SUNK)
|
||||
, finished(NOT_FINISHED)
|
||||
, mouseWasOver(NOT_MOUSE_OVER)
|
||||
{}
|
||||
|
||||
bool getMouseWasOver() const {return mouseWasOver == MOUSE_OVER;}
|
||||
void setMouseWasOver() {mouseWasOver = MOUSE_OVER;}
|
||||
|
||||
bool wasSunk() {return (response == SUNK);}
|
||||
bool wasSunkAndFinished()
|
||||
{
|
||||
RBXASSERT(!((finished == FINISHED) && !wasSunk()));
|
||||
return (finished == FINISHED);
|
||||
}
|
||||
|
||||
static GuiResponse notSunk() {return GuiResponse(NOT_SUNK);}
|
||||
static GuiResponse notSunkMouseWasOver() {return GuiResponse(NOT_SUNK, NOT_FINISHED, MOUSE_OVER, NULL);}
|
||||
static GuiResponse sunk() {return GuiResponse(SUNK);}
|
||||
static GuiResponse sunkAndFinished() {return GuiResponse(SUNK, FINISHED, NOT_MOUSE_OVER, NULL);}
|
||||
static GuiResponse sunkWithTarget(Instance* target) {return GuiResponse(SUNK, NOT_FINISHED, NOT_MOUSE_OVER, target);}
|
||||
|
||||
shared_ptr<Instance> getTarget() { return target.lock(); }
|
||||
void setTarget(Instance* value) { target = weak_from(value); }
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,29 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Util/Rect.h"
|
||||
#include "Util/G3DCore.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Layout
|
||||
{
|
||||
public:
|
||||
enum Style {HORIZONTAL = 0, VERTICAL = 1};
|
||||
|
||||
Rect::Location xLocation;
|
||||
Rect::Location yLocation;
|
||||
Vector2int16 offset;
|
||||
Style layoutStyle;
|
||||
Color4 backdropColor;
|
||||
|
||||
Layout()
|
||||
: xLocation(Rect::LEFT)
|
||||
, yLocation(Rect::TOP)
|
||||
, offset(Vector2int16(0,0))
|
||||
, layoutStyle(HORIZONTAL)
|
||||
, backdropColor(Color4::clear())
|
||||
{}
|
||||
};
|
||||
} // namespace
|
||||
@@ -0,0 +1,35 @@
|
||||
/* Copyright 2003-2006 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Util/ScopedSingleton.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class WordList
|
||||
{
|
||||
private:
|
||||
std::set<std::string> blacklist;
|
||||
void decrypt(std::string& str);
|
||||
public:
|
||||
WordList();
|
||||
~WordList();
|
||||
|
||||
bool ContainsProfanity(std::string str);
|
||||
|
||||
};
|
||||
|
||||
|
||||
class ProfanityFilter : public ScopedSingleton<ProfanityFilter>
|
||||
{
|
||||
private:
|
||||
WordList *wordlist;
|
||||
bool ContainsProfanityWorker(std::string str);
|
||||
public:
|
||||
ProfanityFilter();
|
||||
~ProfanityFilter();
|
||||
|
||||
static bool ContainsProfanity(const std::string& str);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,14 @@
|
||||
/* Copyright 2003-2008 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Gui/Gui.h"
|
||||
#include "Util/RunStateOwner.h"
|
||||
#include "Network/Player.h"
|
||||
#include "Network/Players.h"
|
||||
#include "V8DataModel/team.h"
|
||||
#include "V8DataModel/teams.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,47 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Gui/GUI.h"
|
||||
#include "V8Tree/Verb.h"
|
||||
#include "V8DataModel/GuiCore.h"
|
||||
#include "v8datamodel/InputObject.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Widget : public GuiItem
|
||||
{
|
||||
private:
|
||||
typedef GuiItem Super;
|
||||
GuiResponse processMouse(const shared_ptr<InputObject>& event);
|
||||
GuiResponse processKey(const shared_ptr<InputObject>& event);
|
||||
|
||||
protected:
|
||||
Gui::WidgetState widgetState;
|
||||
|
||||
// This should be standard for all widgets, verb widets, etc.
|
||||
/*override*/ GuiResponse process(const shared_ptr<InputObject>& event);
|
||||
/*override*/ void onLoseFocus() {
|
||||
widgetState = Gui::NOTHING;
|
||||
Super::onLoseFocus();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
//
|
||||
// Override these to make new widgets
|
||||
|
||||
// GUI ITEM
|
||||
/*override*/ void render2d(Adorn* adorn);
|
||||
|
||||
// WIDGET
|
||||
virtual void onClick(const shared_ptr<InputObject>& event) {}
|
||||
virtual int getFontSize() const {return 10;}
|
||||
virtual G3D::Color4 getFontColor() {return G3D::Color3::white();}
|
||||
virtual bool isEnabled() {return isVisible();}
|
||||
|
||||
public:
|
||||
Widget();
|
||||
};
|
||||
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,39 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Humanoid/HumanoidState.h"
|
||||
|
||||
namespace RBX {
|
||||
namespace HUMAN {
|
||||
|
||||
|
||||
class Balancing : public HumanoidState
|
||||
{
|
||||
private:
|
||||
float kP; // units: 1/sec^2 torque = kP * momentOfInertia * rotation
|
||||
float kD; // units: 1/sec torque = kD * momentOfInertia * rotVelocity
|
||||
|
||||
Vector3 lastBalanceTorque;
|
||||
int tick;
|
||||
|
||||
static int balanceRate(double torqueMag);
|
||||
static int balanceRateForPGS();
|
||||
protected:
|
||||
static const float maxTorqueComponent() {return 4000.0f;} // units: 1/sec^2 torque <= maxTorqueComponent * momentOfInertia
|
||||
|
||||
void setBalanceP(float P) { kP = P; };
|
||||
void setBalanceD(float D) { kD = D; };
|
||||
|
||||
// Humanoid::State
|
||||
/*override*/ void onComputeForceImpl();
|
||||
|
||||
public:
|
||||
Balancing(Humanoid* humanoid, StateType priorState);
|
||||
Balancing(Humanoid* humanoid, StateType priorState, const float kP, const float kD);
|
||||
};
|
||||
|
||||
|
||||
} // namespace HUMAN
|
||||
} // namespace RBX
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Humanoid/HumanoidState.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace HUMAN {
|
||||
|
||||
// pure simulation!
|
||||
|
||||
extern const char* const sDead;
|
||||
class Dead : public Named<HumanoidState, sDead>
|
||||
{
|
||||
private:
|
||||
/*override*/ StateType getStateType() const {return DEAD;}
|
||||
/*override*/ void onStepImpl();
|
||||
/*override*/ void onSimulatorStepImpl(float stepDt);
|
||||
/*override*/ void onComputeForceImpl() {}
|
||||
/*override*/ bool enableAutoJump() const { return false; }
|
||||
public:
|
||||
Dead(Humanoid* humanoid, StateType priorState);
|
||||
};
|
||||
|
||||
|
||||
extern const char* const sFallingDown;
|
||||
class FallingDown : public Named<HumanoidState, sFallingDown>
|
||||
{
|
||||
private:
|
||||
/*override*/ StateType getStateType() const {return FALLING_DWN;}
|
||||
/*override*/ void onComputeForceImpl() {}
|
||||
/*override*/ bool enableAutoJump() const { return false; }
|
||||
public:
|
||||
FallingDown(Humanoid* humanoid, StateType priorState);
|
||||
};
|
||||
|
||||
extern const char* const sPhysics;
|
||||
class Physics : public Named<HumanoidState, sPhysics>
|
||||
{
|
||||
private:
|
||||
/*override*/ StateType getStateType() const {return PHYSICS;}
|
||||
/*override*/ void onComputeForceImpl() {}
|
||||
/*override*/ bool enableAutoJump() const { return false; }
|
||||
public:
|
||||
Physics(Humanoid* humanoid, StateType priorState);
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace HUMAN
|
||||
} // namespace RBX
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Humanoid/Balancing.h"
|
||||
#include "Util/Name.h"
|
||||
|
||||
namespace RBX {
|
||||
namespace HUMAN {
|
||||
|
||||
// Flying occurs when there's no ground below you. You have the ability
|
||||
// to turn around the y-axis, but not much else.
|
||||
extern const char* const sFlying;
|
||||
|
||||
class Flying : public Named<Balancing, sFlying>
|
||||
{
|
||||
private:
|
||||
/*override*/ StateType getStateType() const {return FLYING;}
|
||||
|
||||
protected:
|
||||
// Humanoid::State
|
||||
/*override*/ void onSimulatorStepImpl(float stepDt);
|
||||
/*override*/ void onComputeForceImpl();
|
||||
/*override*/ bool enableAutoJump() const { return false; }
|
||||
|
||||
public:
|
||||
Flying(Humanoid* humanoid, StateType priorState);
|
||||
};
|
||||
|
||||
} // namespace HUMAN
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Humanoid/Balancing.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace HUMAN {
|
||||
|
||||
extern const char* const sFreefall;
|
||||
|
||||
class Freefall : public Named<Balancing, sFreefall>
|
||||
{
|
||||
private:
|
||||
typedef Named<Balancing, sFreefall> Super;
|
||||
bool initialized; // hack- some data is bad in the constructor - do first time through;
|
||||
Vector3 initialLinearVelocity;
|
||||
Velocity desiredVelocity; // Y is world-up
|
||||
float torsoFriction; // I set both of these to zero!
|
||||
float headFriction;
|
||||
|
||||
/*override*/ StateType getStateType() const {return FREE_FALL;}
|
||||
|
||||
/*override*/ void onSimulatorStepImpl(float stepDt);
|
||||
|
||||
/*override*/ void onComputeForceImpl();
|
||||
|
||||
/*override*/ int ladderCheckRate() { return 0; }
|
||||
|
||||
/*override*/ bool armsShouldCollide() const {return false;}
|
||||
/*override*/ bool legsShouldCollide() const {return false;}
|
||||
/*override*/ bool enableAutoJump() const { return false; }
|
||||
|
||||
static float characterVelocityInfluence();
|
||||
static float floorVelocityInfluence();
|
||||
static float velocityDecay();
|
||||
|
||||
public:
|
||||
Freefall(Humanoid* humanoid, StateType priorState);
|
||||
|
||||
~Freefall();
|
||||
|
||||
static float kTurnSpeed();
|
||||
static float kTurnSpeedForPGS();
|
||||
static const float kTurnAccelMax() {return 20000.0f * kTurnSpeed();} // units: 1/sec^2
|
||||
};
|
||||
|
||||
} // namespace HUMAN
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Humanoid/Humanoid.h"
|
||||
#include "Humanoid/Balancing.h"
|
||||
#include "Util/Name.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace HUMAN {
|
||||
|
||||
extern const char* const sGettingUp;
|
||||
|
||||
class GettingUp : public Named<Balancing, sGettingUp>
|
||||
{
|
||||
protected:
|
||||
/*override*/ StateType getStateType() const {return GETTING_UP;}
|
||||
|
||||
/*override*/ bool armsShouldCollide() const {return false;}
|
||||
/*override*/ bool legsShouldCollide() const {return false;}
|
||||
/*override*/ bool enableAutoJump() const { return false; }
|
||||
|
||||
public:
|
||||
GettingUp(Humanoid* humanoid, StateType priorState);
|
||||
};
|
||||
|
||||
} // HUMAN
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,621 @@
|
||||
/* Copyright 2003-2007 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8DataModel/ICharacterSubject.h"
|
||||
#include "V8DataModel/IModelModifier.h"
|
||||
#include "V8DataModel/PartInstance.h"
|
||||
#include "V8DataModel/Tool.h"
|
||||
#include "V8World/KernelJoint.h"
|
||||
#include "V8World/Primitive.h"
|
||||
#include "Util/SteppedInstance.h"
|
||||
#include "GfxBase/IAdornable.h"
|
||||
#include "Util/RunStateOwner.h"
|
||||
#include "Util/ContentFilter.h"
|
||||
#include "Util/HeapValue.h"
|
||||
#include "Humanoid/StatusInstance.h"
|
||||
#include "Humanoid/HumanoidState.h"
|
||||
|
||||
namespace RBX {
|
||||
class World;
|
||||
class RunService;
|
||||
class Controller;
|
||||
class Primitive;
|
||||
class PartInstance;
|
||||
class ModelInstance;
|
||||
class JointInstance;
|
||||
class DataModelMesh;
|
||||
class Decal;
|
||||
class Weld;
|
||||
class Animator;
|
||||
|
||||
namespace HUMAN {
|
||||
class HumanoidState;
|
||||
}
|
||||
|
||||
namespace Soundscape {
|
||||
class SoundChannel;
|
||||
}
|
||||
|
||||
extern const char* const sHumanoid;
|
||||
class Humanoid
|
||||
: public DescribedCreatable<Humanoid, Instance, sHumanoid>
|
||||
, public KernelJoint // Implements "computeForce"
|
||||
, public IAdornable
|
||||
, public ICharacterSubject
|
||||
, public IModelModifier
|
||||
, public IStepped
|
||||
{
|
||||
public:
|
||||
enum NameOcclusion
|
||||
{
|
||||
NAME_OCCLUSION_NONE = 0,
|
||||
NAME_OCCLUSION_ENEMY = 1,
|
||||
NAME_OCCLUSION_ALL = 2,
|
||||
};
|
||||
|
||||
enum HumanoidDisplayDistanceType
|
||||
{
|
||||
HUMANOID_DISPLAY_DISTANCE_TYPE_VIEWER = 0,
|
||||
HUMANOID_DISPLAY_DISTANCE_TYPE_SUBJECT = 1,
|
||||
HUMANOID_DISPLAY_DISTANCE_TYPE_NONE = 2,
|
||||
};
|
||||
|
||||
enum HumanoidRigType
|
||||
{
|
||||
HUMANOID_RIG_TYPE_R6 = 0,
|
||||
HUMANOID_RIG_TYPE_R15 = 1,
|
||||
};
|
||||
private:
|
||||
friend unsigned int HUMAN::HumanoidState::checkComputeEvent(); // only used to check for exploits.
|
||||
|
||||
typedef DescribedCreatable<Humanoid, Instance, sHumanoid> Super;
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// REFLECTED DATA
|
||||
shared_ptr<PartInstance> seatPart; // seat the humanoid is sitting in
|
||||
shared_ptr<PartInstance> walkToPart; // if null, then use the walk speed control
|
||||
Vector3 walkToPoint; // in part coordinate Frame
|
||||
Vector3 walkDirection; // x == xvalue, y == 0, z== zvalue
|
||||
Vector3 luaMoveDirection; // unit vector, used to move humanoid continously in that direction
|
||||
Vector3 rawMovementVector; // unit vector, stores the raw input (never world adjusted)
|
||||
Vector3 targetPoint;
|
||||
Vector3 replicatedTargetPoint;
|
||||
float walkAngleError;
|
||||
HeapValue<float> walkSpeed;
|
||||
HeapValue<float> walkSpeedShadow; // due to exploits.
|
||||
HeapValue<float> percentWalkSpeed; // used to make walk speed variable (for joysticks and the like)
|
||||
HeapValue<float> health;
|
||||
HeapValue<float> maxHealth;
|
||||
mutable ObscureValue<size_t> walkSpeedErrors; // only used in const member functions...
|
||||
HeapValue<float> jumpPower;
|
||||
HeapValue<float> maxSlopeAngle;
|
||||
HeapValue<float> hipHeight;
|
||||
bool torsoArrived;
|
||||
bool jump;
|
||||
bool autoJump;
|
||||
bool sit;
|
||||
bool touchedHard;
|
||||
bool strafe;
|
||||
bool localSimulating; // am I simulating this humanoid?
|
||||
bool ownedByLocalPlayer; // is this my own humanoid?
|
||||
bool typing;
|
||||
bool autorotate;
|
||||
HumanoidRigType rigType;
|
||||
HeapValue<bool> platformStanding;
|
||||
|
||||
bool autoJumpEnabled;
|
||||
|
||||
bool activatePhysics;
|
||||
Vector3 activatePhysicsImpulse; //
|
||||
|
||||
int ragdollCriteria;
|
||||
int numContacts; // Used to signal nearlyTouched event
|
||||
NameOcclusion nameOcclusion;
|
||||
HumanoidDisplayDistanceType displayDistanceType;
|
||||
float nameDisplayDistance;
|
||||
float healthDisplayDistance;
|
||||
Vector3 cameraOffset; // When this humanoid is used as a camera target, offset the camera target by this vector
|
||||
|
||||
bool isWalkingFromStudioTouchEmulation;
|
||||
|
||||
std::string displayText;
|
||||
ContentFilter::FilterResult filterState;
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// INTERNAL DATA
|
||||
// Controller interface - server side
|
||||
bool isWalking;
|
||||
double walkTimer;
|
||||
Vector3 getDeltaToGoal() const;
|
||||
void setWalkMode(bool walking);
|
||||
void stepWalkMode(double gameDt);
|
||||
|
||||
bool clickToWalkEnabled;
|
||||
|
||||
bool stateTransitionEnabled[HUMAN::NUM_STATE_TYPES];
|
||||
|
||||
Vector3 lastFloorNormal;
|
||||
// Humanoid Network Floor Platforms
|
||||
boost::shared_ptr<PartInstance> lastFloorPart;
|
||||
boost::shared_ptr<PartInstance> rootFloorMechPart;
|
||||
int lastFilterPhase;
|
||||
|
||||
// hack - easiest place to update is on query of had neck
|
||||
bool hadNeck; // has this humanoid ever had a neck? Only break joints on death if so
|
||||
bool hadHealth; // has this humanoid ever had health > 0? Only break joints on death if so
|
||||
|
||||
Vector3 pos0; // for looking for movement spikes
|
||||
Vector3 pos1;
|
||||
Vector3 pos2;
|
||||
|
||||
void updateHadHealth() {
|
||||
hadHealth = hadHealth || (health > 0.0f);
|
||||
}
|
||||
|
||||
typedef enum {TORSO, HEAD, RIGHT_ARM, LEFT_ARM, RIGHT_LEG, LEFT_LEG, VISIBLE_TORSO, APPENDAGE_COUNT} AppendageType;
|
||||
|
||||
shared_ptr<PartInstance> appendageCache[APPENDAGE_COUNT];
|
||||
shared_ptr<PartInstance> baseInstance;
|
||||
|
||||
rbx::signals::scoped_connection characterChildAdded;
|
||||
rbx::signals::scoped_connection characterChildRemoved;
|
||||
void onEvent_ChildModified(shared_ptr<Instance> child);
|
||||
|
||||
boost::unordered_map<shared_ptr<PartInstance>, rbx::signals::scoped_connection> siblingMap;
|
||||
void updateSiblingPropertyListener(shared_ptr<PartInstance> sibling);
|
||||
void onEvent_SiblingPropertyChanged(const RBX::Reflection::PropertyDescriptor* desc);
|
||||
|
||||
shared_ptr<StatusInstance> status;
|
||||
|
||||
rbx::signals::scoped_connection onCFrameChangedConnection;
|
||||
rbx::signals::scoped_connection humanoidEquipConnection;
|
||||
|
||||
void setCachePointerByType(AppendageType appendage, PartInstance *part);
|
||||
void updateBaseInstance();
|
||||
|
||||
const PartInstance* getConstAppendageSlow(AppendageType appendage) const;
|
||||
PartInstance* getAppendageFast(AppendageType appendage, shared_ptr<PartInstance>& appendagePart);
|
||||
PartInstance* getAppendageSlow(AppendageType appendage);
|
||||
|
||||
World* world;
|
||||
shared_ptr<HUMAN::HumanoidState> currentState;
|
||||
HUMAN::StateType previousState;
|
||||
|
||||
shared_ptr<Animator> animator;
|
||||
Animator* getAnimator();
|
||||
|
||||
void updateLocalSimulating(); // Do I need to simulate this humanoid?
|
||||
|
||||
void onLocalHumanoidEnteringWorkspace();
|
||||
|
||||
void onCFrameChangedFromReflection();
|
||||
|
||||
bool hasWalkToPoint(Vector3& worldPosition) const;
|
||||
|
||||
bool canClickToWalk() const;
|
||||
|
||||
void setLocalTransparencyModifier(float transparencyModifier) const;
|
||||
|
||||
void setWalkDirectionInternal(const Vector3& value, bool raiseSignal);
|
||||
void setJumpInternal(bool value, bool replicate);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Instance
|
||||
/*override*/ bool askSetParent(const Instance* instance) const;
|
||||
/*override*/ void onAncestorChanged(const AncestorChanged& event);
|
||||
/*override*/ void setName(const std::string& value);
|
||||
/*override*/ void onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider);
|
||||
/*override*/ void onDescendantAdded(Instance* instance);
|
||||
/*override*/ void onDescendantRemoving(const shared_ptr<Instance>& instance);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// IAdornable
|
||||
/*override*/ bool shouldRender3dAdorn() const {return true;}
|
||||
/*override*/ bool shouldRender3dSortedAdorn() const {return true;}
|
||||
/*override*/ Vector3 render3dSortedPosition() const;
|
||||
/*override*/ void render3dAdorn(Adorn* adorn);
|
||||
/*override*/ void render3dSortedAdorn(Adorn* adorn);
|
||||
|
||||
void renderMultiplayer(Adorn* adorn, const RBX::Camera& camera);
|
||||
|
||||
void renderBillboard(Adorn* adorn, const RBX::Camera& camera);
|
||||
void renderBillboardImpl(Adorn* adorn, const Vector2& screenLoc, float fontSize, const Color3& nameTagColor, float nameAlpha, float healthAlpha);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// SteppedInstance
|
||||
/*override*/ void onStepped(const Stepped& event);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// KernelJoint / Connector
|
||||
/*override*/ void computeForce(bool throttling);
|
||||
/*override*/ Body* getEngineBody() {return getRootBodyFast();}
|
||||
/*override*/ virtual KernelType getConnectorKernelType() const { return Connector::HUMANOID; }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ILocation
|
||||
/*override*/ const CoordinateFrame getLocation();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// CameraSubject
|
||||
/*override*/ const CoordinateFrame getRenderLocation();
|
||||
/*override*/ const Vector3 getRenderSize();
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ICharacterSubject
|
||||
/*override*/ float getYAxisRotationalVelocity() const; // used for camera control
|
||||
/*override*/ void setFirstPersonRotationalVelocity(const Vector3& desiredLook, bool firstPersonOn);
|
||||
/*override*/ void getSelectionIgnorePrimitives(std::vector<const Primitive*>& primitives);
|
||||
/*override*/ virtual bool hasFocusCoord() const {return getHeadSlow() != NULL;}
|
||||
|
||||
// Humanoid Platform Networking
|
||||
bool validateNetworkUpdateDistance(PartInstance* floorPart, CoordinateFrame& previousFloorPosition, float& netDt);
|
||||
void truncateDisplacementIfObstacle(PartInstance* floorPart, Vector3& newCharPosition, const Vector3& previousCharPosition);
|
||||
Vector3 getSimulatedFrictionVelocityOffset(PartInstance* floorPart, Vector3& newCharPosition, const Vector3& previousCharPosition, const Vector3& charPosInFloorSpace, const RBX::Velocity& previousFloorVelocity, float& netDt);
|
||||
const Velocity getHumanoidRelativeVelocityToPart(Primitive* floorPrim);
|
||||
|
||||
public:
|
||||
void updateNetworkFloorPosition(PartInstance* floorPart, CoordinateFrame& previousFloorPosition, RBX::Velocity& lastFloorVelocity, float& netDt);
|
||||
bool shouldNotApplyFloorVelocity(Primitive* floorPrim);
|
||||
bool primitiveIsLastFloor(Primitive* prim);
|
||||
void updateFloorSimPhaseCharVelocity(Primitive* floorPrim);
|
||||
// End Humanoid Platform Networking
|
||||
|
||||
|
||||
/*override*/ void tellCameraNear(float distance) const;
|
||||
/*override*/ void tellCameraSubjectDidChange(shared_ptr<Instance> oldSubject, shared_ptr<Instance> newSubject) const;
|
||||
/*override*/ void tellCursorOver(float cursorOffset) const;
|
||||
/*override*/ void getCameraIgnorePrimitives(std::vector<const Primitive*>& primitives);
|
||||
/*override*/ Velocity calcDesiredWalkVelocity() const; // used for camera control
|
||||
|
||||
static float autoTurnSpeed() {return 8.0f;}
|
||||
|
||||
Humanoid();
|
||||
~Humanoid();
|
||||
|
||||
bool waitingForTorso() { return !torsoArrived; }
|
||||
bool isLegalForClientToChange(const Reflection::PropertyDescriptor& desc) const;
|
||||
int getPlayerId();
|
||||
|
||||
enum Status
|
||||
{
|
||||
POISON_STATUS = 0,
|
||||
CONFUSION_STATUS = 1,
|
||||
};
|
||||
bool hasStatus(Status status);
|
||||
bool addStatus(Status status);
|
||||
bool removeStatus(Status status);
|
||||
bool hasCustomStatus(std::string status);
|
||||
bool addCustomStatus(std::string status);
|
||||
bool removeCustomStatus(std::string status);
|
||||
bool isLocalSimulating() const {return localSimulating;}
|
||||
bool computeNearlyTouched();
|
||||
|
||||
bool getStateTransitionEnabled(HUMAN::StateType state);
|
||||
void setStateTransitionEnabled(HUMAN::StateType state, bool enabled);
|
||||
|
||||
shared_ptr<const Reflection::ValueArray> getStatuses();
|
||||
rbx::signal<void(Status)> statusAddedSignal;
|
||||
rbx::signal<void(Status)> statusRemovedSignal;
|
||||
rbx::signal<void(std::string)> customStatusAddedSignal;
|
||||
rbx::signal<void(std::string)> customStatusRemovedSignal;
|
||||
|
||||
rbx::remote_signal<void(shared_ptr<Instance>)> serverEquipToolSignal;
|
||||
|
||||
// Humanoid Network Update Connection
|
||||
rbx::signals::scoped_connection onPositionUpdatedByNetworkConnection;
|
||||
|
||||
NameOcclusion getNameOcclusion() const { return nameOcclusion; }
|
||||
void setNameOcclusion(NameOcclusion value);
|
||||
|
||||
HumanoidDisplayDistanceType getDisplayDistanceType() const { return displayDistanceType; }
|
||||
void setDisplayDistanceType(HumanoidDisplayDistanceType value);
|
||||
|
||||
static Humanoid* humanoidFromBodyPart(Instance* bodyPart);
|
||||
static const Humanoid* constHumanoidFromBodyPart(const Instance* bodyPart);
|
||||
static const Humanoid* constHumanoidFromDescendant(const Instance* bodyPart);
|
||||
|
||||
static Humanoid* modelIsCharacter(Instance* testModel);
|
||||
static const Humanoid* modelIsConstCharacter(const Instance* testModel);
|
||||
|
||||
static Humanoid* getLocalHumanoidFromContext(Instance* context);
|
||||
static const Humanoid* getConstLocalHumanoidFromContext(const Instance* context);
|
||||
|
||||
static PartInstance* getLocalHeadFromContext(Instance* context);
|
||||
static const PartInstance* getConstLocalHeadFromContext(const Instance* context);
|
||||
|
||||
static ModelInstance* getCharacterFromHumanoid(Humanoid* humanoid);
|
||||
static const ModelInstance* getConstCharacterFromHumanoid(const Humanoid* humanoid);
|
||||
|
||||
static PartInstance* getHeadFromCharacter(ModelInstance* character);
|
||||
static const PartInstance* getConstHeadFromCharacter(const ModelInstance* character);
|
||||
|
||||
static Weld* getGrip(Instance* character);
|
||||
|
||||
static const Vector3 &defaultCharacterCorner() { static Vector3 corner(2.5f,2.5f,2.5f); return corner; }
|
||||
|
||||
// By Definition, these are all called by HumanoidState - these are reflected
|
||||
rbx::signal<void()> diedSignal;
|
||||
rbx::signal<void(float)> swimmingSignal;
|
||||
rbx::signal<void(float)> runningSignal; // state change scripts
|
||||
rbx::signal<void(float)> climbingSignal; // state change scripts
|
||||
rbx::signal<void(bool)> jumpingSignal; // state change scripts
|
||||
rbx::signal<void(bool)> freeFallingSignal;
|
||||
rbx::signal<void(bool)> strafingSignal;
|
||||
rbx::signal<void(bool)> gettingUpSignal;
|
||||
rbx::signal<void(bool)> fallingDownSignal;
|
||||
rbx::signal<void(bool)> ragdollSignal;
|
||||
rbx::signal<void(bool, shared_ptr<Instance>)> seatedSignal;
|
||||
rbx::signal<void(bool)> platformStandingSignal;
|
||||
rbx::signal<void(RBX::HUMAN::StateType, RBX::HUMAN::StateType)> stateChangedSignal;
|
||||
rbx::signal<void(RBX::HUMAN::StateType, bool)> stateEnabledChangedSignal;
|
||||
RBX::HUMAN::StateType getCurrentStateType();
|
||||
RBX::HUMAN::StateType getPreviousStateType() { return previousState; };
|
||||
void setPreviousStateType(RBX::HUMAN::StateType newState);
|
||||
void changeState(RBX::HUMAN::StateType state);
|
||||
static bool isStateInString(const std::string& text, const RBX::HUMAN::StateType &compare, RBX::HUMAN::StateType& value);
|
||||
|
||||
rbx::signal<void(float)> healthChangedSignal;
|
||||
|
||||
// Internal use only - no reflection - happens both client, server
|
||||
rbx::signal<void()> doneSittingSignal;
|
||||
rbx::signal<void()> donePlatformStandingSignal;
|
||||
|
||||
void equipToolInstance(shared_ptr<Instance> instance);
|
||||
void equipTool(RBX::Tool* tool);
|
||||
void unequipTools();
|
||||
|
||||
void setWalkSpeed(float value);
|
||||
float getWalkSpeed() const {return walkSpeed;}
|
||||
void testWalkSpeed(float walkSpeed, float percentWalkSpeed) const
|
||||
{
|
||||
walkSpeedErrors = (walkSpeed > walkSpeedShadow) ? walkSpeedErrors + 1 : 0;
|
||||
if (walkSpeedErrors > 8)
|
||||
{
|
||||
RBX::Security::setHackFlagVs<LINE_RAND4>(RBX::Security::hackFlag11, HATE_SPEEDHACK);
|
||||
}
|
||||
if (fabs(percentWalkSpeed) > 1.01)
|
||||
{
|
||||
RBX::Security::setHackFlagVs<LINE_RAND4>(RBX::Security::hackFlag11, HATE_SPEEDHACK);
|
||||
}
|
||||
}
|
||||
|
||||
void setPercentWalkSpeed(float value);
|
||||
float getPercentWalkSpeed() const { return percentWalkSpeed; }
|
||||
|
||||
void setJumpPower(float value);
|
||||
float getJumpPower() const { return jumpPower; }
|
||||
|
||||
void setMaxSlopeAngle(float value);
|
||||
float getMaxSlopeAngle() const { return maxSlopeAngle; }
|
||||
|
||||
const Vector3 &getLastFloorNormal() const { return lastFloorNormal; }
|
||||
void setLastFloorNormal(const Vector3 &norm) { lastFloorNormal = norm; }
|
||||
|
||||
void setHipHeight(float value);
|
||||
float getHipHeight() const { return hipHeight; }
|
||||
|
||||
// Health / damage interface
|
||||
void setHealth(float value);
|
||||
void setHealthUi(float value);
|
||||
void zeroHealthLocal() {health = 0.0f;} // for a non-simulating client -zero out health without bouncing back to the server
|
||||
float getHealth() const {return health;}
|
||||
|
||||
void setMaxHealth(float value);
|
||||
float getMaxHealth() const {return maxHealth;}
|
||||
|
||||
void setTyping(bool value) { typing = value; }
|
||||
bool getTyping() const { return typing; }
|
||||
|
||||
void takeDamage(float value); // honors explosions, etc.
|
||||
|
||||
void setClickToWalkEnabled(bool value) { clickToWalkEnabled = value; }
|
||||
|
||||
// Controller interface - don't set the walk direction directly
|
||||
void setWalkDirection(const Vector3& value); // compacted - z is in the y place
|
||||
Vector3 getWalkDirection() const {return walkDirection;} // compacted - z is in the y place
|
||||
bool allow3dWalkDirection() const;
|
||||
|
||||
void move(Vector3 walkVector, bool relativeToCamera);
|
||||
|
||||
Vector3 getLuaMoveDirection() const { return luaMoveDirection;}
|
||||
void setLuaMoveDirection(const Vector3& value);
|
||||
Vector3 getRawMovementVector() const { return rawMovementVector; }
|
||||
|
||||
bool getAutoJumpEnabled() const { return autoJumpEnabled; };
|
||||
void setAutoJumpEnabled(bool value);
|
||||
|
||||
void setWalkAngleError(const float &value);
|
||||
float getWalkAngleError() const {return walkAngleError;}
|
||||
|
||||
void setWalkToPoint(const Vector3& value);
|
||||
const Vector3& getWalkToPoint() const {return walkToPoint;}
|
||||
|
||||
void setWalkToPart(PartInstance* value);
|
||||
PartInstance* getWalkToPart() const {return walkToPart.get();}
|
||||
|
||||
void setSeatPart(PartInstance* value);
|
||||
PartInstance* getSeatPart() const {return seatPart.get();}
|
||||
|
||||
void setJump(bool value);
|
||||
bool getJump() const { return jump; }
|
||||
|
||||
void setAutoJump(bool value);
|
||||
bool getAutoJump() const { return autoJump;}
|
||||
|
||||
void setSit(bool value);
|
||||
bool getSit() const { return sit; }
|
||||
|
||||
void setAutoRotate(bool value);
|
||||
bool getAutoRotate() const { return autorotate; }
|
||||
|
||||
void setTouchedHard(bool hit) { touchedHard = hit; }
|
||||
|
||||
void setActivatePhysics(bool flag, const Vector3& impulse)
|
||||
{
|
||||
activatePhysics = flag;
|
||||
if (flag)
|
||||
activatePhysicsImpulse += impulse;
|
||||
else
|
||||
activatePhysicsImpulse = impulse;
|
||||
}
|
||||
bool getActivatePhysics() { return activatePhysics; }
|
||||
const Vector3 getActivatePhysicsImpulse() { return activatePhysicsImpulse; }
|
||||
bool getTouchedHard() { return touchedHard; }
|
||||
|
||||
void setRagdollCriteria(int value);
|
||||
int getRagdollCriteria() const { return ragdollCriteria; }
|
||||
|
||||
void setPlatformStanding(bool value);
|
||||
bool getPlatformStanding() const { return platformStanding; }
|
||||
|
||||
void setStrafe(bool value);
|
||||
bool getStrafe() const { return strafe; }
|
||||
|
||||
bool getDead() const;
|
||||
|
||||
void setHadNeck() {hadNeck = true;}
|
||||
bool breakJointsOnDeath() const {return hadNeck && hadHealth;}
|
||||
|
||||
void setTargetPoint(const Vector3& value);
|
||||
void setTargetPointLocal(const Vector3& value); // does not replicate
|
||||
const Vector3& getTargetPoint() const {return targetPoint;}
|
||||
|
||||
void setNameDisplayDistance(float d);
|
||||
float getNameDisplayDistance() const { return nameDisplayDistance; }
|
||||
|
||||
void setHealthDisplayDistance(float d);
|
||||
float getHealthDisplayDistance() const { return healthDisplayDistance; }
|
||||
|
||||
void setCameraOffset(const Vector3 &value);
|
||||
const Vector3 &getCamearaOffset() const { return cameraOffset; }
|
||||
|
||||
// Humanoid Platform Update Getters and Setters;
|
||||
void setLastFloor(PartInstance* part)
|
||||
{
|
||||
if(lastFloorPart)
|
||||
{
|
||||
lastFloorPart.reset();
|
||||
}
|
||||
lastFloorPart = shared_from(part);
|
||||
}
|
||||
const shared_ptr<PartInstance>& getLastFloor() const { return lastFloorPart; }
|
||||
|
||||
void setRootFloorPart(PartInstance* part)
|
||||
{
|
||||
if (rootFloorMechPart)
|
||||
{
|
||||
rootFloorMechPart.reset();
|
||||
}
|
||||
rootFloorMechPart = shared_from(part);
|
||||
}
|
||||
shared_ptr<PartInstance> getRootFloorPart() const { return rootFloorMechPart; }
|
||||
|
||||
int getCurrentFloorFilterPhase();
|
||||
int getCurrentFloorFilterPhase(Assembly* floorAssembly);
|
||||
|
||||
void setLastFloorPhase(int phase) { lastFilterPhase = phase; }
|
||||
int getLastFloorPhase() const { return lastFilterPhase; }
|
||||
|
||||
// Walk Utilities
|
||||
void moveTo(const Vector3& worldPosition, PartInstance* part);
|
||||
void moveTo2(Vector3 worldPosition, shared_ptr<Instance> part);
|
||||
rbx::signal<void(bool)> moveToFinishedSignal;
|
||||
|
||||
bool getUseR15() const { return (rigType != HUMANOID_RIG_TYPE_R6); }
|
||||
Humanoid::HumanoidRigType getRigType() const { return rigType; }
|
||||
void setRigType(Humanoid::HumanoidRigType type);
|
||||
|
||||
// Build Joints
|
||||
void buildJoints(RBX::DataModel* dm = NULL);
|
||||
void buildJointsFromAttachments(PartInstance* part, std::vector<PartInstance*>& characterParts);
|
||||
|
||||
JointInstance* getRightShoulder();
|
||||
Joint* getNeck();
|
||||
|
||||
// Primitive
|
||||
void getPrimitives(std::vector<Primitive*>& primitives) const;
|
||||
|
||||
void getParts(std::vector<PartInstance*>& primitives) const;
|
||||
|
||||
PartInstance* getTorsoDangerous() const; // reflection only
|
||||
PartInstance* getLeftLegDangerous() const; // reflection only
|
||||
PartInstance* getRightLegDangerous() const; // reflection only
|
||||
|
||||
// TODO: No internal buffering - after refactor, rename without the word slow
|
||||
PartInstance* getTorsoSlow(); // no internal buffering
|
||||
PartInstance* getVisibleTorsoSlow();
|
||||
PartInstance* getHeadSlow();
|
||||
PartInstance* getLeftLegSlow();
|
||||
PartInstance* getRightLegSlow();
|
||||
PartInstance* getLeftArmSlow();
|
||||
PartInstance* getRightArmSlow();
|
||||
StatusInstance* getStatusSlow();
|
||||
|
||||
const PartInstance* getTorsoSlow() const; // no internal buffering
|
||||
const PartInstance* getVisibleTorsoSlow() const;
|
||||
const PartInstance* getHeadSlow() const;
|
||||
const PartInstance* getLeftLegSlow() const;
|
||||
const PartInstance* getRightLegSlow() const;
|
||||
const PartInstance* getLeftArmSlow() const;
|
||||
const PartInstance* getRightArmSlow() const;
|
||||
const StatusInstance* getStatusSlow() const;
|
||||
|
||||
Primitive* getTorsoPrimitiveSlow();
|
||||
Primitive* getHeadPrimitiveSlow();
|
||||
|
||||
// Internal buffering
|
||||
PartInstance* getTorsoFast();
|
||||
PartInstance* getVisibleTorsoFast();
|
||||
PartInstance* getHeadFast();
|
||||
PartInstance* getLeftLegFast();
|
||||
PartInstance* getRightLegFast();
|
||||
PartInstance* getLeftArmFast();
|
||||
PartInstance* getRightArmFast();
|
||||
StatusInstance* getStatusFast();
|
||||
|
||||
Primitive* getTorsoPrimitiveFast();
|
||||
|
||||
// Body
|
||||
inline Body* getTorsoBodyFast()
|
||||
{
|
||||
Primitive* prim = getTorsoPrimitiveFast();
|
||||
return prim ? prim->getBody() : NULL;
|
||||
}
|
||||
Body* getRootBodyFast();
|
||||
|
||||
// Attachment Points
|
||||
CoordinateFrame getTopOfHead() const;
|
||||
CoordinateFrame getRightArmGrip() const;
|
||||
|
||||
float getTorsoHeading() const; // 0 == North == -Z. Pi/2 = WEST == -x
|
||||
float getTorsoElevation() const;
|
||||
|
||||
void setTorso(PartInstance* value);
|
||||
void setLeftLeg(PartInstance* value);
|
||||
void setRightLeg(PartInstance* value);
|
||||
|
||||
void setHeadMesh(DataModelMesh* value);
|
||||
void setHeadDecal(Decal* value);
|
||||
|
||||
World* getWorld() {return world;};
|
||||
const World* getConstWorld() const {return world;};
|
||||
|
||||
static void renderWaypoint(Adorn* adorn, const Vector3& waypoint);
|
||||
|
||||
// proxy interface to Animator object.
|
||||
shared_ptr<Instance> loadAnimation(shared_ptr<Instance> animation);
|
||||
bool CheckTorso();
|
||||
void setupAnimator();
|
||||
shared_ptr<const Reflection::ValueArray> getPlayingAnimationTracks();
|
||||
|
||||
rbx::signal<void(shared_ptr<Instance>)> animationPlayedSignal;
|
||||
|
||||
bool getOwnedByLocalPlayer() const { return ownedByLocalPlayer; }
|
||||
|
||||
bool getWalkingFromStudioTouchEmulation() const { return isWalkingFromStudioTouchEmulation; }
|
||||
void setWalkingFromStudioTouchEmulation(bool value) { isWalkingFromStudioTouchEmulation = value; }
|
||||
};
|
||||
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,346 @@
|
||||
/* Copyright 2003-2007 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "Util/HitTestFilter.h"
|
||||
#include "GfxBase/IAdornable.h"
|
||||
#include "Util/Name.h"
|
||||
#include "rbx/Debug.h"
|
||||
#include "Util/Velocity.h"
|
||||
#include "rbx/boost.hpp"
|
||||
#include "Reflection/Event.h"
|
||||
#include "G3D/Array.h"
|
||||
#include "util/PartMaterial.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define CHARACTER_FORCE_DEBUG 0
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class Humanoid;
|
||||
class PartInstance;
|
||||
class Controller;
|
||||
class Assembly;
|
||||
class GeometryService;
|
||||
|
||||
namespace HUMAN
|
||||
{
|
||||
typedef enum { FALLING_DWN = 0,
|
||||
RAGDOLL, // 1
|
||||
GETTING_UP,
|
||||
JUMPING,
|
||||
SWIMMING,
|
||||
FREE_FALL, // 4: balancing, no thrust
|
||||
FLYING,
|
||||
LANDED, // 6: can't jump
|
||||
RUNNING, // 7
|
||||
RUNNING_SLAVE, // 8: slave side - lock to running mode to do accurate physics when touched slave side
|
||||
RUNNING_NO_PHYS, // 9
|
||||
STRAFING_NO_PHYS,
|
||||
CLIMBING,
|
||||
SEATED,
|
||||
PLATFORM_STANDING,
|
||||
DEAD,
|
||||
PHYSICS,
|
||||
NUM_STATE_TYPES,
|
||||
xx } StateType; // XX == NO change
|
||||
|
||||
typedef enum { NO_HEALTH = 0, // Humanoid Commands
|
||||
NO_NECK,
|
||||
JUMP_CMD,
|
||||
STRAFE_CMD,
|
||||
NO_STRAFE_CMD,
|
||||
SIT_CMD,
|
||||
NO_SIT_CMD,
|
||||
PLATFORM_STAND_CMD,
|
||||
NO_PLATFORM_STAND_CMD,
|
||||
TIPPED, // Tilting
|
||||
UPRIGHT,
|
||||
FACE_LDR, // Ladder
|
||||
AWAY_LDR,
|
||||
OFF_FLOOR, // Floor
|
||||
OFF_FLOOR_GRACE, // Floor w/ Grace Period
|
||||
ON_FLOOR,
|
||||
TOUCHED, // Other Objects
|
||||
NEARLY_TOUCHED, // Other Objects
|
||||
TOUCHED_HARD,
|
||||
ACTIVATE_PHYSICS,
|
||||
FINISHED,
|
||||
TIMER_UP, // FINISHED_FALLING, READY_TO_JUMP,
|
||||
NO_TOUCH_ONE_SECOND,
|
||||
HAS_GYRO,
|
||||
HAS_BUOYANCY,
|
||||
NO_BUOYANCY,
|
||||
NUM_EVENT_TYPES } EventType;
|
||||
|
||||
#if CHARACTER_FORCE_DEBUG
|
||||
class DebugRay
|
||||
{
|
||||
public:
|
||||
RbxRay ray;
|
||||
Color3 color;
|
||||
|
||||
DebugRay(const RbxRay& _ray, const Color3& _color)
|
||||
{
|
||||
ray = _ray;
|
||||
color = _color;
|
||||
}
|
||||
|
||||
void Draw(Adorn* adorn);
|
||||
};
|
||||
#endif
|
||||
|
||||
class HumanoidState : public INamed,
|
||||
public HitTestFilter
|
||||
|
||||
{
|
||||
public:
|
||||
static const unsigned int kCorrectCheckValue = 2;
|
||||
|
||||
private:
|
||||
const Vector3& unitializedFloorTouch() const {
|
||||
static Vector3 v(1e15f, 1e15f, 1e15f);
|
||||
return v;
|
||||
}
|
||||
|
||||
Humanoid* humanoid;
|
||||
float timer;
|
||||
float noTouchTimer;
|
||||
bool nearlyTouched;
|
||||
bool shouldRender;
|
||||
bool finished;
|
||||
bool outOfWater;
|
||||
bool headClear;
|
||||
StateType priorState;
|
||||
StateType luaState;
|
||||
|
||||
G3D::Array<PartInstance*> foundParts; // temp buffer
|
||||
bool facingLadder;
|
||||
shared_ptr<PartInstance> floorPart;
|
||||
PartMaterial floorMaterial;
|
||||
Vector3 floorTouchInWorld;
|
||||
Vector3 floorTouchNormal;
|
||||
Vector3 floorHumanoidLocationInWorld;
|
||||
float noFloorTimer;
|
||||
|
||||
// Cut down firing of the running event to when there are major difference in velocity
|
||||
float lastMovementVelocity;
|
||||
|
||||
// signals that the state needs these updated
|
||||
bool usesEvent(EventType e) const;
|
||||
bool usesLadder() const {return (usesEvent(FACE_LDR) || usesEvent(AWAY_LDR));}
|
||||
bool usesFloor() const {return (usesEvent(OFF_FLOOR) || usesEvent(ON_FLOOR) || usesEvent(OFF_FLOOR_GRACE));}
|
||||
|
||||
float computeTilt() const;
|
||||
bool computeTipped() const;
|
||||
bool computeUpright() const;
|
||||
bool computeHasGyro() const;
|
||||
bool computeJumped() const;
|
||||
float computeFloorTilt() const;
|
||||
|
||||
void setLegsCanCollide(bool canCollide);
|
||||
void setArmsCanCollide(bool canCollide);
|
||||
void setHeadCanCollide(bool canCollide);
|
||||
void setTorsoCanCollide(bool canCollide);
|
||||
|
||||
int ladderCheck;
|
||||
virtual int ladderCheckRate() { return 2; }
|
||||
bool findPrimitiveInLadderZone(Adorn* adorn);
|
||||
bool findLadder(Adorn* adorn);
|
||||
void doLadderRaycast(GeometryService *geom, const RbxRay& caster,Humanoid* humanoid, Primitive** hitPrimOut,
|
||||
Vector3* hitLocationOut);
|
||||
void doAutoJump();
|
||||
void findFloor(shared_ptr<PartInstance>& oldFloor);
|
||||
shared_ptr<PartInstance> tryFloor(const RbxRay& ray, Vector3& hitLocation, Vector3& hitNormal, float maxDistance, Assembly* humanoidAssembly, PartMaterial& recentFloorMaterial);
|
||||
void AverageFloorRayCast(shared_ptr<PartInstance> &floorPart, Vector3& floorPartHitLocation, Vector3& floorPartHitNormal,
|
||||
PartMaterial& floorPartHitMaterial, Vector3& hitLocationAccumulator, int& hitLocationCount, const bool UpdateFloorPart,
|
||||
const Vector3& offset, const float maxDistance, Assembly* humanoidAssembly, const CoordinateFrame& torsoC);
|
||||
void preStepFloor();
|
||||
void preStepCollide();
|
||||
void preStepSimulatorSide(float dt);
|
||||
void preStepSlaveSide() {preStepCollide();}
|
||||
|
||||
static void doSimulatorStateTable(shared_ptr<HumanoidState>& state, float dt);
|
||||
static void doSlaveStateTable(shared_ptr<HumanoidState>& state, StateType newType);
|
||||
static HumanoidState* create(StateType newType, StateType oldType, Humanoid* humanoid);
|
||||
static HumanoidState* createNew(StateType newType, StateType oldType, Humanoid* humanoid);
|
||||
static void changeState(shared_ptr<HumanoidState>& state, StateType newType);
|
||||
|
||||
void fireEvent(StateType stateType, bool entering);
|
||||
|
||||
// Override hitTestFiler
|
||||
/*override*/ Result filterResult(const Primitive* testMe) const;
|
||||
|
||||
protected:
|
||||
|
||||
// For debugging
|
||||
Vector3 maxTorque;
|
||||
Vector3 maxForce;
|
||||
float maxContactVel;
|
||||
Vector3 lastTorque;
|
||||
Vector3 lastForce;
|
||||
float lastContactVel;
|
||||
|
||||
static float minMoveVelocity() {return 0.5f;}
|
||||
static float maxClimbDistance() {return 2.45f;} // studs
|
||||
static const Vector3 maxMoveForce() {static Vector3 m(1000.0f, 10000.0f, 1000.0f); return m;} //const Vector3 maxMoveAccelerationGrid(5e4f*0.02f, 5e5f*0.02f, 1e4f*0.02f);
|
||||
static const Vector3 minMoveForce() {static Vector3 m(-1000.0f, 0.0f, -1000.0f); return m;}
|
||||
static const Vector3 maxSwimmingMoveForce() {static Vector3 m(10000.0f, 1000.0f, 10000.0f); return m;}
|
||||
static const Vector3 minSwimmingMoveForce() {static Vector3 m(-10000.0f, -10000.0f, -10000.0f); return m;}
|
||||
static float fallDelay() { return 0.125f; }
|
||||
static float maxLinearMoveForce() { return 143.0; }
|
||||
|
||||
// Need public for some Physics calculations outside of Humanoid State
|
||||
public:
|
||||
float steepSlopeAngle() const;
|
||||
static float runningKMoveP();
|
||||
static float runningKMovePForPGS();
|
||||
static float maxLinearGroundMoveForce() { return 500.0; }
|
||||
|
||||
protected:
|
||||
Assembly* filteringAssembly;
|
||||
|
||||
bool computeEvent(EventType eventType);
|
||||
|
||||
bool computeTouched();
|
||||
bool computeNearlyTouched();
|
||||
bool computeTouchedByMySimulation();
|
||||
bool computeTouchedHard();
|
||||
bool computeActivatePhysics();
|
||||
|
||||
void setOutOfWater() { outOfWater = true; }
|
||||
bool getOutOfWater() const { return outOfWater; }
|
||||
|
||||
void setTimer(float time) {timer = time;}
|
||||
float getTimer() const {return timer;}
|
||||
|
||||
bool getFinished() const {return finished;}
|
||||
void setFinished(bool value) {finished = value;}
|
||||
|
||||
bool getFacingLadder() const {return facingLadder;}
|
||||
bool getHeadClear() const { return headClear; }
|
||||
|
||||
PartMaterial getFloorMaterial() const { return floorMaterial; }
|
||||
float getFloorFrictionProperty(Primitive* floorPrim) const;
|
||||
|
||||
Primitive* getFloorPrimitive();
|
||||
const Primitive* getFloorPrimitiveConst() const;
|
||||
const Vector3& getFloorTouchInWorld() const {
|
||||
RBXASSERT(floorTouchInWorld != unitializedFloorTouch());
|
||||
return floorTouchInWorld;
|
||||
}
|
||||
const Vector3& getFloorTouchNormal() const {
|
||||
RBXASSERT(floorTouchInWorld != unitializedFloorTouch());
|
||||
return floorTouchNormal;
|
||||
}
|
||||
const Vector3& getFloorHumanoidLocationInWorld() const {
|
||||
RBXASSERT(floorHumanoidLocationInWorld != unitializedFloorTouch());
|
||||
return floorHumanoidLocationInWorld;
|
||||
}
|
||||
|
||||
|
||||
const Velocity getFloorPointVelocity();
|
||||
Vector3 getRelativeMovementVelocity();
|
||||
float getDesiredAltitude() const;
|
||||
|
||||
#if CHARACTER_FORCE_DEBUG
|
||||
std::vector<DebugRay> debugRayList;
|
||||
#endif
|
||||
|
||||
void fireMovementSignal(rbx::signal<void(float)>& movementSignal, float movementVelocity);
|
||||
|
||||
// Tick Count - 30 FPS, state table occurs here
|
||||
virtual void onComputeForceImpl() = 0;
|
||||
virtual void onStepImpl() {}
|
||||
virtual void onSimulatorStepImpl(float stepDt) {}
|
||||
|
||||
protected:
|
||||
void setCanThrottleState(bool canThrottle); // only the Seated state can throttle - its joined to parts so it must
|
||||
|
||||
// Attributes moved in assemblies
|
||||
Assembly* getAssembly();
|
||||
const Assembly* getAssemblyConst() const;
|
||||
void stateToAssembly();
|
||||
StateType stateFromAssembly();
|
||||
|
||||
public:
|
||||
virtual bool armsShouldCollide() const {return true;}
|
||||
virtual bool legsShouldCollide() const {return true;}
|
||||
virtual bool headShouldCollide() const {return true;}
|
||||
virtual bool torsoShouldCollide() const {return true;}
|
||||
|
||||
virtual bool enableAutoJump() const { return true; }
|
||||
|
||||
virtual void onCFrameChangedFromReflection() { preStepFloor();} // recalculate floor part
|
||||
|
||||
|
||||
HumanoidState(Humanoid* humanoid, StateType priorState);
|
||||
|
||||
virtual ~HumanoidState();
|
||||
|
||||
const Humanoid* getHumanoidConst() const;
|
||||
|
||||
Humanoid* getHumanoid() {
|
||||
return const_cast<Humanoid*>(getHumanoidConst());
|
||||
}
|
||||
|
||||
static HumanoidState* defaultState(Humanoid* humanoid); // new Running(this));
|
||||
|
||||
static void simulate(shared_ptr<HumanoidState>& state, float dt);
|
||||
|
||||
static void updateHumanoidFloorStatus(shared_ptr<HumanoidState>& state);
|
||||
|
||||
static bool hasFloorChanged(shared_ptr<HumanoidState>& state, Primitive* lastFloorPrim);
|
||||
|
||||
static void noSimulate(shared_ptr<HumanoidState>& state); // for non-simulating humanoids, match states
|
||||
|
||||
virtual void fireEvents();
|
||||
|
||||
virtual float getYAxisRotationalVelocity() const {return 0.0f;}
|
||||
|
||||
float getCharacterHipHeight() const;
|
||||
|
||||
void onComputeForce();
|
||||
|
||||
bool torsoHasBuoyancy, leftLegHasBuoyancy, rightLegHasBuoyancy;
|
||||
std::vector<rbx::signals::connection> buoyancyConnections;
|
||||
void setTorsoHasBuoyancy( bool value ) { torsoHasBuoyancy = value; }
|
||||
void setLeftLegHasBuoyancy( bool value ) { leftLegHasBuoyancy = value; }
|
||||
void setRightLegHasBuoyancy( bool value ) { rightLegHasBuoyancy = value; }
|
||||
bool computeHasBuoyancy();
|
||||
|
||||
virtual StateType getStateType() const = 0;
|
||||
|
||||
void setLuaState(StateType state);
|
||||
StateType getLuaState() { return luaState; }
|
||||
|
||||
static const char *getStateNameByType(StateType state);
|
||||
|
||||
bool computeHitByHighImpactObject();
|
||||
|
||||
// only in debug
|
||||
void render3dAdorn(Adorn* adorn);
|
||||
|
||||
void setNearlyTouched();
|
||||
|
||||
// for security purposes, get the address of this code.
|
||||
// A member function pointer is a compiler defined data structure.
|
||||
static inline const void* getComputeEventBaseAddress()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
bool (RBX::HUMAN::HumanoidState::* hsce)(EventType) = &computeEvent;
|
||||
if(sizeof(hsce) == 8 || sizeof(hsce) == 4)
|
||||
{
|
||||
return (const void*&)(hsce); // odd, but required syntax for this horrible conversion.
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int checkComputeEvent(); // this was added due to exploits.
|
||||
};
|
||||
|
||||
} // namespace HUMAN
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,43 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Humanoid/Flying.h"
|
||||
|
||||
namespace RBX {
|
||||
namespace HUMAN {
|
||||
|
||||
extern const char* const sJumping;
|
||||
|
||||
class Jumping : public Named<Flying, sJumping>
|
||||
{
|
||||
private:
|
||||
typedef Named<Flying, sJumping> Super;
|
||||
/*override*/ StateType getStateType() const {return JUMPING;}
|
||||
|
||||
// Humanoid::State
|
||||
/*override*/ void onComputeForceImpl();
|
||||
|
||||
/*override*/ bool armsShouldCollide() const {return false;}
|
||||
/*override*/ bool legsShouldCollide() const {return false;}
|
||||
/*override*/ bool torsoShouldCollide() const {return false;}
|
||||
|
||||
// Override hitTestFiler
|
||||
/*override*/ Result filterResult(const Primitive* testMe) const;
|
||||
|
||||
bool findCeiling();
|
||||
shared_ptr<PartInstance> tryCeiling(const RbxRay& ray, float maxDistance, Assembly* humanoidAssembly);
|
||||
|
||||
Vector3 jumpDir;
|
||||
|
||||
public:
|
||||
Jumping(Humanoid* humanoid, StateType priorState);
|
||||
|
||||
static float kJumpP() {return 500.0f;}
|
||||
static float kJumpVelocityGrid() {return 50.0f;}
|
||||
|
||||
};
|
||||
|
||||
} // namespace HUMAN
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Humanoid/HumanoidState.h"
|
||||
#include "V8World/Mechanism.h"
|
||||
|
||||
namespace RBX {
|
||||
class Assembly;
|
||||
class PhysicsService;
|
||||
|
||||
namespace HUMAN {
|
||||
|
||||
extern const char* const sMovingNoPhysicsBase;
|
||||
|
||||
class MovingNoPhysicsBase
|
||||
: public Named<HumanoidState, sMovingNoPhysicsBase>
|
||||
{
|
||||
private:
|
||||
typedef Named<HumanoidState, sMovingNoPhysicsBase> Super;
|
||||
/*override*/ StateType getStateType() const {return RUNNING_NO_PHYS;}
|
||||
/*override*/ void fireEvents();
|
||||
|
||||
shared_ptr<PartInstance> torsoPart;
|
||||
weak_ptr<PhysicsService> physicsService;
|
||||
|
||||
rbx::signals::scoped_connection torsoAncestryChanged;
|
||||
void onEvent_TorsoAncestryChanged();
|
||||
void disconnectTorso();
|
||||
|
||||
const Assembly* getAssemblyConst() const;
|
||||
|
||||
void applyImpulseToFloor(float dt);
|
||||
|
||||
protected:
|
||||
|
||||
// Humanoid::State
|
||||
/*override*/ void onSimulatorStepImpl(float stepDt);
|
||||
/*override*/ void onComputeForceImpl();
|
||||
|
||||
/*override*/ bool armsShouldCollide() const {return false;}
|
||||
/*override*/ bool legsShouldCollide() const {return false;}
|
||||
/*override*/ bool headTorsoShouldCollide() const {return false;}
|
||||
|
||||
public:
|
||||
MovingNoPhysicsBase(Humanoid* humanoid, StateType priorState);
|
||||
~MovingNoPhysicsBase();
|
||||
};
|
||||
|
||||
} // namespace HUMAN
|
||||
} // namespace
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Humanoid/Balancing.h"
|
||||
#include "Util/Name.h"
|
||||
|
||||
namespace RBX {
|
||||
namespace HUMAN {
|
||||
|
||||
// Flying occurs when there's no ground below you. You have the ability
|
||||
// to turn around the y-axis, but not much else.
|
||||
extern const char* const sRagdoll;
|
||||
|
||||
class Ragdoll : public Named<HumanoidState, sRagdoll>
|
||||
{
|
||||
private:
|
||||
typedef Named<HumanoidState, sRagdoll> Super;
|
||||
/*override*/ StateType getStateType() const {return RAGDOLL;}
|
||||
/*override*/ void onStepImpl();
|
||||
/*override*/ void onComputeForceImpl() {}
|
||||
/*override*/ bool enableAutoJump() const { return false; }
|
||||
public:
|
||||
Ragdoll(Humanoid* humanoid, StateType priorState);
|
||||
~Ragdoll();
|
||||
};
|
||||
|
||||
} // namespace HUMAN
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Humanoid/RunningBase.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
class Body;
|
||||
|
||||
namespace HUMAN {
|
||||
|
||||
extern const char* const sRunning;
|
||||
extern const char* const sRunningSlave;
|
||||
extern const char* const sLanded;
|
||||
extern const char* const sClimbing;
|
||||
|
||||
|
||||
class Running : public Named<RunningBase, sRunning>
|
||||
{
|
||||
private:
|
||||
typedef Named<RunningBase, sRunning> Super;
|
||||
/*override*/ StateType getStateType() const {return RUNNING;}
|
||||
/*override*/ void fireEvents();
|
||||
|
||||
protected:
|
||||
/*override*/ void onComputeForceImpl();
|
||||
|
||||
public:
|
||||
Running(Humanoid* humanoid, StateType priorState);
|
||||
};
|
||||
|
||||
// Slave side only - stays running until some other change to respond to touch events correctly
|
||||
class RunningSlave : public Named<Running, sRunningSlave>
|
||||
{
|
||||
public:
|
||||
RunningSlave(Humanoid* humanoid, StateType priorState);
|
||||
};
|
||||
|
||||
class Landed : public Named<RunningBase, sLanded>
|
||||
{
|
||||
private:
|
||||
/*override*/ StateType getStateType() const {return LANDED;}
|
||||
|
||||
public:
|
||||
Landed(Humanoid* humanoid, StateType priorState);
|
||||
};
|
||||
|
||||
|
||||
class Climbing : public Named<RunningBase, sClimbing>
|
||||
{
|
||||
private:
|
||||
typedef Named<RunningBase, sClimbing> Super;
|
||||
/*override*/ StateType getStateType() const {return CLIMBING;}
|
||||
/*override*/ void fireEvents();
|
||||
/*override*/ int ladderCheckRate() { return 0; }
|
||||
/*override*/ bool enableAutoJump() const { return false; }
|
||||
public:
|
||||
Climbing(Humanoid* humanoid, StateType priorState) : Named<RunningBase, sClimbing>(humanoid, priorState)
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
} // namespace HUMAN
|
||||
} // namespace RBX
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Humanoid/Balancing.h"
|
||||
|
||||
|
||||
namespace RBX {
|
||||
class Body;
|
||||
|
||||
namespace HUMAN {
|
||||
|
||||
class RunningBase : public Balancing
|
||||
{
|
||||
private:
|
||||
typedef Balancing Super;
|
||||
protected:
|
||||
Velocity floorVelocity;
|
||||
|
||||
// The following velocities are w.r.t the ground that the figure is walking on. The ground may be moving
|
||||
Velocity desiredVelocity; // desired velocity in world coordinates relative to the floor's velocity
|
||||
float desiredAltitude; // ignored if 0.0
|
||||
|
||||
void rotateWithGround(Body* body);
|
||||
void hoverOnFloor(Body* body);
|
||||
void move(Body* body);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Humanoid::State
|
||||
/*override*/ void onComputeForceImpl();
|
||||
/*override*/ void onSimulatorStepImpl(float stepDt);
|
||||
|
||||
/*override*/ float getYAxisRotationalVelocity() const {return desiredVelocity.rotational.y;}
|
||||
|
||||
/*override*/ bool armsShouldCollide() const {return false;}
|
||||
/*override*/ bool legsShouldCollide() const {return false;}
|
||||
|
||||
public:
|
||||
RunningBase(Humanoid* humanoid, StateType priorState);
|
||||
RunningBase(Humanoid* humanoid, StateType priorState, const float kP, const float kD);
|
||||
|
||||
/*override*/ void onCFrameChangedFromReflection();
|
||||
|
||||
static const float kTurnP() {return 7500.0f;}
|
||||
static const float kTurnPForRotatePGS() {return 450.0f;}
|
||||
static const float kTurnPForFreeFallPGS() {return 375.0f;}
|
||||
};
|
||||
|
||||
} // namespace HUMAN
|
||||
} // namespace RBX
|
||||
@@ -0,0 +1,24 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Humanoid/MovingNoPhysicsBase.h"
|
||||
|
||||
namespace RBX {
|
||||
class Clump;
|
||||
|
||||
namespace HUMAN {
|
||||
|
||||
extern const char* const sRunningNoPhysics;
|
||||
|
||||
class RunningNoPhysics
|
||||
: public Named<MovingNoPhysicsBase, sRunningNoPhysics>
|
||||
{
|
||||
private:
|
||||
/*override*/ StateType getStateType() const {return RUNNING_NO_PHYS;}
|
||||
public:
|
||||
RunningNoPhysics(Humanoid* humanoid, StateType priorState);
|
||||
};
|
||||
|
||||
} // namespace HUMAN
|
||||
} // namespace
|
||||
@@ -0,0 +1,48 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Humanoid/HumanoidState.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
namespace HUMAN {
|
||||
|
||||
extern const char *const sSeated;
|
||||
|
||||
class Seated : public Named<HumanoidState, sSeated>
|
||||
{
|
||||
private:
|
||||
/*override*/ StateType getStateType() const {return SEATED;}
|
||||
|
||||
/*override*/ bool armsShouldCollide() const {return false;}
|
||||
/*override*/ bool legsShouldCollide() const {return false;}
|
||||
/*override*/ void onComputeForceImpl() {}
|
||||
/*override*/ bool enableAutoJump() const { return false; }
|
||||
|
||||
public:
|
||||
Seated(Humanoid* humanoid, StateType priorState);
|
||||
~Seated();
|
||||
};
|
||||
|
||||
|
||||
extern const char* const sPlatformStanding;
|
||||
|
||||
class PlatformStanding : public Named<HumanoidState, sPlatformStanding>
|
||||
{
|
||||
private:
|
||||
/*override*/ StateType getStateType() const {return PLATFORM_STANDING;}
|
||||
|
||||
/*override*/ bool armsShouldCollide() const {return false;}
|
||||
/*override*/ bool legsShouldCollide() const {return false;}
|
||||
/*override*/ void onComputeForceImpl() {}
|
||||
/*override*/ bool enableAutoJump() const { return false; }
|
||||
|
||||
public:
|
||||
PlatformStanding(Humanoid* humanoid, StateType priorState);
|
||||
~PlatformStanding();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "V8DataModel/ModelInstance.h"
|
||||
|
||||
namespace RBX {
|
||||
|
||||
extern const char* const sStatusInstance;
|
||||
class StatusInstance
|
||||
: public DescribedCreatable<StatusInstance, ModelInstance, sStatusInstance, Reflection::ClassDescriptor::INTERNAL>
|
||||
{
|
||||
private:
|
||||
typedef DescribedCreatable<StatusInstance, ModelInstance, sStatusInstance, Reflection::ClassDescriptor::INTERNAL> Super;
|
||||
|
||||
public:
|
||||
StatusInstance();
|
||||
|
||||
protected:
|
||||
/*override*/ bool askSetParent(const Instance* instance) const;
|
||||
/*override*/ bool askForbidParent(const Instance* instance) const { return !askSetParent(instance); }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -0,0 +1,24 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Humanoid/MovingNoPhysicsBase.h"
|
||||
|
||||
namespace RBX {
|
||||
class Clump;
|
||||
|
||||
namespace HUMAN {
|
||||
|
||||
extern const char* const sStrafingNoPhysics;
|
||||
|
||||
class StrafingNoPhysics
|
||||
: public Named<MovingNoPhysicsBase, sStrafingNoPhysics>
|
||||
{
|
||||
private:
|
||||
/*override*/ StateType getStateType() const {return STRAFING_NO_PHYS;}
|
||||
public:
|
||||
StrafingNoPhysics(Humanoid* humanoid, StateType priorState);
|
||||
};
|
||||
|
||||
} // namespace HUMAN
|
||||
} // namespace
|
||||
@@ -0,0 +1,43 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Humanoid/Balancing.h"
|
||||
#include "Util/Name.h"
|
||||
|
||||
namespace RBX {
|
||||
namespace HUMAN {
|
||||
|
||||
extern const char* const sSwimming;
|
||||
|
||||
class Swimming : public Named<HumanoidState, sSwimming>
|
||||
{
|
||||
private:
|
||||
typedef Named<HumanoidState, sSwimming> Super;
|
||||
Vector3 initialLinearVelocity;
|
||||
static float velocityDecay();
|
||||
|
||||
/*override*/ StateType getStateType() const {return SWIMMING;}
|
||||
/*override*/ void fireEvents();
|
||||
/*override*/ bool enableAutoJump() const { return false; }
|
||||
|
||||
Velocity desiredVelocity;
|
||||
|
||||
protected:
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Humanoid::State
|
||||
/*override*/ void onComputeForceImpl();
|
||||
/*override*/ void onSimulatorStepImpl(float stepDt);
|
||||
|
||||
public:
|
||||
Swimming(Humanoid* humanoid, StateType priorState);
|
||||
|
||||
|
||||
|
||||
static const float kTurnSpeed() {return 6.0f;} // note Humanoid autoTurnSpeed is 8.0f;
|
||||
static const float kTurnAccelMax() {return 20000.0f * kTurnSpeed();}
|
||||
};
|
||||
|
||||
} // namespace HUMAN
|
||||
} // namespace
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace RBX
|
||||
:Descriptor(name, Descriptor::Attributes())
|
||||
,tag(Name::lookup(name))
|
||||
,isNumber(boost::is_arithmetic<T>::value)
|
||||
,isFloat(boost::is_floating_point<T>::value)
|
||||
,isFloat(boost::is_float<T>::value)
|
||||
,isEnum(false)
|
||||
{
|
||||
*isOutdated = false;
|
||||
@@ -71,7 +71,7 @@ namespace RBX
|
||||
:Descriptor(name, Descriptor::Attributes())
|
||||
,tag(Name::declare(tag))
|
||||
,isNumber(boost::is_arithmetic<T>::value)
|
||||
,isFloat(boost::is_floating_point<T>::value)
|
||||
,isFloat(boost::is_float<T>::value)
|
||||
,isEnum(false)
|
||||
{
|
||||
RBXASSERT(!this->tag.empty());
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace RBX
|
||||
/*implement*/ void setValue(DescribedBase* object, const V& value) const
|
||||
{
|
||||
Class* c = boost::polymorphic_downcast<Class*>(object);
|
||||
set(c, value);
|
||||
(c->*set)(value);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -125,7 +125,6 @@ public:
|
||||
rbx::signal<void(const std::string &)> screenshotReadySignal;
|
||||
rbx::signal<void(bool)> screenshotUploadSignal;
|
||||
|
||||
|
||||
rbx::signal<void(bool)> graphicsQualityShortcutSignal;
|
||||
|
||||
rbx::signal<void()> allowedGearTypeChanged;
|
||||
@@ -227,8 +226,6 @@ private:
|
||||
|
||||
bool networkStatsWindowsOn;
|
||||
|
||||
bool isRobloxApp;
|
||||
|
||||
bool renderGuisActive;
|
||||
|
||||
RBX::Game* game;
|
||||
@@ -251,8 +248,6 @@ private:
|
||||
public:
|
||||
static bool BlockingDataModelShutdown;
|
||||
|
||||
static bool isXboxApp;
|
||||
|
||||
static unsigned int perfStats; // another bitmask used to record detected hacks
|
||||
|
||||
std::string jobId;
|
||||
@@ -384,9 +379,6 @@ public:
|
||||
bool isStudio() const { return runningInStudio; }
|
||||
void setIsStudio(bool runningInStudio);
|
||||
|
||||
bool getIsXboxApp() const { return isXboxApp; }
|
||||
void setIsXboxApp(bool value);
|
||||
|
||||
bool isRunMode() const { return isStudioRunMode; }
|
||||
void setIsRunMode(bool value);
|
||||
|
||||
@@ -499,8 +491,6 @@ public:
|
||||
void save(ContentId contentId);
|
||||
static bool canSave(const RBX::Instance* instance);
|
||||
|
||||
|
||||
|
||||
bool getRemoteBuildMode();
|
||||
void setRemoteBuildMode(bool remoteBuildMode);
|
||||
|
||||
|
||||
@@ -5,33 +5,37 @@
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
extern const char *const sGameBasicSettings;
|
||||
extern const char* const sGameBasicSettings;
|
||||
class GameBasicSettings
|
||||
: public GlobalBasicSettingsItem<GameBasicSettings, sGameBasicSettings>
|
||||
{
|
||||
typedef GlobalBasicSettingsItem<GameBasicSettings, sGameBasicSettings> Super;
|
||||
public:
|
||||
enum ControlMode {CONTROL_CLASSIC = 0, CONTROL_MOUSELOCK = 1, CONTROL_HYBRID = 2, CONTROL_CAMLOCK = 3, CONTROL_MOUSEPAN = 4};
|
||||
enum RenderQualitySetting {QUALITY_AUTO = 0, QUALITY_1 = 1, QUALITY_2 = 2, QUALITY_3 = 3, QUALITY_4 = 4, QUALITY_5 = 5, QUALITY_6 = 6, QUALITY_7 = 7, QUALITY_8 = 8, QUALITY_9 = 9, QUALITY_10 = 10};
|
||||
enum CameraMode {CAMERA_MODE_DEFAULT = 0, CAMERA_MODE_CLASSIC = 1, CAMERA_MODE_FOLLOW = 2};
|
||||
enum ControlMode { CONTROL_CLASSIC = 0, CONTROL_MOUSELOCK = 1, CONTROL_HYBRID = 2, CONTROL_CAMLOCK = 3, CONTROL_MOUSEPAN = 4 };
|
||||
enum RenderQualitySetting { QUALITY_AUTO = 0, QUALITY_1 = 1, QUALITY_2 = 2, QUALITY_3 = 3, QUALITY_4 = 4, QUALITY_5 = 5, QUALITY_6 = 6, QUALITY_7 = 7, QUALITY_8 = 8, QUALITY_9 = 9, QUALITY_10 = 10 };
|
||||
enum CameraMode { CAMERA_MODE_DEFAULT = 0, CAMERA_MODE_CLASSIC = 1, CAMERA_MODE_FOLLOW = 2 };
|
||||
enum TouchCameraMovementMode {
|
||||
TOUCH_CAMERA_MOVEMENT_MODE_DEFAULT = 0,
|
||||
TOUCH_CAMERA_MOVEMENT_MODE_CLASSIC = 1,
|
||||
TOUCH_CAMERA_MOVEMENT_MODE_FOLLOW = 2 };
|
||||
TOUCH_CAMERA_MOVEMENT_MODE_FOLLOW = 2
|
||||
};
|
||||
enum ComputerCameraMovementMode {
|
||||
COMPUTER_CAMERA_MOVEMENT_MODE_DEFAULT = 0,
|
||||
COMPUTER_CAMERA_MOVEMENT_MODE_CLASSIC = 1,
|
||||
COMPUTER_CAMERA_MOVEMENT_MODE_FOLLOW = 2};
|
||||
COMPUTER_CAMERA_MOVEMENT_MODE_FOLLOW = 2
|
||||
};
|
||||
enum TouchMovementMode {
|
||||
TOUCH_MOVEMENT_MODE_DEFAULT = 0,
|
||||
TOUCH_MOVEMENT_MODE_THUMBSTICK = 1,
|
||||
TOUCH_MOVEMENT_MODE_DPAD = 2,
|
||||
TOUCH_MOVEMENT_MODE_THUMBPAD = 3,
|
||||
TOUCH_MOVEMENT_MODE_CLICK_TO_MOVE = 4 };
|
||||
TOUCH_MOVEMENT_MODE_CLICK_TO_MOVE = 4
|
||||
};
|
||||
enum ComputerMovementMode {
|
||||
COMPUTER_MOVEMENT_MODE_DEFAULT = 0,
|
||||
COMPUTER_MOVEMENT_MODE_KBD_MOUSE = 1,
|
||||
COMPUTER_MOVEMENT_MODE_CLICK_TO_MOVE = 2};
|
||||
COMPUTER_MOVEMENT_MODE_CLICK_TO_MOVE = 2
|
||||
};
|
||||
enum YearSettings {
|
||||
Year2016 = 0,
|
||||
Year2015 = 1,
|
||||
@@ -40,7 +44,8 @@ namespace RBX
|
||||
};
|
||||
enum RotationType {
|
||||
ROTATION_TYPE_MOVEMENT_RELATIVE = 0,
|
||||
ROTATION_TYPE_CAMERA_RELATIVE = 1};
|
||||
ROTATION_TYPE_CAMERA_RELATIVE = 1
|
||||
};
|
||||
|
||||
static Reflection::PropDescriptor<GameBasicSettings, float> prop_masterVolume;
|
||||
|
||||
@@ -88,14 +93,14 @@ namespace RBX
|
||||
void setFreeLook(bool canLook) { freeLook = canLook; }
|
||||
bool getFreeLook() { return freeLook; }
|
||||
|
||||
bool inClassicMode() { return controlMode == CONTROL_CLASSIC; }
|
||||
bool inMouseLockMode() { return controlMode == CONTROL_MOUSELOCK; }
|
||||
bool inHybridMode() { return controlMode == CONTROL_HYBRID; }
|
||||
bool inCamlockMode() { return controlMode == CONTROL_CAMLOCK; }
|
||||
bool inMousepanMode() { return controlMode == CONTROL_MOUSEPAN; }
|
||||
bool inClassicMode() { return controlMode == CONTROL_CLASSIC; }
|
||||
bool inMouseLockMode() { return controlMode == CONTROL_MOUSELOCK; }
|
||||
bool inHybridMode() { return controlMode == CONTROL_HYBRID; }
|
||||
bool inCamlockMode() { return controlMode == CONTROL_CAMLOCK; }
|
||||
bool inMousepanMode() { return controlMode == CONTROL_MOUSEPAN; }
|
||||
|
||||
bool mouseLockedInMouseLockMode() { return inMouseLockMode() && isMouseLocked(); }
|
||||
bool camLockedInCamLockMode() { return inCamlockMode() && !getFreeLook(); }
|
||||
bool mouseLockedInMouseLockMode() { return inMouseLockMode() && isMouseLocked(); }
|
||||
bool camLockedInCamLockMode() { return inCamlockMode() && !getFreeLook(); }
|
||||
|
||||
bool getTutorialState(std::string tutorialId);
|
||||
void setTutorialState(std::string tutorialId, bool value);
|
||||
@@ -120,7 +125,7 @@ namespace RBX
|
||||
bool getFullScreen() { return fullscreen; }
|
||||
void setFullScreen(bool value)
|
||||
{
|
||||
if(value != fullscreen)
|
||||
if (value != fullscreen)
|
||||
{
|
||||
fullscreen = value;
|
||||
fullscreenChangedSignal(value);
|
||||
@@ -145,7 +150,7 @@ namespace RBX
|
||||
bool inStudioMode() { return studio; }
|
||||
void setStudioMode(bool value)
|
||||
{
|
||||
if(value != studio)
|
||||
if (value != studio)
|
||||
{
|
||||
studioModeChangedSignal(value);
|
||||
studio = value;
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
#pragma once
|
||||
|
||||
#include "Lua.hpp"
|
||||
|
||||
#include "util/exception.h"
|
||||
#include "util/utilities.h"
|
||||
#include "rbx/Debug.h"
|
||||
#include "rbx/atomic.h"
|
||||
|
||||
namespace RBX { namespace Lua {
|
||||
|
||||
void newweaktable(lua_State *L, const char *mode);
|
||||
|
||||
template<class C, int (C::*Func)(lua_State*)>
|
||||
int memberFunctionProxy(lua_State* thread)
|
||||
{
|
||||
C* c = reinterpret_cast<C*>(lua_touserdata(thread, lua_upvalueindex(1)));
|
||||
return (c->*Func)(thread);
|
||||
}
|
||||
|
||||
template<class C, int (C::*Func)(lua_State*)>
|
||||
void pushMemberFunction(lua_State* L, C* c)
|
||||
{
|
||||
lua_pushlightuserdata(L, (void*)c);
|
||||
lua_pushcclosure(L, &memberFunctionProxy<C, Func>, 1);
|
||||
}
|
||||
|
||||
// TODO: Use traits pattern rather than bool __eq
|
||||
template<class Class, bool __eq = true>
|
||||
class Bridge
|
||||
{
|
||||
public:
|
||||
// 0 arg constructor
|
||||
static Class* pushNewObject(lua_State *L)
|
||||
{
|
||||
Class* data = (Class*)lua_newuserdata(L, sizeof(Class));
|
||||
new(data) Class;
|
||||
luaL_getmetatable(L, className);
|
||||
lua_setmetatable(L, -2);
|
||||
return data;
|
||||
}
|
||||
// 1 arg constructor
|
||||
template<typename Param1>
|
||||
static Class* pushNewObject(lua_State *L, Param1 param1)
|
||||
{
|
||||
Class* data = (Class*)lua_newuserdata(L, sizeof(Class));
|
||||
new(data) Class(param1);
|
||||
luaL_getmetatable(L, className);
|
||||
lua_setmetatable(L, -2);
|
||||
return data;
|
||||
}
|
||||
// 2 arg constructor
|
||||
template<typename Param1, typename Param2>
|
||||
static Class* pushNewObject(lua_State *L, Param1 param1, Param2 param2)
|
||||
{
|
||||
Class* data = (Class*)lua_newuserdata(L, sizeof(Class));
|
||||
new(data) Class(param1, param2);
|
||||
luaL_getmetatable(L, className);
|
||||
lua_setmetatable(L, -2);
|
||||
return data;
|
||||
}
|
||||
|
||||
// Throws an exception if index doesn't hold the right type
|
||||
static Class& getObject(lua_State *L, unsigned int index) {
|
||||
void *ud = luaL_checkudata(L, index, className);
|
||||
return *reinterpret_cast<Class*>(ud);
|
||||
}
|
||||
|
||||
// Returns false if index doesn't hold the right type (leaving value unchanged)
|
||||
template<typename V>
|
||||
static bool getValue(lua_State *L, unsigned int index, V& value) {
|
||||
|
||||
// A re-implementation of luaL_checkudata that doesn't throw an exception
|
||||
void *p = lua_touserdata(L, index);
|
||||
if (p != NULL) { /* value is a userdata? */
|
||||
if (lua_getmetatable(L, index)) { /* does it have a metatable? */
|
||||
lua_getfield(L, LUA_REGISTRYINDEX, className); /* get correct metatable */
|
||||
if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */
|
||||
lua_pop(L, 2); /* remove both metatables */
|
||||
value = *reinterpret_cast<Class*>(p);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
lua_pop(L, 2); /* remove both metatables */
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void registerClass (lua_State *L);
|
||||
|
||||
/// gcc craps out with the error while it is called from ScriptContext.cpp for registerClass fns for the Bridge e.g EventBridge::registerClass(globalState);
|
||||
// error: 'static int RBX::Lua::Bridge<Class, __eq>::on_index(lua_State*) [with Class = RBX::Lua::EventInstance, bool __eq = true]' is protected
|
||||
#ifdef _WIN32
|
||||
protected:
|
||||
#endif
|
||||
|
||||
// The following members must be implemented by client:
|
||||
static int on_index(const Class& object, const char* name, lua_State *L);
|
||||
static void on_newindex(Class& object, const char* name, lua_State *L);
|
||||
|
||||
// This member may be specialized when StringConverter has no implementation for Class:
|
||||
static int on_tostring(const Class& object, lua_State *L);
|
||||
|
||||
static const char* className;
|
||||
|
||||
static int on_gc(lua_State *L) {
|
||||
getObject(L, 1).~Class();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_tostring(lua_State *L) {
|
||||
return on_tostring(getObject(L, 1), L);
|
||||
}
|
||||
|
||||
static int on_newindex(lua_State *L) {
|
||||
const char* name = lua_checkstring_secure(L, 2);
|
||||
on_newindex(getObject(L, 1), name, L);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_index(lua_State *L) {
|
||||
const char* name = lua_checkstring_secure(L, 2);
|
||||
return on_index(getObject(L, 1), name, L);
|
||||
}
|
||||
|
||||
static int on_eq(lua_State *L) {
|
||||
lua_pushboolean(L, getObject(L, 1) == getObject(L, 2));
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
|
||||
// This class hides parent on purpose
|
||||
template<class Class>
|
||||
class SharedPtrBridge : protected Bridge<boost::shared_ptr<Class>, false>
|
||||
{
|
||||
public:
|
||||
static void registerClass (lua_State *L)
|
||||
{
|
||||
Bridge<boost::shared_ptr<Class>, false>::registerClass(L);
|
||||
}
|
||||
|
||||
static void registerClassLibrary (lua_State *L) {
|
||||
// Declare the UserData re-use table
|
||||
lua_pushlightuserdata(L, (void*)&push);
|
||||
newweaktable(L, "v");
|
||||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
}
|
||||
|
||||
static void push(lua_State *L, boost::shared_ptr<Class> instance)
|
||||
{
|
||||
if (instance==NULL)
|
||||
lua_pushnil(L);
|
||||
else
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
int i = lua_gettop(L);
|
||||
#endif
|
||||
// Matt Campbell at Serotek Corporation had a great idea. Create only
|
||||
// a single instance of the userdata and re-use it. This way the userdata
|
||||
// can be used in table keys, and we don't need an __eq operator
|
||||
// Also see http://lua-users.org/lists/lua-l/2004-07/msg00391.html
|
||||
|
||||
lua_pushlightuserdata(L, (void*)&push ); /* Registry mapping for weak table. Key is arbitrary. */
|
||||
lua_rawget(L, LUA_REGISTRYINDEX); // Stack: t
|
||||
RBXASSERT(!lua_isnil( L, -1 )); // Did you forget to call registerClassLibrary??
|
||||
|
||||
// Now the top of the stack is our lookup table
|
||||
// See if we already have a UserData for this instance
|
||||
lua_pushlightuserdata (L, (void*)instance.get()); // Stack: t, i
|
||||
lua_rawget (L, -2); // Stack: t, t[i]
|
||||
|
||||
if( lua_isnil( L, -1 ) ) { // Stack: t, nil or I
|
||||
lua_pop (L, 1); // Stack: t
|
||||
Bridge<boost::shared_ptr<Class>, false>::pushNewObject(L, instance); // Stack: t, I
|
||||
/* store the value for later use */
|
||||
lua_pushlightuserdata (L, (void*)instance.get()); // Stack: t, I, i
|
||||
lua_pushvalue (L, -2); // Stack: t, I, i, I
|
||||
lua_rawset (L, -4); // Stack: t, I
|
||||
}
|
||||
lua_remove (L, -2); // Stack: I
|
||||
#ifdef _DEBUG
|
||||
RBXASSERT(lua_gettop(L) == i + 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static boost::shared_ptr<Class> getPtr(lua_State *L, unsigned int index)
|
||||
{
|
||||
if (lua_isnil(L, index))
|
||||
return boost::shared_ptr<Class>();
|
||||
else
|
||||
return RBX::Lua::Bridge<boost::shared_ptr<Class>, false>::getObject(L, index);
|
||||
}
|
||||
|
||||
template<typename V>
|
||||
static bool getPtr(lua_State *L, unsigned int index, V& value) {
|
||||
if (lua_isnil(L, index))
|
||||
{
|
||||
value = boost::shared_ptr<Class>();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return Bridge<boost::shared_ptr<Class>, false>::getValue(L, index, value);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// This class hides Bridge on purpose
|
||||
template<class T>
|
||||
class SingletonBridge : protected Bridge<T, false>
|
||||
{
|
||||
public:
|
||||
static void registerClass (lua_State *L) {
|
||||
Bridge<T, false>::registerClass(L);
|
||||
}
|
||||
|
||||
static void registerClassLibrary (lua_State *L) {
|
||||
// Declare the UserData re-use table
|
||||
lua_pushlightuserdata(L, (void*)&push);
|
||||
lua_newtable(L); // Not a weak table, unlike SharedPtrBridge
|
||||
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||
}
|
||||
|
||||
static void push(lua_State *L, T item)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
int i = lua_gettop(L);
|
||||
#endif
|
||||
// Matt Campbell at Serotek Corporation had a great idea. Create only
|
||||
// a single instance of the userdata and re-use it. This way the userdata
|
||||
// can be used in table keys
|
||||
// Also see http://lua-users.org/lists/lua-l/2004-07/msg00391.html
|
||||
|
||||
lua_pushlightuserdata(L, (void*)&push); /* Registry mapping for table. Key is arbitrary. */
|
||||
lua_rawget(L, LUA_REGISTRYINDEX); // Stack: t
|
||||
RBXASSERT(!lua_isnil( L, -1 )); // Did you forget to call registerClassLibrary??
|
||||
|
||||
// Now the top of the stack is our lookup table
|
||||
// See if we already have a UserData for this instance
|
||||
lua_pushlightuserdata (L, (void*)item); // Stack: t, i
|
||||
lua_rawget (L, -2); // Stack: t, t[i]
|
||||
|
||||
// TODO: only allow explicit, one-time declaration
|
||||
if( lua_isnil( L, -1 ) ) { // Stack: t, nil or I
|
||||
lua_pop (L, 1); // Stack: t
|
||||
Bridge<T, false>::pushNewObject(L, item); // Stack: t, I
|
||||
/* store the value for later use */
|
||||
lua_pushlightuserdata (L, (void*)item); // Stack: t, I, i
|
||||
lua_pushvalue (L, -2); // Stack: t, I, i, I
|
||||
lua_rawset (L, -4); // Stack: t, I
|
||||
}
|
||||
lua_remove (L, -2); // Stack: I
|
||||
|
||||
#ifdef _DEBUG
|
||||
RBXASSERT(lua_gettop(L) == i + 1);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
} }
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Lua
|
||||
{
|
||||
extern const char* safe_lua_tostring(lua_State *L, int idx);
|
||||
extern const char* throwable_lua_tostring(lua_State *L, int idx);
|
||||
extern float lua_tofloat(lua_State *L, int idx);
|
||||
extern void protect_metatable(lua_State* thread, int index);
|
||||
inline void lua_pushstring(lua_State* thread, const std::string& s)
|
||||
{
|
||||
lua_pushlstring(thread, s.c_str(), s.size());
|
||||
}
|
||||
|
||||
const char* lua_checkstring_secure(lua_State* L, int idx);
|
||||
|
||||
void lua_resetstack(lua_State* L, int idx);
|
||||
|
||||
// Pops items from the stack when it goes out of scope
|
||||
class ScopedPopper
|
||||
{
|
||||
int popCount;
|
||||
lua_State* const thread;
|
||||
public:
|
||||
ScopedPopper(lua_State* thread, int popCount)
|
||||
:thread(thread),popCount(popCount)
|
||||
{}
|
||||
|
||||
ScopedPopper& operator +=(int popCount)
|
||||
{
|
||||
this->popCount += popCount;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ScopedPopper& operator -=(int popCount)
|
||||
{
|
||||
this->popCount -= popCount;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~ScopedPopper()
|
||||
{
|
||||
lua_pop(thread, popCount);
|
||||
}
|
||||
};
|
||||
|
||||
class ScopedState
|
||||
{
|
||||
lua_State* const thread;
|
||||
public:
|
||||
ScopedState()
|
||||
:thread(luaL_newstate())
|
||||
{}
|
||||
|
||||
~ScopedState()
|
||||
{
|
||||
lua_close(thread);
|
||||
}
|
||||
|
||||
operator lua_State*()
|
||||
{
|
||||
return thread;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include "lua/lua.hpp"
|
||||
|
||||
RBX::Lua::LuaStubGen<609> stub609;
|
||||
RBX::Lua::LuaStubGen<288> stub288;
|
||||
RBX::Lua::LuaStubGen<646> stub646;
|
||||
RBX::Lua::LuaStubGen<387> stub387;
|
||||
RBX::Lua::LuaStubGen<649> stub649;
|
||||
RBX::Lua::LuaStubGen<687> stub687;
|
||||
RBX::Lua::LuaStubGen<836> stub836;
|
||||
RBX::Lua::LuaStubGen<959> stub959;
|
||||
RBX::Lua::LuaStubGen<803> stub803;
|
||||
RBX::Lua::LuaStubGen<107> stub107;
|
||||
RBX::Lua::LuaStubGen<361> stub361;
|
||||
RBX::Lua::LuaStubGen<172> stub172;
|
||||
RBX::Lua::LuaStubGen<666> stub666;
|
||||
RBX::Lua::LuaStubGen<901> stub901;
|
||||
RBX::Lua::LuaStubGen<287> stub287;
|
||||
RBX::Lua::LuaStubGen<523> stub523;
|
||||
RBX::Lua::LuaStubGen<701> stub701;
|
||||
RBX::Lua::LuaStubGen<316> stub316;
|
||||
RBX::Lua::LuaStubGen<671> stub671;
|
||||
RBX::Lua::LuaStubGen<423> stub423;
|
||||
RBX::Lua::LuaStubGen<718> stub718;
|
||||
RBX::Lua::LuaStubGen<711> stub711;
|
||||
RBX::Lua::LuaStubGen<211> stub211;
|
||||
RBX::Lua::LuaStubGen<158> stub158;
|
||||
RBX::Lua::LuaStubGen<219> stub219;
|
||||
RBX::Lua::LuaStubGen<68> stub68;
|
||||
RBX::Lua::LuaStubGen<790> stub790;
|
||||
RBX::Lua::LuaStubGen<58> stub58;
|
||||
RBX::Lua::LuaStubGen<919> stub919;
|
||||
RBX::Lua::LuaStubGen<747> stub747;
|
||||
RBX::Lua::LuaStubGen<161> stub161;
|
||||
RBX::Lua::LuaStubGen<119> stub119;
|
||||
RBX::Lua::LuaStubGen<622> stub622;
|
||||
RBX::Lua::LuaStubGen<183> stub183;
|
||||
RBX::Lua::LuaStubGen<93> stub93;
|
||||
RBX::Lua::LuaStubGen<560> stub560;
|
||||
RBX::Lua::LuaStubGen<382> stub382;
|
||||
RBX::Lua::LuaStubGen<455> stub455;
|
||||
RBX::Lua::LuaStubGen<562> stub562;
|
||||
RBX::Lua::LuaStubGen<554> stub554;
|
||||
RBX::Lua::LuaStubGen<652> stub652;
|
||||
RBX::Lua::LuaStubGen<997> stub997;
|
||||
RBX::Lua::LuaStubGen<237> stub237;
|
||||
RBX::Lua::LuaStubGen<655> stub655;
|
||||
RBX::Lua::LuaStubGen<892> stub892;
|
||||
RBX::Lua::LuaStubGen<840> stub840;
|
||||
RBX::Lua::LuaStubGen<872> stub872;
|
||||
RBX::Lua::LuaStubGen<821> stub821;
|
||||
RBX::Lua::LuaStubGen<314> stub314;
|
||||
RBX::Lua::LuaStubGen<249> stub249;
|
||||
RBX::Lua::LuaStubGen<82> stub82;
|
||||
RBX::Lua::LuaStubGen<470> stub470;
|
||||
RBX::Lua::LuaStubGen<203> stub203;
|
||||
RBX::Lua::LuaStubGen<722> stub722;
|
||||
RBX::Lua::LuaStubGen<492> stub492;
|
||||
RBX::Lua::LuaStubGen<29> stub29;
|
||||
RBX::Lua::LuaStubGen<429> stub429;
|
||||
RBX::Lua::LuaStubGen<933> stub933;
|
||||
RBX::Lua::LuaStubGen<983> stub983;
|
||||
RBX::Lua::LuaStubGen<700> stub700;
|
||||
RBX::Lua::LuaStubGen<471> stub471;
|
||||
RBX::Lua::LuaStubGen<453> stub453;
|
||||
RBX::Lua::LuaStubGen<396> stub396;
|
||||
RBX::Lua::LuaStubGen<330> stub330;
|
||||
RBX::Lua::LuaStubGen<206> stub206;
|
||||
RBX::Lua::LuaStubGen<362> stub362;
|
||||
RBX::Lua::LuaStubGen<737> stub737;
|
||||
RBX::Lua::LuaStubGen<390> stub390;
|
||||
RBX::Lua::LuaStubGen<914> stub914;
|
||||
RBX::Lua::LuaStubGen<985> stub985;
|
||||
RBX::Lua::LuaStubGen<490> stub490;
|
||||
RBX::Lua::LuaStubGen<786> stub786;
|
||||
RBX::Lua::LuaStubGen<173> stub173;
|
||||
RBX::Lua::LuaStubGen<346> stub346;
|
||||
RBX::Lua::LuaStubGen<643> stub643;
|
||||
RBX::Lua::LuaStubGen<331> stub331;
|
||||
RBX::Lua::LuaStubGen<539> stub539;
|
||||
RBX::Lua::LuaStubGen<134> stub134;
|
||||
RBX::Lua::LuaStubGen<325> stub325;
|
||||
RBX::Lua::LuaStubGen<34> stub34;
|
||||
RBX::Lua::LuaStubGen<88> stub88;
|
||||
RBX::Lua::LuaStubGen<536> stub536;
|
||||
RBX::Lua::LuaStubGen<79> stub79;
|
||||
RBX::Lua::LuaStubGen<459> stub459;
|
||||
RBX::Lua::LuaStubGen<842> stub842;
|
||||
RBX::Lua::LuaStubGen<370> stub370;
|
||||
RBX::Lua::LuaStubGen<553> stub553;
|
||||
RBX::Lua::LuaStubGen<486> stub486;
|
||||
RBX::Lua::LuaStubGen<591> stub591;
|
||||
RBX::Lua::LuaStubGen<797> stub797;
|
||||
RBX::Lua::LuaStubGen<571> stub571;
|
||||
RBX::Lua::LuaStubGen<907> stub907;
|
||||
RBX::Lua::LuaStubGen<43> stub43;
|
||||
RBX::Lua::LuaStubGen<918> stub918;
|
||||
RBX::Lua::LuaStubGen<866> stub866;
|
||||
RBX::Lua::LuaStubGen<856> stub856;
|
||||
RBX::Lua::LuaStubGen<751> stub751;
|
||||
RBX::Lua::LuaStubGen<124> stub124;
|
||||
RBX::Lua::LuaStubGen<559> stub559;
|
||||
RBX::Lua::LuaStubGen<620> stub620;
|
||||
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include "lua/lua.hpp"
|
||||
|
||||
RBX::Lua::LuaStubGen<339> stub339;
|
||||
RBX::Lua::LuaStubGen<510> stub510;
|
||||
RBX::Lua::LuaStubGen<634> stub634;
|
||||
RBX::Lua::LuaStubGen<17> stub17;
|
||||
RBX::Lua::LuaStubGen<302> stub302;
|
||||
RBX::Lua::LuaStubGen<454> stub454;
|
||||
RBX::Lua::LuaStubGen<814> stub814;
|
||||
RBX::Lua::LuaStubGen<887> stub887;
|
||||
RBX::Lua::LuaStubGen<824> stub824;
|
||||
RBX::Lua::LuaStubGen<703> stub703;
|
||||
RBX::Lua::LuaStubGen<932> stub932;
|
||||
RBX::Lua::LuaStubGen<220> stub220;
|
||||
RBX::Lua::LuaStubGen<972> stub972;
|
||||
RBX::Lua::LuaStubGen<99> stub99;
|
||||
RBX::Lua::LuaStubGen<627> stub627;
|
||||
RBX::Lua::LuaStubGen<13> stub13;
|
||||
RBX::Lua::LuaStubGen<633> stub633;
|
||||
RBX::Lua::LuaStubGen<800> stub800;
|
||||
RBX::Lua::LuaStubGen<875> stub875;
|
||||
RBX::Lua::LuaStubGen<458> stub458;
|
||||
RBX::Lua::LuaStubGen<181> stub181;
|
||||
RBX::Lua::LuaStubGen<352> stub352;
|
||||
RBX::Lua::LuaStubGen<920> stub920;
|
||||
RBX::Lua::LuaStubGen<951> stub951;
|
||||
RBX::Lua::LuaStubGen<319> stub319;
|
||||
RBX::Lua::LuaStubGen<716> stub716;
|
||||
RBX::Lua::LuaStubGen<529> stub529;
|
||||
RBX::Lua::LuaStubGen<507> stub507;
|
||||
RBX::Lua::LuaStubGen<85> stub85;
|
||||
RBX::Lua::LuaStubGen<105> stub105;
|
||||
RBX::Lua::LuaStubGen<727> stub727;
|
||||
RBX::Lua::LuaStubGen<568> stub568;
|
||||
RBX::Lua::LuaStubGen<749> stub749;
|
||||
RBX::Lua::LuaStubGen<530> stub530;
|
||||
RBX::Lua::LuaStubGen<207> stub207;
|
||||
RBX::Lua::LuaStubGen<5> stub5;
|
||||
RBX::Lua::LuaStubGen<413> stub413;
|
||||
RBX::Lua::LuaStubGen<675> stub675;
|
||||
RBX::Lua::LuaStubGen<462> stub462;
|
||||
RBX::Lua::LuaStubGen<762> stub762;
|
||||
RBX::Lua::LuaStubGen<397> stub397;
|
||||
RBX::Lua::LuaStubGen<431> stub431;
|
||||
RBX::Lua::LuaStubGen<47> stub47;
|
||||
RBX::Lua::LuaStubGen<307> stub307;
|
||||
RBX::Lua::LuaStubGen<692> stub692;
|
||||
RBX::Lua::LuaStubGen<320> stub320;
|
||||
RBX::Lua::LuaStubGen<947> stub947;
|
||||
RBX::Lua::LuaStubGen<775> stub775;
|
||||
RBX::Lua::LuaStubGen<647> stub647;
|
||||
RBX::Lua::LuaStubGen<766> stub766;
|
||||
RBX::Lua::LuaStubGen<661> stub661;
|
||||
RBX::Lua::LuaStubGen<384> stub384;
|
||||
RBX::Lua::LuaStubGen<235> stub235;
|
||||
RBX::Lua::LuaStubGen<177> stub177;
|
||||
RBX::Lua::LuaStubGen<535> stub535;
|
||||
RBX::Lua::LuaStubGen<580> stub580;
|
||||
RBX::Lua::LuaStubGen<854> stub854;
|
||||
RBX::Lua::LuaStubGen<987> stub987;
|
||||
RBX::Lua::LuaStubGen<891> stub891;
|
||||
RBX::Lua::LuaStubGen<846> stub846;
|
||||
RBX::Lua::LuaStubGen<630> stub630;
|
||||
RBX::Lua::LuaStubGen<491> stub491;
|
||||
RBX::Lua::LuaStubGen<573> stub573;
|
||||
RBX::Lua::LuaStubGen<488> stub488;
|
||||
RBX::Lua::LuaStubGen<695> stub695;
|
||||
RBX::Lua::LuaStubGen<995> stub995;
|
||||
RBX::Lua::LuaStubGen<321> stub321;
|
||||
RBX::Lua::LuaStubGen<322> stub322;
|
||||
RBX::Lua::LuaStubGen<504> stub504;
|
||||
RBX::Lua::LuaStubGen<403> stub403;
|
||||
RBX::Lua::LuaStubGen<197> stub197;
|
||||
RBX::Lua::LuaStubGen<487> stub487;
|
||||
RBX::Lua::LuaStubGen<231> stub231;
|
||||
RBX::Lua::LuaStubGen<236> stub236;
|
||||
RBX::Lua::LuaStubGen<128> stub128;
|
||||
RBX::Lua::LuaStubGen<381> stub381;
|
||||
RBX::Lua::LuaStubGen<705> stub705;
|
||||
RBX::Lua::LuaStubGen<61> stub61;
|
||||
RBX::Lua::LuaStubGen<214> stub214;
|
||||
RBX::Lua::LuaStubGen<497> stub497;
|
||||
RBX::Lua::LuaStubGen<232> stub232;
|
||||
RBX::Lua::LuaStubGen<725> stub725;
|
||||
RBX::Lua::LuaStubGen<371> stub371;
|
||||
RBX::Lua::LuaStubGen<401> stub401;
|
||||
RBX::Lua::LuaStubGen<526> stub526;
|
||||
RBX::Lua::LuaStubGen<448> stub448;
|
||||
RBX::Lua::LuaStubGen<961> stub961;
|
||||
RBX::Lua::LuaStubGen<97> stub97;
|
||||
RBX::Lua::LuaStubGen<375> stub375;
|
||||
RBX::Lua::LuaStubGen<979> stub979;
|
||||
RBX::Lua::LuaStubGen<908> stub908;
|
||||
RBX::Lua::LuaStubGen<227> stub227;
|
||||
RBX::Lua::LuaStubGen<112> stub112;
|
||||
RBX::Lua::LuaStubGen<819> stub819;
|
||||
RBX::Lua::LuaStubGen<208> stub208;
|
||||
RBX::Lua::LuaStubGen<78> stub78;
|
||||
RBX::Lua::LuaStubGen<992> stub992;
|
||||
RBX::Lua::LuaStubGen<209> stub209;
|
||||
RBX::Lua::LuaStubGen<881> stub881;
|
||||
RBX::Lua::LuaStubGen<463> stub463;
|
||||
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include "lua/lua.hpp"
|
||||
|
||||
RBX::Lua::LuaStubGen<925> stub925;
|
||||
RBX::Lua::LuaStubGen<311> stub311;
|
||||
RBX::Lua::LuaStubGen<801> stub801;
|
||||
RBX::Lua::LuaStubGen<450> stub450;
|
||||
RBX::Lua::LuaStubGen<469> stub469;
|
||||
RBX::Lua::LuaStubGen<522> stub522;
|
||||
RBX::Lua::LuaStubGen<412> stub412;
|
||||
RBX::Lua::LuaStubGen<418> stub418;
|
||||
RBX::Lua::LuaStubGen<879> stub879;
|
||||
RBX::Lua::LuaStubGen<745> stub745;
|
||||
RBX::Lua::LuaStubGen<818> stub818;
|
||||
RBX::Lua::LuaStubGen<69> stub69;
|
||||
RBX::Lua::LuaStubGen<122> stub122;
|
||||
RBX::Lua::LuaStubGen<654> stub654;
|
||||
RBX::Lua::LuaStubGen<385> stub385;
|
||||
RBX::Lua::LuaStubGen<160> stub160;
|
||||
RBX::Lua::LuaStubGen<550> stub550;
|
||||
RBX::Lua::LuaStubGen<199> stub199;
|
||||
RBX::Lua::LuaStubGen<897> stub897;
|
||||
RBX::Lua::LuaStubGen<60> stub60;
|
||||
RBX::Lua::LuaStubGen<420> stub420;
|
||||
RBX::Lua::LuaStubGen<712> stub712;
|
||||
RBX::Lua::LuaStubGen<581> stub581;
|
||||
RBX::Lua::LuaStubGen<613> stub613;
|
||||
RBX::Lua::LuaStubGen<928> stub928;
|
||||
RBX::Lua::LuaStubGen<391> stub391;
|
||||
RBX::Lua::LuaStubGen<868> stub868;
|
||||
RBX::Lua::LuaStubGen<517> stub517;
|
||||
RBX::Lua::LuaStubGen<393> stub393;
|
||||
RBX::Lua::LuaStubGen<593> stub593;
|
||||
RBX::Lua::LuaStubGen<865> stub865;
|
||||
RBX::Lua::LuaStubGen<610> stub610;
|
||||
RBX::Lua::LuaStubGen<289> stub289;
|
||||
RBX::Lua::LuaStubGen<508> stub508;
|
||||
RBX::Lua::LuaStubGen<779> stub779;
|
||||
RBX::Lua::LuaStubGen<224> stub224;
|
||||
RBX::Lua::LuaStubGen<527> stub527;
|
||||
RBX::Lua::LuaStubGen<733> stub733;
|
||||
RBX::Lua::LuaStubGen<419> stub419;
|
||||
RBX::Lua::LuaStubGen<106> stub106;
|
||||
RBX::Lua::LuaStubGen<501> stub501;
|
||||
RBX::Lua::LuaStubGen<677> stub677;
|
||||
RBX::Lua::LuaStubGen<212> stub212;
|
||||
RBX::Lua::LuaStubGen<859> stub859;
|
||||
RBX::Lua::LuaStubGen<697> stub697;
|
||||
RBX::Lua::LuaStubGen<357> stub357;
|
||||
RBX::Lua::LuaStubGen<233> stub233;
|
||||
RBX::Lua::LuaStubGen<248> stub248;
|
||||
RBX::Lua::LuaStubGen<698> stub698;
|
||||
RBX::Lua::LuaStubGen<552> stub552;
|
||||
RBX::Lua::LuaStubGen<19> stub19;
|
||||
RBX::Lua::LuaStubGen<873> stub873;
|
||||
RBX::Lua::LuaStubGen<169> stub169;
|
||||
RBX::Lua::LuaStubGen<367> stub367;
|
||||
RBX::Lua::LuaStubGen<763> stub763;
|
||||
RBX::Lua::LuaStubGen<115> stub115;
|
||||
RBX::Lua::LuaStubGen<477> stub477;
|
||||
RBX::Lua::LuaStubGen<475> stub475;
|
||||
RBX::Lua::LuaStubGen<341> stub341;
|
||||
RBX::Lua::LuaStubGen<686> stub686;
|
||||
RBX::Lua::LuaStubGen<939> stub939;
|
||||
RBX::Lua::LuaStubGen<648> stub648;
|
||||
RBX::Lua::LuaStubGen<277> stub277;
|
||||
RBX::Lua::LuaStubGen<584> stub584;
|
||||
RBX::Lua::LuaStubGen<776> stub776;
|
||||
RBX::Lua::LuaStubGen<684> stub684;
|
||||
RBX::Lua::LuaStubGen<155> stub155;
|
||||
RBX::Lua::LuaStubGen<51> stub51;
|
||||
RBX::Lua::LuaStubGen<994> stub994;
|
||||
RBX::Lua::LuaStubGen<702> stub702;
|
||||
RBX::Lua::LuaStubGen<3> stub3;
|
||||
RBX::Lua::LuaStubGen<73> stub73;
|
||||
RBX::Lua::LuaStubGen<579> stub579;
|
||||
RBX::Lua::LuaStubGen<83> stub83;
|
||||
RBX::Lua::LuaStubGen<768> stub768;
|
||||
RBX::Lua::LuaStubGen<813> stub813;
|
||||
RBX::Lua::LuaStubGen<604> stub604;
|
||||
RBX::Lua::LuaStubGen<312> stub312;
|
||||
RBX::Lua::LuaStubGen<588> stub588;
|
||||
RBX::Lua::LuaStubGen<834> stub834;
|
||||
RBX::Lua::LuaStubGen<313> stub313;
|
||||
RBX::Lua::LuaStubGen<967> stub967;
|
||||
RBX::Lua::LuaStubGen<784> stub784;
|
||||
RBX::Lua::LuaStubGen<139> stub139;
|
||||
RBX::Lua::LuaStubGen<555> stub555;
|
||||
RBX::Lua::LuaStubGen<157> stub157;
|
||||
RBX::Lua::LuaStubGen<226> stub226;
|
||||
RBX::Lua::LuaStubGen<263> stub263;
|
||||
RBX::Lua::LuaStubGen<863> stub863;
|
||||
RBX::Lua::LuaStubGen<882> stub882;
|
||||
RBX::Lua::LuaStubGen<110> stub110;
|
||||
RBX::Lua::LuaStubGen<274> stub274;
|
||||
RBX::Lua::LuaStubGen<736> stub736;
|
||||
RBX::Lua::LuaStubGen<113> stub113;
|
||||
RBX::Lua::LuaStubGen<484> stub484;
|
||||
RBX::Lua::LuaStubGen<638> stub638;
|
||||
RBX::Lua::LuaStubGen<49> stub49;
|
||||
RBX::Lua::LuaStubGen<774> stub774;
|
||||
RBX::Lua::LuaStubGen<742> stub742;
|
||||
RBX::Lua::LuaStubGen<485> stub485;
|
||||
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include "lua/lua.hpp"
|
||||
|
||||
RBX::Lua::LuaStubGen<290> stub290;
|
||||
RBX::Lua::LuaStubGen<734> stub734;
|
||||
RBX::Lua::LuaStubGen<543> stub543;
|
||||
RBX::Lua::LuaStubGen<433> stub433;
|
||||
RBX::Lua::LuaStubGen<871> stub871;
|
||||
RBX::Lua::LuaStubGen<308> stub308;
|
||||
RBX::Lua::LuaStubGen<685> stub685;
|
||||
RBX::Lua::LuaStubGen<839> stub839;
|
||||
RBX::Lua::LuaStubGen<870> stub870;
|
||||
RBX::Lua::LuaStubGen<910> stub910;
|
||||
RBX::Lua::LuaStubGen<150> stub150;
|
||||
RBX::Lua::LuaStubGen<439> stub439;
|
||||
RBX::Lua::LuaStubGen<799> stub799;
|
||||
RBX::Lua::LuaStubGen<760> stub760;
|
||||
RBX::Lua::LuaStubGen<878> stub878;
|
||||
RBX::Lua::LuaStubGen<912> stub912;
|
||||
RBX::Lua::LuaStubGen<168> stub168;
|
||||
RBX::Lua::LuaStubGen<743> stub743;
|
||||
RBX::Lua::LuaStubGen<624> stub624;
|
||||
RBX::Lua::LuaStubGen<516> stub516;
|
||||
RBX::Lua::LuaStubGen<545> stub545;
|
||||
RBX::Lua::LuaStubGen<148> stub148;
|
||||
RBX::Lua::LuaStubGen<121> stub121;
|
||||
RBX::Lua::LuaStubGen<977> stub977;
|
||||
RBX::Lua::LuaStubGen<998> stub998;
|
||||
RBX::Lua::LuaStubGen<156> stub156;
|
||||
RBX::Lua::LuaStubGen<999> stub999;
|
||||
RBX::Lua::LuaStubGen<860> stub860;
|
||||
RBX::Lua::LuaStubGen<41> stub41;
|
||||
RBX::Lua::LuaStubGen<479> stub479;
|
||||
RBX::Lua::LuaStubGen<366> stub366;
|
||||
RBX::Lua::LuaStubGen<938> stub938;
|
||||
RBX::Lua::LuaStubGen<577> stub577;
|
||||
RBX::Lua::LuaStubGen<640> stub640;
|
||||
RBX::Lua::LuaStubGen<956> stub956;
|
||||
RBX::Lua::LuaStubGen<929> stub929;
|
||||
RBX::Lua::LuaStubGen<574> stub574;
|
||||
RBX::Lua::LuaStubGen<619> stub619;
|
||||
RBX::Lua::LuaStubGen<166> stub166;
|
||||
RBX::Lua::LuaStubGen<198> stub198;
|
||||
RBX::Lua::LuaStubGen<11> stub11;
|
||||
RBX::Lua::LuaStubGen<64> stub64;
|
||||
RBX::Lua::LuaStubGen<221> stub221;
|
||||
RBX::Lua::LuaStubGen<564> stub564;
|
||||
RBX::Lua::LuaStubGen<56> stub56;
|
||||
RBX::Lua::LuaStubGen<787> stub787;
|
||||
RBX::Lua::LuaStubGen<713> stub713;
|
||||
RBX::Lua::LuaStubGen<777> stub777;
|
||||
RBX::Lua::LuaStubGen<541> stub541;
|
||||
RBX::Lua::LuaStubGen<187> stub187;
|
||||
RBX::Lua::LuaStubGen<600> stub600;
|
||||
RBX::Lua::LuaStubGen<472> stub472;
|
||||
RBX::Lua::LuaStubGen<196> stub196;
|
||||
RBX::Lua::LuaStubGen<323> stub323;
|
||||
RBX::Lua::LuaStubGen<616> stub616;
|
||||
RBX::Lua::LuaStubGen<242> stub242;
|
||||
RBX::Lua::LuaStubGen<699> stub699;
|
||||
RBX::Lua::LuaStubGen<678> stub678;
|
||||
RBX::Lua::LuaStubGen<532> stub532;
|
||||
RBX::Lua::LuaStubGen<949> stub949;
|
||||
RBX::Lua::LuaStubGen<973> stub973;
|
||||
RBX::Lua::LuaStubGen<270> stub270;
|
||||
RBX::Lua::LuaStubGen<14> stub14;
|
||||
RBX::Lua::LuaStubGen<451> stub451;
|
||||
RBX::Lua::LuaStubGen<12> stub12;
|
||||
RBX::Lua::LuaStubGen<809> stub809;
|
||||
RBX::Lua::LuaStubGen<642> stub642;
|
||||
RBX::Lua::LuaStubGen<324> stub324;
|
||||
RBX::Lua::LuaStubGen<7> stub7;
|
||||
RBX::Lua::LuaStubGen<569> stub569;
|
||||
RBX::Lua::LuaStubGen<880> stub880;
|
||||
RBX::Lua::LuaStubGen<828> stub828;
|
||||
RBX::Lua::LuaStubGen<35> stub35;
|
||||
RBX::Lua::LuaStubGen<547> stub547;
|
||||
RBX::Lua::LuaStubGen<447> stub447;
|
||||
RBX::Lua::LuaStubGen<228> stub228;
|
||||
RBX::Lua::LuaStubGen<739> stub739;
|
||||
RBX::Lua::LuaStubGen<796> stub796;
|
||||
RBX::Lua::LuaStubGen<889> stub889;
|
||||
RBX::Lua::LuaStubGen<317> stub317;
|
||||
RBX::Lua::LuaStubGen<668> stub668;
|
||||
RBX::Lua::LuaStubGen<598> stub598;
|
||||
RBX::Lua::LuaStubGen<781> stub781;
|
||||
RBX::Lua::LuaStubGen<466> stub466;
|
||||
RBX::Lua::LuaStubGen<823> stub823;
|
||||
RBX::Lua::LuaStubGen<753> stub753;
|
||||
RBX::Lua::LuaStubGen<101> stub101;
|
||||
RBX::Lua::LuaStubGen<170> stub170;
|
||||
RBX::Lua::LuaStubGen<612> stub612;
|
||||
RBX::Lua::LuaStubGen<40> stub40;
|
||||
RBX::Lua::LuaStubGen<502> stub502;
|
||||
RBX::Lua::LuaStubGen<621> stub621;
|
||||
RBX::Lua::LuaStubGen<893> stub893;
|
||||
RBX::Lua::LuaStubGen<452> stub452;
|
||||
RBX::Lua::LuaStubGen<345> stub345;
|
||||
RBX::Lua::LuaStubGen<546> stub546;
|
||||
RBX::Lua::LuaStubGen<623> stub623;
|
||||
RBX::Lua::LuaStubGen<513> stub513;
|
||||
RBX::Lua::LuaStubGen<15> stub15;
|
||||
RBX::Lua::LuaStubGen<758> stub758;
|
||||
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include "lua/lua.hpp"
|
||||
|
||||
RBX::Lua::LuaStubGen<614> stub614;
|
||||
RBX::Lua::LuaStubGen<481> stub481;
|
||||
RBX::Lua::LuaStubGen<217> stub217;
|
||||
RBX::Lua::LuaStubGen<883> stub883;
|
||||
RBX::Lua::LuaStubGen<261> stub261;
|
||||
RBX::Lua::LuaStubGen<432> stub432;
|
||||
RBX::Lua::LuaStubGen<383> stub383;
|
||||
RBX::Lua::LuaStubGen<791> stub791;
|
||||
RBX::Lua::LuaStubGen<395> stub395;
|
||||
RBX::Lua::LuaStubGen<20> stub20;
|
||||
RBX::Lua::LuaStubGen<916> stub916;
|
||||
RBX::Lua::LuaStubGen<229> stub229;
|
||||
RBX::Lua::LuaStubGen<215> stub215;
|
||||
RBX::Lua::LuaStubGen<589> stub589;
|
||||
RBX::Lua::LuaStubGen<23> stub23;
|
||||
RBX::Lua::LuaStubGen<750> stub750;
|
||||
RBX::Lua::LuaStubGen<483> stub483;
|
||||
RBX::Lua::LuaStubGen<724> stub724;
|
||||
RBX::Lua::LuaStubGen<505> stub505;
|
||||
RBX::Lua::LuaStubGen<254> stub254;
|
||||
RBX::Lua::LuaStubGen<752> stub752;
|
||||
RBX::Lua::LuaStubGen<926> stub926;
|
||||
RBX::Lua::LuaStubGen<524> stub524;
|
||||
RBX::Lua::LuaStubGen<672> stub672;
|
||||
RBX::Lua::LuaStubGen<406> stub406;
|
||||
RBX::Lua::LuaStubGen<924> stub924;
|
||||
RBX::Lua::LuaStubGen<394> stub394;
|
||||
RBX::Lua::LuaStubGen<506> stub506;
|
||||
RBX::Lua::LuaStubGen<772> stub772;
|
||||
RBX::Lua::LuaStubGen<603> stub603;
|
||||
RBX::Lua::LuaStubGen<175> stub175;
|
||||
RBX::Lua::LuaStubGen<256> stub256;
|
||||
RBX::Lua::LuaStubGen<392> stub392;
|
||||
RBX::Lua::LuaStubGen<605> stub605;
|
||||
RBX::Lua::LuaStubGen<534> stub534;
|
||||
RBX::Lua::LuaStubGen<443> stub443;
|
||||
RBX::Lua::LuaStubGen<365> stub365;
|
||||
RBX::Lua::LuaStubGen<126> stub126;
|
||||
RBX::Lua::LuaStubGen<709> stub709;
|
||||
RBX::Lua::LuaStubGen<42> stub42;
|
||||
RBX::Lua::LuaStubGen<10> stub10;
|
||||
RBX::Lua::LuaStubGen<292> stub292;
|
||||
RBX::Lua::LuaStubGen<669> stub669;
|
||||
RBX::Lua::LuaStubGen<282> stub282;
|
||||
RBX::Lua::LuaStubGen<201> stub201;
|
||||
RBX::Lua::LuaStubGen<585> stub585;
|
||||
RBX::Lua::LuaStubGen<693> stub693;
|
||||
RBX::Lua::LuaStubGen<241> stub241;
|
||||
RBX::Lua::LuaStubGen<131> stub131;
|
||||
RBX::Lua::LuaStubGen<70> stub70;
|
||||
RBX::Lua::LuaStubGen<360> stub360;
|
||||
RBX::Lua::LuaStubGen<537> stub537;
|
||||
RBX::Lua::LuaStubGen<408> stub408;
|
||||
RBX::Lua::LuaStubGen<515> stub515;
|
||||
RBX::Lua::LuaStubGen<9> stub9;
|
||||
RBX::Lua::LuaStubGen<111> stub111;
|
||||
RBX::Lua::LuaStubGen<388> stub388;
|
||||
RBX::Lua::LuaStubGen<937> stub937;
|
||||
RBX::Lua::LuaStubGen<276> stub276;
|
||||
RBX::Lua::LuaStubGen<426> stub426;
|
||||
RBX::Lua::LuaStubGen<832> stub832;
|
||||
RBX::Lua::LuaStubGen<90> stub90;
|
||||
RBX::Lua::LuaStubGen<414> stub414;
|
||||
RBX::Lua::LuaStubGen<151> stub151;
|
||||
RBX::Lua::LuaStubGen<178> stub178;
|
||||
RBX::Lua::LuaStubGen<625> stub625;
|
||||
RBX::Lua::LuaStubGen<478> stub478;
|
||||
RBX::Lua::LuaStubGen<941> stub941;
|
||||
RBX::Lua::LuaStubGen<71> stub71;
|
||||
RBX::Lua::LuaStubGen<556> stub556;
|
||||
RBX::Lua::LuaStubGen<421> stub421;
|
||||
RBX::Lua::LuaStubGen<683> stub683;
|
||||
RBX::Lua::LuaStubGen<422> stub422;
|
||||
RBX::Lua::LuaStubGen<193> stub193;
|
||||
RBX::Lua::LuaStubGen<626> stub626;
|
||||
RBX::Lua::LuaStubGen<738> stub738;
|
||||
RBX::Lua::LuaStubGen<728> stub728;
|
||||
RBX::Lua::LuaStubGen<438> stub438;
|
||||
RBX::Lua::LuaStubGen<606> stub606;
|
||||
RBX::Lua::LuaStubGen<969> stub969;
|
||||
RBX::Lua::LuaStubGen<602> stub602;
|
||||
RBX::Lua::LuaStubGen<857> stub857;
|
||||
RBX::Lua::LuaStubGen<572> stub572;
|
||||
RBX::Lua::LuaStubGen<129> stub129;
|
||||
RBX::Lua::LuaStubGen<578> stub578;
|
||||
RBX::Lua::LuaStubGen<544> stub544;
|
||||
RBX::Lua::LuaStubGen<358> stub358;
|
||||
RBX::Lua::LuaStubGen<651> stub651;
|
||||
RBX::Lua::LuaStubGen<482> stub482;
|
||||
RBX::Lua::LuaStubGen<729> stub729;
|
||||
RBX::Lua::LuaStubGen<582> stub582;
|
||||
RBX::Lua::LuaStubGen<975> stub975;
|
||||
RBX::Lua::LuaStubGen<238> stub238;
|
||||
RBX::Lua::LuaStubGen<167> stub167;
|
||||
RBX::Lua::LuaStubGen<632> stub632;
|
||||
RBX::Lua::LuaStubGen<770> stub770;
|
||||
RBX::Lua::LuaStubGen<176> stub176;
|
||||
RBX::Lua::LuaStubGen<805> stub805;
|
||||
RBX::Lua::LuaStubGen<473> stub473;
|
||||
RBX::Lua::LuaStubGen<145> stub145;
|
||||
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include "lua/lua.hpp"
|
||||
|
||||
RBX::Lua::LuaStubGen<641> stub641;
|
||||
RBX::Lua::LuaStubGen<200> stub200;
|
||||
RBX::Lua::LuaStubGen<428> stub428;
|
||||
RBX::Lua::LuaStubGen<596> stub596;
|
||||
RBX::Lua::LuaStubGen<909> stub909;
|
||||
RBX::Lua::LuaStubGen<540> stub540;
|
||||
RBX::Lua::LuaStubGen<108> stub108;
|
||||
RBX::Lua::LuaStubGen<328> stub328;
|
||||
RBX::Lua::LuaStubGen<852> stub852;
|
||||
RBX::Lua::LuaStubGen<81> stub81;
|
||||
RBX::Lua::LuaStubGen<761> stub761;
|
||||
RBX::Lua::LuaStubGen<159> stub159;
|
||||
RBX::Lua::LuaStubGen<46> stub46;
|
||||
RBX::Lua::LuaStubGen<272> stub272;
|
||||
RBX::Lua::LuaStubGen<404> stub404;
|
||||
RBX::Lua::LuaStubGen<386> stub386;
|
||||
RBX::Lua::LuaStubGen<719> stub719;
|
||||
RBX::Lua::LuaStubGen<191> stub191;
|
||||
RBX::Lua::LuaStubGen<33> stub33;
|
||||
RBX::Lua::LuaStubGen<851> stub851;
|
||||
RBX::Lua::LuaStubGen<561> stub561;
|
||||
RBX::Lua::LuaStubGen<681> stub681;
|
||||
RBX::Lua::LuaStubGen<721> stub721;
|
||||
RBX::Lua::LuaStubGen<87> stub87;
|
||||
RBX::Lua::LuaStubGen<996> stub996;
|
||||
RBX::Lua::LuaStubGen<576> stub576;
|
||||
RBX::Lua::LuaStubGen<835> stub835;
|
||||
RBX::Lua::LuaStubGen<305> stub305;
|
||||
RBX::Lua::LuaStubGen<182> stub182;
|
||||
RBX::Lua::LuaStubGen<974> stub974;
|
||||
RBX::Lua::LuaStubGen<294> stub294;
|
||||
RBX::Lua::LuaStubGen<922> stub922;
|
||||
RBX::Lua::LuaStubGen<890> stub890;
|
||||
RBX::Lua::LuaStubGen<185> stub185;
|
||||
RBX::Lua::LuaStubGen<253> stub253;
|
||||
RBX::Lua::LuaStubGen<298> stub298;
|
||||
RBX::Lua::LuaStubGen<744> stub744;
|
||||
RBX::Lua::LuaStubGen<861> stub861;
|
||||
RBX::Lua::LuaStubGen<885> stub885;
|
||||
RBX::Lua::LuaStubGen<351> stub351;
|
||||
RBX::Lua::LuaStubGen<63> stub63;
|
||||
RBX::Lua::LuaStubGen<327> stub327;
|
||||
RBX::Lua::LuaStubGen<599> stub599;
|
||||
RBX::Lua::LuaStubGen<720> stub720;
|
||||
RBX::Lua::LuaStubGen<911> stub911;
|
||||
RBX::Lua::LuaStubGen<676> stub676;
|
||||
RBX::Lua::LuaStubGen<993> stub993;
|
||||
RBX::Lua::LuaStubGen<326> stub326;
|
||||
RBX::Lua::LuaStubGen<489> stub489;
|
||||
RBX::Lua::LuaStubGen<4> stub4;
|
||||
RBX::Lua::LuaStubGen<830> stub830;
|
||||
RBX::Lua::LuaStubGen<398> stub398;
|
||||
RBX::Lua::LuaStubGen<509> stub509;
|
||||
RBX::Lua::LuaStubGen<372> stub372;
|
||||
RBX::Lua::LuaStubGen<102> stub102;
|
||||
RBX::Lua::LuaStubGen<296> stub296;
|
||||
RBX::Lua::LuaStubGen<86> stub86;
|
||||
RBX::Lua::LuaStubGen<258> stub258;
|
||||
RBX::Lua::LuaStubGen<981> stub981;
|
||||
RBX::Lua::LuaStubGen<971> stub971;
|
||||
RBX::Lua::LuaStubGen<65> stub65;
|
||||
RBX::Lua::LuaStubGen<467> stub467;
|
||||
RBX::Lua::LuaStubGen<566> stub566;
|
||||
RBX::Lua::LuaStubGen<118> stub118;
|
||||
RBX::Lua::LuaStubGen<565> stub565;
|
||||
RBX::Lua::LuaStubGen<717> stub717;
|
||||
RBX::Lua::LuaStubGen<741> stub741;
|
||||
RBX::Lua::LuaStubGen<66> stub66;
|
||||
RBX::Lua::LuaStubGen<348> stub348;
|
||||
RBX::Lua::LuaStubGen<557> stub557;
|
||||
RBX::Lua::LuaStubGen<202> stub202;
|
||||
RBX::Lua::LuaStubGen<674> stub674;
|
||||
RBX::Lua::LuaStubGen<480> stub480;
|
||||
RBX::Lua::LuaStubGen<794> stub794;
|
||||
RBX::Lua::LuaStubGen<234> stub234;
|
||||
RBX::Lua::LuaStubGen<353> stub353;
|
||||
RBX::Lua::LuaStubGen<757> stub757;
|
||||
RBX::Lua::LuaStubGen<844> stub844;
|
||||
RBX::Lua::LuaStubGen<900> stub900;
|
||||
RBX::Lua::LuaStubGen<587> stub587;
|
||||
RBX::Lua::LuaStubGen<773> stub773;
|
||||
RBX::Lua::LuaStubGen<84> stub84;
|
||||
RBX::Lua::LuaStubGen<284> stub284;
|
||||
RBX::Lua::LuaStubGen<300> stub300;
|
||||
RBX::Lua::LuaStubGen<456> stub456;
|
||||
RBX::Lua::LuaStubGen<461> stub461;
|
||||
RBX::Lua::LuaStubGen<109> stub109;
|
||||
RBX::Lua::LuaStubGen<349> stub349;
|
||||
RBX::Lua::LuaStubGen<337> stub337;
|
||||
RBX::Lua::LuaStubGen<154> stub154;
|
||||
RBX::Lua::LuaStubGen<293> stub293;
|
||||
RBX::Lua::LuaStubGen<706> stub706;
|
||||
RBX::Lua::LuaStubGen<764> stub764;
|
||||
RBX::Lua::LuaStubGen<930> stub930;
|
||||
RBX::Lua::LuaStubGen<465> stub465;
|
||||
RBX::Lua::LuaStubGen<245> stub245;
|
||||
RBX::Lua::LuaStubGen<55> stub55;
|
||||
RBX::Lua::LuaStubGen<960> stub960;
|
||||
RBX::Lua::LuaStubGen<756> stub756;
|
||||
RBX::Lua::LuaStubGen<521> stub521;
|
||||
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include "lua/lua.hpp"
|
||||
|
||||
RBX::Lua::LuaStubGen<144> stub144;
|
||||
RBX::Lua::LuaStubGen<44> stub44;
|
||||
RBX::Lua::LuaStubGen<667> stub667;
|
||||
RBX::Lua::LuaStubGen<896> stub896;
|
||||
RBX::Lua::LuaStubGen<318> stub318;
|
||||
RBX::Lua::LuaStubGen<731> stub731;
|
||||
RBX::Lua::LuaStubGen<98> stub98;
|
||||
RBX::Lua::LuaStubGen<306> stub306;
|
||||
RBX::Lua::LuaStubGen<434> stub434;
|
||||
RBX::Lua::LuaStubGen<374> stub374;
|
||||
RBX::Lua::LuaStubGen<92> stub92;
|
||||
RBX::Lua::LuaStubGen<309> stub309;
|
||||
RBX::Lua::LuaStubGen<94> stub94;
|
||||
RBX::Lua::LuaStubGen<239> stub239;
|
||||
RBX::Lua::LuaStubGen<464> stub464;
|
||||
RBX::Lua::LuaStubGen<243> stub243;
|
||||
RBX::Lua::LuaStubGen<963> stub963;
|
||||
RBX::Lua::LuaStubGen<514> stub514;
|
||||
RBX::Lua::LuaStubGen<639> stub639;
|
||||
RBX::Lua::LuaStubGen<816> stub816;
|
||||
RBX::Lua::LuaStubGen<164> stub164;
|
||||
RBX::Lua::LuaStubGen<653> stub653;
|
||||
RBX::Lua::LuaStubGen<812> stub812;
|
||||
RBX::Lua::LuaStubGen<269> stub269;
|
||||
RBX::Lua::LuaStubGen<822> stub822;
|
||||
RBX::Lua::LuaStubGen<864> stub864;
|
||||
RBX::Lua::LuaStubGen<499> stub499;
|
||||
RBX::Lua::LuaStubGen<130> stub130;
|
||||
RBX::Lua::LuaStubGen<59> stub59;
|
||||
RBX::Lua::LuaStubGen<27> stub27;
|
||||
RBX::Lua::LuaStubGen<162> stub162;
|
||||
RBX::Lua::LuaStubGen<570> stub570;
|
||||
RBX::Lua::LuaStubGen<74> stub74;
|
||||
RBX::Lua::LuaStubGen<117> stub117;
|
||||
RBX::Lua::LuaStubGen<935> stub935;
|
||||
RBX::Lua::LuaStubGen<96> stub96;
|
||||
RBX::Lua::LuaStubGen<629> stub629;
|
||||
RBX::Lua::LuaStubGen<163> stub163;
|
||||
RBX::Lua::LuaStubGen<934> stub934;
|
||||
RBX::Lua::LuaStubGen<275> stub275;
|
||||
RBX::Lua::LuaStubGen<165> stub165;
|
||||
RBX::Lua::LuaStubGen<267> stub267;
|
||||
RBX::Lua::LuaStubGen<195> stub195;
|
||||
RBX::Lua::LuaStubGen<833> stub833;
|
||||
RBX::Lua::LuaStubGen<30> stub30;
|
||||
RBX::Lua::LuaStubGen<304> stub304;
|
||||
RBX::Lua::LuaStubGen<114> stub114;
|
||||
RBX::Lua::LuaStubGen<369> stub369;
|
||||
RBX::Lua::LuaStubGen<708> stub708;
|
||||
RBX::Lua::LuaStubGen<611> stub611;
|
||||
RBX::Lua::LuaStubGen<441> stub441;
|
||||
RBX::Lua::LuaStubGen<512> stub512;
|
||||
RBX::Lua::LuaStubGen<143> stub143;
|
||||
RBX::Lua::LuaStubGen<615> stub615;
|
||||
RBX::Lua::LuaStubGen<792> stub792;
|
||||
RBX::Lua::LuaStubGen<76> stub76;
|
||||
RBX::Lua::LuaStubGen<853> stub853;
|
||||
RBX::Lua::LuaStubGen<500> stub500;
|
||||
RBX::Lua::LuaStubGen<710> stub710;
|
||||
RBX::Lua::LuaStubGen<782> stub782;
|
||||
RBX::Lua::LuaStubGen<869> stub869;
|
||||
RBX::Lua::LuaStubGen<690> stub690;
|
||||
RBX::Lua::LuaStubGen<184> stub184;
|
||||
RBX::Lua::LuaStubGen<424> stub424;
|
||||
RBX::Lua::LuaStubGen<204> stub204;
|
||||
RBX::Lua::LuaStubGen<2> stub2;
|
||||
RBX::Lua::LuaStubGen<354> stub354;
|
||||
RBX::Lua::LuaStubGen<400> stub400;
|
||||
RBX::Lua::LuaStubGen<216> stub216;
|
||||
RBX::Lua::LuaStubGen<152> stub152;
|
||||
RBX::Lua::LuaStubGen<18> stub18;
|
||||
RBX::Lua::LuaStubGen<190> stub190;
|
||||
RBX::Lua::LuaStubGen<380> stub380;
|
||||
RBX::Lua::LuaStubGen<246> stub246;
|
||||
RBX::Lua::LuaStubGen<628> stub628;
|
||||
RBX::Lua::LuaStubGen<26> stub26;
|
||||
RBX::Lua::LuaStubGen<645> stub645;
|
||||
RBX::Lua::LuaStubGen<945> stub945;
|
||||
RBX::Lua::LuaStubGen<347> stub347;
|
||||
RBX::Lua::LuaStubGen<829> stub829;
|
||||
RBX::Lua::LuaStubGen<858> stub858;
|
||||
RBX::Lua::LuaStubGen<802> stub802;
|
||||
RBX::Lua::LuaStubGen<965> stub965;
|
||||
RBX::Lua::LuaStubGen<262> stub262;
|
||||
RBX::Lua::LuaStubGen<268> stub268;
|
||||
RBX::Lua::LuaStubGen<806> stub806;
|
||||
RBX::Lua::LuaStubGen<944> stub944;
|
||||
RBX::Lua::LuaStubGen<225> stub225;
|
||||
RBX::Lua::LuaStubGen<188> stub188;
|
||||
RBX::Lua::LuaStubGen<266> stub266;
|
||||
RBX::Lua::LuaStubGen<417> stub417;
|
||||
RBX::Lua::LuaStubGen<377> stub377;
|
||||
RBX::Lua::LuaStubGen<425> stub425;
|
||||
RBX::Lua::LuaStubGen<286> stub286;
|
||||
RBX::Lua::LuaStubGen<986> stub986;
|
||||
RBX::Lua::LuaStubGen<843> stub843;
|
||||
RBX::Lua::LuaStubGen<827> stub827;
|
||||
RBX::Lua::LuaStubGen<807> stub807;
|
||||
RBX::Lua::LuaStubGen<730> stub730;
|
||||
RBX::Lua::LuaStubGen<440> stub440;
|
||||
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include "lua/lua.hpp"
|
||||
|
||||
RBX::Lua::LuaStubGen<525> stub525;
|
||||
RBX::Lua::LuaStubGen<980> stub980;
|
||||
RBX::Lua::LuaStubGen<496> stub496;
|
||||
RBX::Lua::LuaStubGen<194> stub194;
|
||||
RBX::Lua::LuaStubGen<608> stub608;
|
||||
RBX::Lua::LuaStubGen<884> stub884;
|
||||
RBX::Lua::LuaStubGen<265> stub265;
|
||||
RBX::Lua::LuaStubGen<62> stub62;
|
||||
RBX::Lua::LuaStubGen<336> stub336;
|
||||
RBX::Lua::LuaStubGen<538> stub538;
|
||||
RBX::Lua::LuaStubGen<295> stub295;
|
||||
RBX::Lua::LuaStubGen<991> stub991;
|
||||
RBX::Lua::LuaStubGen<795> stub795;
|
||||
RBX::Lua::LuaStubGen<976> stub976;
|
||||
RBX::Lua::LuaStubGen<498> stub498;
|
||||
RBX::Lua::LuaStubGen<103> stub103;
|
||||
RBX::Lua::LuaStubGen<723> stub723;
|
||||
RBX::Lua::LuaStubGen<222> stub222;
|
||||
RBX::Lua::LuaStubGen<886> stub886;
|
||||
RBX::Lua::LuaStubGen<285> stub285;
|
||||
RBX::Lua::LuaStubGen<927> stub927;
|
||||
RBX::Lua::LuaStubGen<765> stub765;
|
||||
RBX::Lua::LuaStubGen<147> stub147;
|
||||
RBX::Lua::LuaStubGen<867> stub867;
|
||||
RBX::Lua::LuaStubGen<597> stub597;
|
||||
RBX::Lua::LuaStubGen<136> stub136;
|
||||
RBX::Lua::LuaStubGen<895> stub895;
|
||||
RBX::Lua::LuaStubGen<837> stub837;
|
||||
RBX::Lua::LuaStubGen<631> stub631;
|
||||
RBX::Lua::LuaStubGen<825> stub825;
|
||||
RBX::Lua::LuaStubGen<575> stub575;
|
||||
RBX::Lua::LuaStubGen<329> stub329;
|
||||
RBX::Lua::LuaStubGen<435> stub435;
|
||||
RBX::Lua::LuaStubGen<769> stub769;
|
||||
RBX::Lua::LuaStubGen<494> stub494;
|
||||
RBX::Lua::LuaStubGen<45> stub45;
|
||||
RBX::Lua::LuaStubGen<31> stub31;
|
||||
RBX::Lua::LuaStubGen<179> stub179;
|
||||
RBX::Lua::LuaStubGen<255> stub255;
|
||||
RBX::Lua::LuaStubGen<943> stub943;
|
||||
RBX::Lua::LuaStubGen<810> stub810;
|
||||
RBX::Lua::LuaStubGen<617> stub617;
|
||||
RBX::Lua::LuaStubGen<988> stub988;
|
||||
RBX::Lua::LuaStubGen<446> stub446;
|
||||
RBX::Lua::LuaStubGen<213> stub213;
|
||||
RBX::Lua::LuaStubGen<567> stub567;
|
||||
RBX::Lua::LuaStubGen<714> stub714;
|
||||
RBX::Lua::LuaStubGen<379> stub379;
|
||||
RBX::Lua::LuaStubGen<301> stub301;
|
||||
RBX::Lua::LuaStubGen<350> stub350;
|
||||
RBX::Lua::LuaStubGen<691> stub691;
|
||||
RBX::Lua::LuaStubGen<551> stub551;
|
||||
RBX::Lua::LuaStubGen<24> stub24;
|
||||
RBX::Lua::LuaStubGen<948> stub948;
|
||||
RBX::Lua::LuaStubGen<931> stub931;
|
||||
RBX::Lua::LuaStubGen<704> stub704;
|
||||
RBX::Lua::LuaStubGen<343> stub343;
|
||||
RBX::Lua::LuaStubGen<133> stub133;
|
||||
RBX::Lua::LuaStubGen<923> stub923;
|
||||
RBX::Lua::LuaStubGen<968> stub968;
|
||||
RBX::Lua::LuaStubGen<735> stub735;
|
||||
RBX::Lua::LuaStubGen<436> stub436;
|
||||
RBX::Lua::LuaStubGen<218> stub218;
|
||||
RBX::Lua::LuaStubGen<957> stub957;
|
||||
RBX::Lua::LuaStubGen<364> stub364;
|
||||
RBX::Lua::LuaStubGen<601> stub601;
|
||||
RBX::Lua::LuaStubGen<982> stub982;
|
||||
RBX::Lua::LuaStubGen<409> stub409;
|
||||
RBX::Lua::LuaStubGen<899> stub899;
|
||||
RBX::Lua::LuaStubGen<953> stub953;
|
||||
RBX::Lua::LuaStubGen<637> stub637;
|
||||
RBX::Lua::LuaStubGen<16> stub16;
|
||||
RBX::Lua::LuaStubGen<402> stub402;
|
||||
RBX::Lua::LuaStubGen<780> stub780;
|
||||
RBX::Lua::LuaStubGen<689> stub689;
|
||||
RBX::Lua::LuaStubGen<373> stub373;
|
||||
RBX::Lua::LuaStubGen<273> stub273;
|
||||
RBX::Lua::LuaStubGen<636> stub636;
|
||||
RBX::Lua::LuaStubGen<210> stub210;
|
||||
RBX::Lua::LuaStubGen<548> stub548;
|
||||
RBX::Lua::LuaStubGen<804> stub804;
|
||||
RBX::Lua::LuaStubGen<1> stub1;
|
||||
RBX::Lua::LuaStubGen<663> stub663;
|
||||
RBX::Lua::LuaStubGen<785> stub785;
|
||||
RBX::Lua::LuaStubGen<811> stub811;
|
||||
RBX::Lua::LuaStubGen<344> stub344;
|
||||
RBX::Lua::LuaStubGen<664> stub664;
|
||||
RBX::Lua::LuaStubGen<831> stub831;
|
||||
RBX::Lua::LuaStubGen<783> stub783;
|
||||
RBX::Lua::LuaStubGen<978> stub978;
|
||||
RBX::Lua::LuaStubGen<841> stub841;
|
||||
RBX::Lua::LuaStubGen<22> stub22;
|
||||
RBX::Lua::LuaStubGen<520> stub520;
|
||||
RBX::Lua::LuaStubGen<6> stub6;
|
||||
RBX::Lua::LuaStubGen<659> stub659;
|
||||
RBX::Lua::LuaStubGen<230> stub230;
|
||||
RBX::Lua::LuaStubGen<72> stub72;
|
||||
RBX::Lua::LuaStubGen<57> stub57;
|
||||
RBX::Lua::LuaStubGen<333> stub333;
|
||||
RBX::Lua::LuaStubGen<80> stub80;
|
||||
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include "lua/lua.hpp"
|
||||
|
||||
RBX::Lua::LuaStubGen<355> stub355;
|
||||
RBX::Lua::LuaStubGen<411> stub411;
|
||||
RBX::Lua::LuaStubGen<531> stub531;
|
||||
RBX::Lua::LuaStubGen<281> stub281;
|
||||
RBX::Lua::LuaStubGen<67> stub67;
|
||||
RBX::Lua::LuaStubGen<297> stub297;
|
||||
RBX::Lua::LuaStubGen<415> stub415;
|
||||
RBX::Lua::LuaStubGen<954> stub954;
|
||||
RBX::Lua::LuaStubGen<410> stub410;
|
||||
RBX::Lua::LuaStubGen<798> stub798;
|
||||
RBX::Lua::LuaStubGen<519> stub519;
|
||||
RBX::Lua::LuaStubGen<493> stub493;
|
||||
RBX::Lua::LuaStubGen<299> stub299;
|
||||
RBX::Lua::LuaStubGen<656> stub656;
|
||||
RBX::Lua::LuaStubGen<808> stub808;
|
||||
RBX::Lua::LuaStubGen<906> stub906;
|
||||
RBX::Lua::LuaStubGen<778> stub778;
|
||||
RBX::Lua::LuaStubGen<445> stub445;
|
||||
RBX::Lua::LuaStubGen<468> stub468;
|
||||
RBX::Lua::LuaStubGen<363> stub363;
|
||||
RBX::Lua::LuaStubGen<902> stub902;
|
||||
RBX::Lua::LuaStubGen<740> stub740;
|
||||
RBX::Lua::LuaStubGen<32> stub32;
|
||||
RBX::Lua::LuaStubGen<278> stub278;
|
||||
RBX::Lua::LuaStubGen<767> stub767;
|
||||
RBX::Lua::LuaStubGen<594> stub594;
|
||||
RBX::Lua::LuaStubGen<335> stub335;
|
||||
RBX::Lua::LuaStubGen<356> stub356;
|
||||
RBX::Lua::LuaStubGen<376> stub376;
|
||||
RBX::Lua::LuaStubGen<955> stub955;
|
||||
RBX::Lua::LuaStubGen<315> stub315;
|
||||
RBX::Lua::LuaStubGen<915> stub915;
|
||||
RBX::Lua::LuaStubGen<788> stub788;
|
||||
RBX::Lua::LuaStubGen<940> stub940;
|
||||
RBX::Lua::LuaStubGen<405> stub405;
|
||||
RBX::Lua::LuaStubGen<442> stub442;
|
||||
RBX::Lua::LuaStubGen<250> stub250;
|
||||
RBX::Lua::LuaStubGen<476> stub476;
|
||||
RBX::Lua::LuaStubGen<120> stub120;
|
||||
RBX::Lua::LuaStubGen<528> stub528;
|
||||
RBX::Lua::LuaStubGen<142> stub142;
|
||||
RBX::Lua::LuaStubGen<186> stub186;
|
||||
RBX::Lua::LuaStubGen<754> stub754;
|
||||
RBX::Lua::LuaStubGen<989> stub989;
|
||||
RBX::Lua::LuaStubGen<25> stub25;
|
||||
RBX::Lua::LuaStubGen<223> stub223;
|
||||
RBX::Lua::LuaStubGen<848> stub848;
|
||||
RBX::Lua::LuaStubGen<815> stub815;
|
||||
RBX::Lua::LuaStubGen<658> stub658;
|
||||
RBX::Lua::LuaStubGen<905> stub905;
|
||||
RBX::Lua::LuaStubGen<37> stub37;
|
||||
RBX::Lua::LuaStubGen<338> stub338;
|
||||
RBX::Lua::LuaStubGen<53> stub53;
|
||||
RBX::Lua::LuaStubGen<682> stub682;
|
||||
RBX::Lua::LuaStubGen<904> stub904;
|
||||
RBX::Lua::LuaStubGen<862> stub862;
|
||||
RBX::Lua::LuaStubGen<533> stub533;
|
||||
RBX::Lua::LuaStubGen<694> stub694;
|
||||
RBX::Lua::LuaStubGen<558> stub558;
|
||||
RBX::Lua::LuaStubGen<100> stub100;
|
||||
RBX::Lua::LuaStubGen<518> stub518;
|
||||
RBX::Lua::LuaStubGen<125> stub125;
|
||||
RBX::Lua::LuaStubGen<845> stub845;
|
||||
RBX::Lua::LuaStubGen<503> stub503;
|
||||
RBX::Lua::LuaStubGen<340> stub340;
|
||||
RBX::Lua::LuaStubGen<399> stub399;
|
||||
RBX::Lua::LuaStubGen<89> stub89;
|
||||
RBX::Lua::LuaStubGen<146> stub146;
|
||||
RBX::Lua::LuaStubGen<917> stub917;
|
||||
RBX::Lua::LuaStubGen<877> stub877;
|
||||
RBX::Lua::LuaStubGen<696> stub696;
|
||||
RBX::Lua::LuaStubGen<279> stub279;
|
||||
RBX::Lua::LuaStubGen<368> stub368;
|
||||
RBX::Lua::LuaStubGen<936> stub936;
|
||||
RBX::Lua::LuaStubGen<378> stub378;
|
||||
RBX::Lua::LuaStubGen<958> stub958;
|
||||
RBX::Lua::LuaStubGen<962> stub962;
|
||||
RBX::Lua::LuaStubGen<38> stub38;
|
||||
RBX::Lua::LuaStubGen<444> stub444;
|
||||
RBX::Lua::LuaStubGen<257> stub257;
|
||||
RBX::Lua::LuaStubGen<607> stub607;
|
||||
RBX::Lua::LuaStubGen<427> stub427;
|
||||
RBX::Lua::LuaStubGen<149> stub149;
|
||||
RBX::Lua::LuaStubGen<855> stub855;
|
||||
RBX::Lua::LuaStubGen<135> stub135;
|
||||
RBX::Lua::LuaStubGen<127> stub127;
|
||||
RBX::Lua::LuaStubGen<430> stub430;
|
||||
RBX::Lua::LuaStubGen<511> stub511;
|
||||
RBX::Lua::LuaStubGen<748> stub748;
|
||||
RBX::Lua::LuaStubGen<952> stub952;
|
||||
RBX::Lua::LuaStubGen<104> stub104;
|
||||
RBX::Lua::LuaStubGen<650> stub650;
|
||||
RBX::Lua::LuaStubGen<771> stub771;
|
||||
RBX::Lua::LuaStubGen<680> stub680;
|
||||
RBX::Lua::LuaStubGen<876> stub876;
|
||||
RBX::Lua::LuaStubGen<849> stub849;
|
||||
RBX::Lua::LuaStubGen<251> stub251;
|
||||
RBX::Lua::LuaStubGen<635> stub635;
|
||||
RBX::Lua::LuaStubGen<77> stub77;
|
||||
RBX::Lua::LuaStubGen<141> stub141;
|
||||
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include "lua/lua.hpp"
|
||||
|
||||
RBX::Lua::LuaStubGen<137> stub137;
|
||||
RBX::Lua::LuaStubGen<966> stub966;
|
||||
RBX::Lua::LuaStubGen<894> stub894;
|
||||
RBX::Lua::LuaStubGen<95> stub95;
|
||||
RBX::Lua::LuaStubGen<586> stub586;
|
||||
RBX::Lua::LuaStubGen<715> stub715;
|
||||
RBX::Lua::LuaStubGen<657> stub657;
|
||||
RBX::Lua::LuaStubGen<244> stub244;
|
||||
RBX::Lua::LuaStubGen<826> stub826;
|
||||
RBX::Lua::LuaStubGen<303> stub303;
|
||||
RBX::Lua::LuaStubGen<964> stub964;
|
||||
RBX::Lua::LuaStubGen<732> stub732;
|
||||
RBX::Lua::LuaStubGen<984> stub984;
|
||||
RBX::Lua::LuaStubGen<240> stub240;
|
||||
RBX::Lua::LuaStubGen<342> stub342;
|
||||
RBX::Lua::LuaStubGen<264> stub264;
|
||||
RBX::Lua::LuaStubGen<192> stub192;
|
||||
RBX::Lua::LuaStubGen<874> stub874;
|
||||
RBX::Lua::LuaStubGen<563> stub563;
|
||||
RBX::Lua::LuaStubGen<644> stub644;
|
||||
RBX::Lua::LuaStubGen<495> stub495;
|
||||
RBX::Lua::LuaStubGen<460> stub460;
|
||||
RBX::Lua::LuaStubGen<583> stub583;
|
||||
RBX::Lua::LuaStubGen<39> stub39;
|
||||
RBX::Lua::LuaStubGen<707> stub707;
|
||||
RBX::Lua::LuaStubGen<334> stub334;
|
||||
RBX::Lua::LuaStubGen<8> stub8;
|
||||
RBX::Lua::LuaStubGen<132> stub132;
|
||||
RBX::Lua::LuaStubGen<474> stub474;
|
||||
RBX::Lua::LuaStubGen<407> stub407;
|
||||
RBX::Lua::LuaStubGen<75> stub75;
|
||||
RBX::Lua::LuaStubGen<542> stub542;
|
||||
RBX::Lua::LuaStubGen<789> stub789;
|
||||
RBX::Lua::LuaStubGen<36> stub36;
|
||||
RBX::Lua::LuaStubGen<174> stub174;
|
||||
RBX::Lua::LuaStubGen<252> stub252;
|
||||
RBX::Lua::LuaStubGen<28> stub28;
|
||||
RBX::Lua::LuaStubGen<618> stub618;
|
||||
RBX::Lua::LuaStubGen<205> stub205;
|
||||
RBX::Lua::LuaStubGen<838> stub838;
|
||||
RBX::Lua::LuaStubGen<260> stub260;
|
||||
RBX::Lua::LuaStubGen<116> stub116;
|
||||
RBX::Lua::LuaStubGen<888> stub888;
|
||||
RBX::Lua::LuaStubGen<91> stub91;
|
||||
RBX::Lua::LuaStubGen<153> stub153;
|
||||
RBX::Lua::LuaStubGen<180> stub180;
|
||||
RBX::Lua::LuaStubGen<247> stub247;
|
||||
RBX::Lua::LuaStubGen<850> stub850;
|
||||
RBX::Lua::LuaStubGen<660> stub660;
|
||||
RBX::Lua::LuaStubGen<280> stub280;
|
||||
RBX::Lua::LuaStubGen<942> stub942;
|
||||
RBX::Lua::LuaStubGen<665> stub665;
|
||||
RBX::Lua::LuaStubGen<726> stub726;
|
||||
RBX::Lua::LuaStubGen<332> stub332;
|
||||
RBX::Lua::LuaStubGen<820> stub820;
|
||||
RBX::Lua::LuaStubGen<592> stub592;
|
||||
RBX::Lua::LuaStubGen<793> stub793;
|
||||
RBX::Lua::LuaStubGen<759> stub759;
|
||||
RBX::Lua::LuaStubGen<898> stub898;
|
||||
RBX::Lua::LuaStubGen<746> stub746;
|
||||
RBX::Lua::LuaStubGen<817> stub817;
|
||||
RBX::Lua::LuaStubGen<457> stub457;
|
||||
RBX::Lua::LuaStubGen<449> stub449;
|
||||
RBX::Lua::LuaStubGen<950> stub950;
|
||||
RBX::Lua::LuaStubGen<291> stub291;
|
||||
RBX::Lua::LuaStubGen<140> stub140;
|
||||
RBX::Lua::LuaStubGen<389> stub389;
|
||||
RBX::Lua::LuaStubGen<913> stub913;
|
||||
RBX::Lua::LuaStubGen<549> stub549;
|
||||
RBX::Lua::LuaStubGen<310> stub310;
|
||||
RBX::Lua::LuaStubGen<990> stub990;
|
||||
RBX::Lua::LuaStubGen<259> stub259;
|
||||
RBX::Lua::LuaStubGen<50> stub50;
|
||||
RBX::Lua::LuaStubGen<688> stub688;
|
||||
RBX::Lua::LuaStubGen<52> stub52;
|
||||
RBX::Lua::LuaStubGen<755> stub755;
|
||||
RBX::Lua::LuaStubGen<437> stub437;
|
||||
RBX::Lua::LuaStubGen<48> stub48;
|
||||
RBX::Lua::LuaStubGen<662> stub662;
|
||||
RBX::Lua::LuaStubGen<189> stub189;
|
||||
RBX::Lua::LuaStubGen<123> stub123;
|
||||
RBX::Lua::LuaStubGen<679> stub679;
|
||||
RBX::Lua::LuaStubGen<0> stub0;
|
||||
RBX::Lua::LuaStubGen<283> stub283;
|
||||
RBX::Lua::LuaStubGen<359> stub359;
|
||||
RBX::Lua::LuaStubGen<946> stub946;
|
||||
RBX::Lua::LuaStubGen<670> stub670;
|
||||
RBX::Lua::LuaStubGen<271> stub271;
|
||||
RBX::Lua::LuaStubGen<847> stub847;
|
||||
RBX::Lua::LuaStubGen<416> stub416;
|
||||
RBX::Lua::LuaStubGen<903> stub903;
|
||||
RBX::Lua::LuaStubGen<595> stub595;
|
||||
RBX::Lua::LuaStubGen<970> stub970;
|
||||
RBX::Lua::LuaStubGen<138> stub138;
|
||||
RBX::Lua::LuaStubGen<54> stub54;
|
||||
RBX::Lua::LuaStubGen<590> stub590;
|
||||
RBX::Lua::LuaStubGen<921> stub921;
|
||||
RBX::Lua::LuaStubGen<21> stub21;
|
||||
RBX::Lua::LuaStubGen<171> stub171;
|
||||
RBX::Lua::LuaStubGen<673> stub673;
|
||||
@@ -0,0 +1,597 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "reflection/type.h"
|
||||
#include "security/securitycontext.h"
|
||||
#include "reflection/member.h"
|
||||
#include "reflection/Type.h"
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Reflection
|
||||
{
|
||||
class Callback;
|
||||
|
||||
// Base class that describes a Callback
|
||||
class RBXBaseClass CallbackDescriptor : public MemberDescriptor
|
||||
{
|
||||
public:
|
||||
typedef Callback ConstMember;
|
||||
typedef Callback Member;
|
||||
|
||||
protected:
|
||||
SignatureDescriptor signature;
|
||||
bool async;
|
||||
|
||||
CallbackDescriptor(ClassDescriptor& classDescriptor, const char* name, Descriptor::Attributes attributes, Security::Permissions security, bool async);
|
||||
public:
|
||||
inline const SignatureDescriptor& getSignature() const { return signature; }
|
||||
bool isAsync() const { return async; }
|
||||
};
|
||||
|
||||
class SyncCallbackDescriptor : public CallbackDescriptor
|
||||
{
|
||||
protected:
|
||||
SyncCallbackDescriptor(ClassDescriptor& classDescriptor, const char* name, Descriptor::Attributes attributes, Security::Permissions security);
|
||||
public:
|
||||
typedef boost::function<shared_ptr<Reflection::Tuple>(shared_ptr<const Reflection::Tuple> args)> GenericFunction;
|
||||
|
||||
// the preferred way to set a generic function:
|
||||
virtual void setGenericCallback(DescribedBase* object, shared_ptr<GenericFunction> function) const = 0;
|
||||
virtual void clearCallback(DescribedBase* object) const = 0;
|
||||
|
||||
// use this function if you don't have a shared_ptr:
|
||||
void setGenericCallbackHelper(DescribedBase* object, const GenericFunction& function) const;
|
||||
};
|
||||
|
||||
class AsyncCallbackDescriptor : public CallbackDescriptor
|
||||
{
|
||||
public:
|
||||
typedef boost::function<void(shared_ptr<const Reflection::Tuple>)> ResumeFunction;
|
||||
typedef boost::function<void(std::string)> ErrorFunction;
|
||||
typedef boost::function<void(shared_ptr<const Reflection::Tuple> args, ResumeFunction resumeFunction, ErrorFunction errorFunction)> GenericFunction;
|
||||
|
||||
// the preferred way to set a generic function:
|
||||
virtual void setGenericCallback(DescribedBase* object, shared_ptr<GenericFunction> function) const = 0;
|
||||
virtual void clearCallback(DescribedBase* object) const = 0;
|
||||
|
||||
// use this function if you don't have a shared_ptr:
|
||||
void setGenericCallbackHelper(DescribedBase* object, const GenericFunction& function) const;
|
||||
|
||||
protected:
|
||||
AsyncCallbackDescriptor(ClassDescriptor& classDescriptor, const char* name, Descriptor::Attributes attributes, Security::Permissions security);
|
||||
|
||||
static void callGenericImpl(shared_ptr<AsyncCallbackDescriptor::GenericFunction> function, shared_ptr<Tuple> args,
|
||||
AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction);
|
||||
|
||||
template <typename Class, typename Function, typename Value>
|
||||
void setGenericCallbackImpl(DescribedBase* object, Function Class::*member, void (Class::*onChanged)(const Function&), const Value& value) const
|
||||
{
|
||||
Class* c = static_cast<Class*>(object);
|
||||
|
||||
Function oldValue = c->*member;
|
||||
c->*member = value;
|
||||
if (onChanged)
|
||||
(c->*onChanged)(oldValue);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// A light-weight convenience class that associates a CallbackDescriptor
|
||||
// with a described object to create a "Callback"
|
||||
class Callback
|
||||
{
|
||||
const CallbackDescriptor* descriptor;
|
||||
DescribedBase* instance;
|
||||
public:
|
||||
inline Callback(const CallbackDescriptor& descriptor, DescribedBase* instance)
|
||||
:descriptor(&descriptor),instance(instance)
|
||||
{}
|
||||
|
||||
inline Callback(const Callback& other)
|
||||
:descriptor(other.descriptor),instance(other.instance)
|
||||
{}
|
||||
|
||||
inline Callback& operator =(const Callback& other)
|
||||
{
|
||||
this->descriptor = other.descriptor;
|
||||
this->instance = other.instance;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const RBX::Name& getName() const {
|
||||
return descriptor->name;
|
||||
}
|
||||
|
||||
inline DescribedBase* getInstance() const
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
inline const CallbackDescriptor& getDescriptor() const
|
||||
{
|
||||
return *descriptor;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Base class of typed CallbackDescriptors
|
||||
template<typename Signature>
|
||||
class SyncCallbackDesc : public SyncCallbackDescriptor
|
||||
{
|
||||
protected:
|
||||
typedef typename boost::function<Signature> Function;
|
||||
typedef typename boost::function_traits<Signature>::result_type result_type;
|
||||
|
||||
template<typename Result>
|
||||
static typename boost::enable_if<boost::is_void<Result>, void>::type
|
||||
callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function, shared_ptr<Tuple> args)
|
||||
{
|
||||
(*function)(args);
|
||||
}
|
||||
|
||||
template<typename Result>
|
||||
static typename boost::disable_if<boost::is_same<shared_ptr<const Tuple>, Result>, Result>::type
|
||||
convertResult(shared_ptr<Reflection::Tuple> result)
|
||||
{
|
||||
// Extract the first value in the Tuple and return it as the result. Ignore other vales
|
||||
if (result->values.size() == 0)
|
||||
throw std::runtime_error("Callback did not return a value");
|
||||
return result->values[0].convert<Result>();
|
||||
}
|
||||
|
||||
template<typename Result>
|
||||
static typename boost::enable_if<boost::is_same<shared_ptr<const Tuple>, Result>, Result>::type
|
||||
convertResult(shared_ptr<Reflection::Tuple> result)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename Result>
|
||||
static typename boost::disable_if<boost::is_void<Result>, Result>::type
|
||||
callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function, shared_ptr<Tuple> args)
|
||||
{
|
||||
shared_ptr<Reflection::Tuple> result = (*function)(args);
|
||||
return convertResult<Result>(result);
|
||||
}
|
||||
|
||||
class RBXInterface ISetter
|
||||
{
|
||||
public:
|
||||
virtual ~ISetter() {}
|
||||
virtual void setCallback(DescribedBase* object, const Function& value) const = 0;
|
||||
};
|
||||
boost::scoped_ptr<ISetter> setter;
|
||||
|
||||
SyncCallbackDesc(ClassDescriptor& classDescriptor, const char* name, Descriptor::Attributes attributes, Security::Permissions security):
|
||||
SyncCallbackDescriptor(classDescriptor, name, attributes, security)
|
||||
{}
|
||||
public:
|
||||
void setCallback(DescribedBase* object, const Function& value) const
|
||||
{
|
||||
setter->setCallback(object, value);
|
||||
}
|
||||
void clearCallback(DescribedBase* object) const
|
||||
{
|
||||
setter->setCallback(object, Function());
|
||||
}
|
||||
};
|
||||
|
||||
// Specialized class that implements generic bindings and sets the signature
|
||||
template <typename Signature, int arity>
|
||||
class SyncCallbackDescImpl;
|
||||
|
||||
template<typename Signature>
|
||||
class SyncCallbackDescImpl<Signature, 0> : public SyncCallbackDesc<Signature>
|
||||
{
|
||||
typedef typename SyncCallbackDesc<Signature>::result_type result_type;
|
||||
static result_type callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function)
|
||||
{
|
||||
shared_ptr<Reflection::Tuple> args(new Tuple());
|
||||
return SyncCallbackDesc<Signature>::template callGeneric<result_type>(function, args);
|
||||
}
|
||||
|
||||
protected:
|
||||
SyncCallbackDescImpl(ClassDescriptor& classDescriptor, const char* name, Descriptor::Attributes attributes, Security::Permissions security)
|
||||
:SyncCallbackDesc<Signature>(classDescriptor, name, attributes, security)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 0));
|
||||
this->signature.resultType = &Type::singleton<result_type>();
|
||||
}
|
||||
public:
|
||||
virtual void setGenericCallback(DescribedBase* object, shared_ptr<SyncCallbackDescriptor::GenericFunction> function) const
|
||||
{
|
||||
this->setCallback(object, boost::bind(callGeneric, function));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Signature>
|
||||
class SyncCallbackDescImpl<Signature, 1> : public SyncCallbackDesc<Signature>
|
||||
{
|
||||
typedef typename SyncCallbackDesc<Signature>::result_type result_type;
|
||||
static result_type callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function,
|
||||
// TODO: Use const ref for args and bind with boost::cref?
|
||||
typename boost::function_traits<Signature>::arg1_type arg1)
|
||||
{
|
||||
shared_ptr<Reflection::Tuple> args(new Tuple());
|
||||
args->values.push_back(arg1);
|
||||
return SyncCallbackDesc<Signature>::template callGeneric<result_type>(function, args);
|
||||
}
|
||||
|
||||
protected:
|
||||
SyncCallbackDescImpl(ClassDescriptor& classDescriptor, const char* name, const char* arg1name, Descriptor::Attributes attributes, Security::Permissions security)
|
||||
:SyncCallbackDesc<Signature>(classDescriptor, name, attributes, security)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 1));
|
||||
this->signature.resultType = &Type::singleton<result_type>();
|
||||
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
|
||||
}
|
||||
public:
|
||||
virtual void setGenericCallback(DescribedBase* object, shared_ptr<SyncCallbackDescriptor::GenericFunction> function) const
|
||||
{
|
||||
this->setCallback(object, boost::bind(callGeneric, function, _1));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Signature>
|
||||
class SyncCallbackDescImpl<Signature, 2> : public SyncCallbackDesc<Signature>
|
||||
{
|
||||
typedef typename SyncCallbackDesc<Signature>::result_type result_type;
|
||||
static result_type callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function,
|
||||
typename boost::function_traits<Signature>::arg1_type arg1,
|
||||
typename boost::function_traits<Signature>::arg2_type arg2)
|
||||
{
|
||||
shared_ptr<Reflection::Tuple> args(new Tuple());
|
||||
args->values.push_back(arg1);
|
||||
args->values.push_back(arg2);
|
||||
return SyncCallbackDesc<Signature>::template callGeneric<result_type>(function, args);
|
||||
}
|
||||
|
||||
protected:
|
||||
SyncCallbackDescImpl(ClassDescriptor& classDescriptor, const char* name, const char* arg1name, const char* arg2name, Descriptor::Attributes attributes, Security::Permissions security)
|
||||
:SyncCallbackDesc<Signature>(classDescriptor, name, attributes, security)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 2));
|
||||
this->signature.resultType = &Type::singleton<result_type>();
|
||||
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
|
||||
this->signature.addArgument(RBX::Name::declare(arg2name), Type::singleton<typename boost::function_traits<Signature>::arg2_type>());
|
||||
}
|
||||
public:
|
||||
virtual void setGenericCallback(DescribedBase* object, shared_ptr<SyncCallbackDescriptor::GenericFunction> function) const
|
||||
{
|
||||
this->setCallback(object, boost::bind(callGeneric, function, _1, _2));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Signature>
|
||||
class SyncCallbackDescImpl<Signature, 3> : public SyncCallbackDesc<Signature>
|
||||
{
|
||||
typedef typename SyncCallbackDesc<Signature>::result_type result_type;
|
||||
static result_type callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function,
|
||||
typename boost::function_traits<Signature>::arg1_type arg1,
|
||||
typename boost::function_traits<Signature>::arg2_type arg2,
|
||||
typename boost::function_traits<Signature>::arg3_type arg3)
|
||||
{
|
||||
shared_ptr<Reflection::Tuple> args(new Tuple());
|
||||
args->values.push_back(arg1);
|
||||
args->values.push_back(arg2);
|
||||
args->values.push_back(arg3);
|
||||
return SyncCallbackDesc<Signature>::template callGeneric<result_type>(function, args);
|
||||
}
|
||||
|
||||
protected:
|
||||
SyncCallbackDescImpl(ClassDescriptor& classDescriptor, const char* name, const char* arg1name, const char* arg2name, const char* arg3name, Descriptor::Attributes attributes, Security::Permissions security)
|
||||
:SyncCallbackDesc<Signature>(classDescriptor, name, attributes, security)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 3));
|
||||
this->signature.resultType = &Type::singleton<result_type>();
|
||||
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
|
||||
this->signature.addArgument(RBX::Name::declare(arg2name), Type::singleton<typename boost::function_traits<Signature>::arg2_type>());
|
||||
this->signature.addArgument(RBX::Name::declare(arg3name), Type::singleton<typename boost::function_traits<Signature>::arg3_type>());
|
||||
}
|
||||
public:
|
||||
virtual void setGenericCallback(DescribedBase* object, shared_ptr<SyncCallbackDescriptor::GenericFunction> function) const
|
||||
{
|
||||
this->setCallback(object, boost::bind(callGeneric, function, _1, _2, _3));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Signature>
|
||||
class SyncCallbackDescImpl<Signature, 4> : public SyncCallbackDesc<Signature>
|
||||
{
|
||||
typedef typename SyncCallbackDesc<Signature>::result_type result_type;
|
||||
static result_type callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function,
|
||||
typename boost::function_traits<Signature>::arg1_type arg1,
|
||||
typename boost::function_traits<Signature>::arg2_type arg2,
|
||||
typename boost::function_traits<Signature>::arg3_type arg3,
|
||||
typename boost::function_traits<Signature>::arg4_type arg4)
|
||||
{
|
||||
shared_ptr<Reflection::Tuple> args(new Tuple());
|
||||
args->values.push_back(arg1);
|
||||
args->values.push_back(arg2);
|
||||
args->values.push_back(arg3);
|
||||
args->values.push_back(arg4);
|
||||
return SyncCallbackDesc<Signature>::template callGeneric<result_type>(function, args);
|
||||
}
|
||||
|
||||
protected:
|
||||
SyncCallbackDescImpl(ClassDescriptor& classDescriptor, const char* name, const char* arg1name, const char* arg2name, const char* arg3name, const char* arg4name, Descriptor::Attributes attributes, Security::Permissions security)
|
||||
:SyncCallbackDesc<Signature>(classDescriptor, name, attributes, security)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 4));
|
||||
this->signature.resultType = &Type::singleton<result_type>();
|
||||
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
|
||||
this->signature.addArgument(RBX::Name::declare(arg2name), Type::singleton<typename boost::function_traits<Signature>::arg2_type>());
|
||||
this->signature.addArgument(RBX::Name::declare(arg3name), Type::singleton<typename boost::function_traits<Signature>::arg3_type>());
|
||||
this->signature.addArgument(RBX::Name::declare(arg4name), Type::singleton<typename boost::function_traits<Signature>::arg4_type>());
|
||||
}
|
||||
public:
|
||||
virtual void setGenericCallback(DescribedBase* object, shared_ptr<SyncCallbackDescriptor::GenericFunction> function) const
|
||||
{
|
||||
this->setCallback(object, boost::bind(callGeneric, function, _1, _2, _3, _4));
|
||||
}
|
||||
};
|
||||
|
||||
// The fully functional descriptor that binds to class members
|
||||
template<typename Signature>
|
||||
class BoundCallbackDesc : public SyncCallbackDescImpl<Signature, boost::function_traits<Signature>::arity>
|
||||
{
|
||||
typedef typename boost::function<Signature> Function;
|
||||
|
||||
template<class Class>
|
||||
class Setter : public SyncCallbackDesc<Signature>::ISetter
|
||||
{
|
||||
typedef void (Class::*OnChanged)();
|
||||
Function Class::*member;
|
||||
OnChanged onChanged;
|
||||
public:
|
||||
Setter(Function Class::*member, OnChanged onChanged = NULL):member(member),onChanged(onChanged) {}
|
||||
|
||||
virtual void setCallback(DescribedBase* object, const Function& value) const
|
||||
{
|
||||
Class* c = static_cast<Class*>(object);
|
||||
c->*member = value;
|
||||
if (onChanged)
|
||||
(c->*onChanged)();
|
||||
}
|
||||
};
|
||||
public:
|
||||
template<class Class>
|
||||
BoundCallbackDesc(const char* name, Function Class::*member, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
:SyncCallbackDescImpl<Signature, 0>(Class::classDescriptor(), name, attributes, security)
|
||||
{
|
||||
this->setter.reset(new Setter<Class>(member));
|
||||
}
|
||||
|
||||
template<class Class>
|
||||
BoundCallbackDesc(const char* name, Function Class::*member, void (Class::*onChanged)(), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
:SyncCallbackDescImpl<Signature, 0>(Class::classDescriptor(), name, attributes, security)
|
||||
{
|
||||
this->setter.reset(new Setter<Class>(member, onChanged));
|
||||
}
|
||||
|
||||
template<class Class>
|
||||
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
:SyncCallbackDescImpl<Signature, 1>(Class::classDescriptor(), name, arg1name, attributes, security)
|
||||
{
|
||||
this->setter.reset(new Setter<Class>(member));
|
||||
}
|
||||
|
||||
template<class Class>
|
||||
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, void (Class::*onChanged)(), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
:SyncCallbackDescImpl<Signature, 1>(Class::classDescriptor(), name, arg1name, attributes, security)
|
||||
{
|
||||
this->setter.reset(new Setter<Class>(member, onChanged));
|
||||
}
|
||||
|
||||
template<class Class>
|
||||
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
:SyncCallbackDescImpl<Signature, 2>(Class::classDescriptor(), name, arg1name, arg2name, attributes, security)
|
||||
{
|
||||
this->setter.reset(new Setter<Class>(member));
|
||||
}
|
||||
|
||||
template<class Class>
|
||||
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, void (Class::*onChanged)(), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
:SyncCallbackDescImpl<Signature, 2>(Class::classDescriptor(), name, arg1name, arg2name, attributes, security)
|
||||
{
|
||||
this->setter.reset(new Setter<Class>(member, onChanged));
|
||||
}
|
||||
|
||||
template<class Class>
|
||||
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, const char* arg3name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
:SyncCallbackDescImpl<Signature, 3>(Class::classDescriptor(), name, arg1name, arg2name, arg3name, attributes, security)
|
||||
{
|
||||
this->setter.reset(new Setter<Class>(member));
|
||||
}
|
||||
|
||||
template<class Class>
|
||||
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, const char* arg3name, void (Class::*onChanged)(), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
:SyncCallbackDescImpl<Signature, 3>(Class::classDescriptor(), name, arg1name, arg2name, arg3name, attributes, security)
|
||||
{
|
||||
this->setter.reset(new Setter<Class>(member, onChanged));
|
||||
}
|
||||
|
||||
template<class Class>
|
||||
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, const char* arg3name, const char* arg4name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
:SyncCallbackDescImpl<Signature, 4>(Class::classDescriptor(), name, arg1name, arg2name, arg3name, arg4name, attributes, security)
|
||||
{
|
||||
this->setter.reset(new Setter<Class>(member));
|
||||
}
|
||||
|
||||
template<class Class>
|
||||
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, const char* arg3name, const char* arg4name, void (Class::*onChanged)(), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
:SyncCallbackDescImpl<Signature, 4>(Class::classDescriptor(), name, arg1name, arg2name, arg3name, arg4name, attributes, security)
|
||||
{
|
||||
this->setter.reset(new Setter<Class>(member, onChanged));
|
||||
}
|
||||
};
|
||||
|
||||
template <class Class, typename Signature, int arity = boost::function_traits<Signature>::arity>
|
||||
class BoundAsyncCallbackDesc;
|
||||
|
||||
template <class Class, typename Signature>
|
||||
class BoundAsyncCallbackDesc<Class, Signature, 0> : public AsyncCallbackDescriptor
|
||||
{
|
||||
typedef boost::function<void(AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)> Function;
|
||||
|
||||
static void callGeneric(shared_ptr<AsyncCallbackDescriptor::GenericFunction> function,
|
||||
AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)
|
||||
{
|
||||
shared_ptr<Reflection::Tuple> args(new Tuple());
|
||||
callGenericImpl(function, args, resumeFunction, errorFunction);
|
||||
}
|
||||
|
||||
void declareSignature()
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 0));
|
||||
this->signature.resultType = &Type::singleton<typename boost::function_traits<Signature>::result_type>();
|
||||
}
|
||||
|
||||
Function Class::*member;
|
||||
void (Class::*onChanged)(const Function&);
|
||||
|
||||
public:
|
||||
BoundAsyncCallbackDesc(const char* name, Function Class::*member, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
|
||||
, member(member)
|
||||
, onChanged(NULL)
|
||||
{
|
||||
declareSignature();
|
||||
}
|
||||
|
||||
BoundAsyncCallbackDesc(const char* name, Function Class::*member, void (Class::*onChanged)(const Function&), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
|
||||
, member(member)
|
||||
, onChanged(onChanged)
|
||||
{
|
||||
declareSignature();
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void setGenericCallback(DescribedBase* object, shared_ptr<AsyncCallbackDescriptor::GenericFunction> function) const
|
||||
{
|
||||
setGenericCallbackImpl(object, member, onChanged, boost::bind(callGeneric, function, _1, _2));
|
||||
}
|
||||
|
||||
virtual void clearCallback(DescribedBase* object) const
|
||||
{
|
||||
setGenericCallbackImpl(object, member, onChanged, Function());
|
||||
}
|
||||
};
|
||||
|
||||
template <class Class, typename Signature>
|
||||
class BoundAsyncCallbackDesc<Class, Signature, 1> : public AsyncCallbackDescriptor
|
||||
{
|
||||
typedef typename boost::function_traits<Signature>::arg1_type Arg1;
|
||||
typedef boost::function<void(Arg1, AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)> Function;
|
||||
|
||||
static void callGeneric(shared_ptr<AsyncCallbackDescriptor::GenericFunction> function,
|
||||
Arg1 arg1,
|
||||
AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)
|
||||
{
|
||||
shared_ptr<Reflection::Tuple> args(new Tuple());
|
||||
args->values.push_back(arg1);
|
||||
callGenericImpl(function, args, resumeFunction, errorFunction);
|
||||
}
|
||||
|
||||
void declareSignature(const char* arg1name)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 1));
|
||||
this->signature.resultType = &Type::singleton<typename boost::function_traits<Signature>::result_type>();
|
||||
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
|
||||
}
|
||||
|
||||
Function Class::*member;
|
||||
void (Class::*onChanged)(const Function&);
|
||||
|
||||
public:
|
||||
BoundAsyncCallbackDesc(const char* name, Function Class::*member, const char* arg1name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
|
||||
, member(member)
|
||||
, onChanged(NULL)
|
||||
{
|
||||
declareSignature(arg1name);
|
||||
}
|
||||
|
||||
BoundAsyncCallbackDesc(const char* name, Function Class::*member, const char* arg1name, void (Class::*onChanged)(const Function&), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
|
||||
, member(member)
|
||||
, onChanged(onChanged)
|
||||
{
|
||||
declareSignature(arg1name);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void setGenericCallback(DescribedBase* object, shared_ptr<AsyncCallbackDescriptor::GenericFunction> function) const
|
||||
{
|
||||
setGenericCallbackImpl(object, member, onChanged, boost::bind(callGeneric, function, _1, _2, _3));
|
||||
}
|
||||
|
||||
virtual void clearCallback(DescribedBase* object) const
|
||||
{
|
||||
setGenericCallbackImpl(object, member, onChanged, Function());
|
||||
}
|
||||
};
|
||||
|
||||
template <class Class, typename Signature>
|
||||
class BoundAsyncCallbackDesc<Class, Signature, 2> : public AsyncCallbackDescriptor
|
||||
{
|
||||
typedef typename boost::function_traits<Signature>::arg1_type Arg1;
|
||||
typedef typename boost::function_traits<Signature>::arg2_type Arg2;
|
||||
typedef boost::function<void(Arg1, Arg2, AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)> Function;
|
||||
|
||||
static void callGeneric(shared_ptr<AsyncCallbackDescriptor::GenericFunction> function,
|
||||
Arg1 arg1,
|
||||
Arg2 arg2,
|
||||
AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)
|
||||
{
|
||||
shared_ptr<Reflection::Tuple> args(new Tuple());
|
||||
args->values.push_back(arg1);
|
||||
args->values.push_back(arg2);
|
||||
callGenericImpl(function, args, resumeFunction, errorFunction);
|
||||
}
|
||||
|
||||
void declareSignature(const char* arg1name, const char* arg2name)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 2));
|
||||
this->signature.resultType = &Type::singleton<typename boost::function_traits<Signature>::result_type>();
|
||||
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
|
||||
this->signature.addArgument(RBX::Name::declare(arg2name), Type::singleton<typename boost::function_traits<Signature>::arg2_type>());
|
||||
}
|
||||
|
||||
Function Class::*member;
|
||||
void (Class::*onChanged)(const Function&);
|
||||
|
||||
public:
|
||||
BoundAsyncCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
|
||||
, member(member)
|
||||
, onChanged(NULL)
|
||||
{
|
||||
declareSignature(arg1name, arg2name);
|
||||
}
|
||||
|
||||
BoundAsyncCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, void (Class::*onChanged)(const Function&), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
|
||||
, member(member)
|
||||
, onChanged(onChanged)
|
||||
{
|
||||
declareSignature(arg1name, arg2name);
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void setGenericCallback(DescribedBase* object, shared_ptr<AsyncCallbackDescriptor::GenericFunction> function) const
|
||||
{
|
||||
setGenericCallbackImpl(object, member, onChanged, boost::bind(callGeneric, function, _1, _2, _3, _4));
|
||||
}
|
||||
|
||||
virtual void clearCallback(DescribedBase* object) const
|
||||
{
|
||||
setGenericCallbackImpl(object, member, onChanged, Function());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/Name.h"
|
||||
#include "boost/utility.hpp"
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Reflection
|
||||
{
|
||||
class Descriptor : public boost::noncopyable
|
||||
{
|
||||
|
||||
static void checkLockedDown()
|
||||
{
|
||||
// If this following assertion fails then you need to put your class
|
||||
// into FactoryRegistrator::FactoryRegistrator() or somewhere else.
|
||||
// Failure of this test is so severe that we want to catch it in production, too.
|
||||
if (lockedDown)
|
||||
RBXCRASH();
|
||||
}
|
||||
public:
|
||||
struct Attributes
|
||||
{
|
||||
bool isDeprecated;
|
||||
const Descriptor* preferred; // used if isDeprecated
|
||||
Attributes()
|
||||
:isDeprecated(false)
|
||||
,preferred(NULL)
|
||||
{}
|
||||
static Attributes deprecated(const Descriptor& preferred)
|
||||
{
|
||||
Attributes result;
|
||||
result.isDeprecated = true;
|
||||
result.preferred = &preferred;
|
||||
return result;
|
||||
}
|
||||
static Attributes deprecated()
|
||||
{
|
||||
Attributes result;
|
||||
result.isDeprecated = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static bool lockedDown; // After the first instance of a described class is created we cannot modify the reflection database
|
||||
|
||||
const RBX::Name& name;
|
||||
scoped_ptr<bool> isReplicable;
|
||||
scoped_ptr<bool> isOutdated;
|
||||
const Attributes attributes;
|
||||
|
||||
Descriptor(const char* name, Attributes attributes)
|
||||
:name(RBX::Name::declare(name))
|
||||
,attributes(attributes)
|
||||
,isReplicable(new bool(false))
|
||||
,isOutdated(new bool(false))
|
||||
{
|
||||
checkLockedDown();
|
||||
RBXASSERT(!this->name.empty());
|
||||
}
|
||||
Descriptor(const RBX::Name& name, Attributes attributes)
|
||||
:name(name)
|
||||
,attributes(attributes)
|
||||
,isReplicable(new bool(false))
|
||||
,isOutdated(new bool(false))
|
||||
{
|
||||
checkLockedDown();
|
||||
RBXASSERT(!this->name.empty());
|
||||
}
|
||||
virtual ~Descriptor() {}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,375 @@
|
||||
#pragma once
|
||||
|
||||
#include "reflection/Type.h"
|
||||
#include "util/utilities.h"
|
||||
#include "util/math.h"
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
|
||||
namespace RBX {
|
||||
|
||||
|
||||
namespace Reflection {
|
||||
|
||||
class EnumDescriptor : public Type
|
||||
{
|
||||
public:
|
||||
static std::vector< const EnumDescriptor* >::const_iterator enumsBegin();
|
||||
static std::vector< const EnumDescriptor* >::const_iterator enumsEnd();
|
||||
static size_t allEnumSize() {return allEnums().size();}
|
||||
|
||||
class Item : public Descriptor
|
||||
{
|
||||
public:
|
||||
const EnumDescriptor& owner;
|
||||
const int value; // value of the enum
|
||||
const size_t index; // place in ordered enum values (0<=index<enumCount)
|
||||
Item(const char* name, Descriptor::Attributes attributes, int value, size_t index, const EnumDescriptor& owner)
|
||||
:Descriptor(name, attributes)
|
||||
,value(value)
|
||||
,index(index)
|
||||
,owner(owner)
|
||||
{
|
||||
}
|
||||
bool convertToValue(Variant& value) const
|
||||
{
|
||||
return owner.convertToValue(index, value);
|
||||
}
|
||||
bool convertToString(std::string& value) const
|
||||
{
|
||||
return owner.convertToString(index, value);
|
||||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
typedef boost::unordered_map<const RBX::Name*, const EnumDescriptor*> EnumNameTable;
|
||||
#else
|
||||
typedef std::map<const RBX::Name*, const EnumDescriptor*> EnumNameTable;
|
||||
#endif
|
||||
|
||||
private:
|
||||
static EnumNameTable& allEnumsNameLookup();
|
||||
static std::vector<const EnumDescriptor*>& allEnums();
|
||||
|
||||
static bool equalValue(const Item* item, int intValue)
|
||||
{
|
||||
return item->value == intValue;
|
||||
}
|
||||
|
||||
static int count;
|
||||
protected:
|
||||
std::vector< const Item* > allItems;
|
||||
size_t enumCount;
|
||||
size_t enumCountMSB;
|
||||
EnumDescriptor(const char* typeName);
|
||||
~EnumDescriptor();
|
||||
public:
|
||||
size_t getEnumCount() const { return enumCount; }
|
||||
size_t getEnumCountMSB() const { return enumCountMSB; }
|
||||
std::vector< const Item* >::const_iterator begin() const {
|
||||
return allItems.begin();
|
||||
}
|
||||
std::vector< const Item* >::const_iterator end() const {
|
||||
return allItems.end();
|
||||
}
|
||||
static const EnumDescriptor* lookupDescriptor(const RBX::Name& name) {
|
||||
EnumNameTable::const_iterator iter = allEnumsNameLookup().find(&name);
|
||||
if (iter!=allEnumsNameLookup().end())
|
||||
return iter->second;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
static const EnumDescriptor* lookupDescriptor(const Type& type) {
|
||||
if (type.isEnum)
|
||||
return static_cast<const EnumDescriptor*>(&type);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool isValue(int intValue) const {
|
||||
return std::find_if(allItems.begin(), allItems.end(), boost::bind(&equalValue, _1, intValue)) != allItems.end();
|
||||
}
|
||||
virtual const Item* lookup(const char* text) const = 0;
|
||||
virtual const Item* lookup(const Variant& value) const = 0;
|
||||
virtual bool convertToValue(size_t index, Variant& value) const = 0;
|
||||
virtual bool convertToString(size_t index, std::string& value) const = 0;
|
||||
};
|
||||
|
||||
// A thread-safe singleton!
|
||||
template<typename T>
|
||||
class Singleton : boost::noncopyable
|
||||
{
|
||||
static T& doGetSingleton()
|
||||
{
|
||||
static T s;
|
||||
return s;
|
||||
}
|
||||
static void initSingleton()
|
||||
{
|
||||
doGetSingleton();
|
||||
}
|
||||
public:
|
||||
static T& singleton()
|
||||
{
|
||||
static boost::once_flag flag = BOOST_ONCE_INIT;
|
||||
boost::call_once(&initSingleton, flag);
|
||||
return doGetSingleton();
|
||||
};
|
||||
};
|
||||
|
||||
template<typename Enum> class EnumRegistrar;
|
||||
|
||||
template<typename Enum>
|
||||
class EnumDesc : public EnumDescriptor
|
||||
{
|
||||
public:
|
||||
friend class Singleton<const EnumDesc<Enum> >;
|
||||
static const EnumDesc& singleton()
|
||||
{
|
||||
return Singleton<const EnumDesc<Enum> >::singleton();
|
||||
}
|
||||
|
||||
private:
|
||||
// You must implement the following constructor for each EnumDesc that you define
|
||||
EnumDesc();
|
||||
~EnumDesc()
|
||||
{
|
||||
// Force linking of EnumRegistrar<Enum>, which will force clients
|
||||
// of this library to define EnumRegistrar<Enum>::registrar in
|
||||
// their startup code.
|
||||
|
||||
|
||||
Reflection::EnumRegistrar<Enum>::registrar.dummy();
|
||||
|
||||
std::for_each(allItems.begin(), allItems.end(), &del_fun<const Item>);
|
||||
}
|
||||
|
||||
std::map<const RBX::Name*, Enum> nameToEnum;
|
||||
std::map<const RBX::Name*, Enum> nameToEnumLegacy;
|
||||
std::vector< const RBX::Name* > enumToName; // maps enum to Name (there may be gaps)
|
||||
|
||||
std::vector< std::string > enumToString; // maps enum to String (there may be gaps)
|
||||
std::vector< const Item* > enumToItem; // maps enum to Item (there may be gaps)
|
||||
|
||||
std::vector< Enum > intToEnum; // maps legacy values to proper enum
|
||||
std::vector< Enum > indexToEnum;
|
||||
std::vector< size_t > enumToIndex; // maps enum to Index (there may be gaps)
|
||||
|
||||
|
||||
// Used in constructor
|
||||
void addPair(Enum value, const char* name, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||
{
|
||||
RBXASSERT_VERY_FAST(value >= 0);
|
||||
// No spaces in enums:
|
||||
RBXASSERT_VERY_FAST(std::string(name).find(' ') == std::string::npos);
|
||||
// No no CamelCase in enums:
|
||||
RBXASSERT_VERY_FAST(!isCamel(name));
|
||||
|
||||
const Item* item = new Item(name, attributes, value, enumCount, *this);
|
||||
|
||||
allItems.push_back(item);
|
||||
|
||||
if (intToEnum.size()<=(size_t)value)
|
||||
intToEnum.resize(value+1, (Enum)-1);
|
||||
intToEnum[value] = value;
|
||||
|
||||
RBXASSERT(value>=0);
|
||||
|
||||
if (enumToIndex.size()<=(size_t)value)
|
||||
enumToIndex.resize(value+1, -1);
|
||||
enumToIndex[value] = enumCount;
|
||||
indexToEnum.push_back(value);
|
||||
|
||||
if (enumToName.size()<=(size_t)value)
|
||||
enumToName.resize(value+1, &RBX::Name::getNullName());
|
||||
enumToName[value] = &item->name;
|
||||
|
||||
if (enumToString.size()<=(size_t)value)
|
||||
enumToString.resize(value+1);
|
||||
enumToString[value] = name;
|
||||
|
||||
if (enumToItem.size()<=(size_t)value)
|
||||
enumToItem.resize(value+1);
|
||||
enumToItem[value] = item;
|
||||
|
||||
nameToEnum[&item->name] = value;
|
||||
|
||||
enumCount++;
|
||||
enumCountMSB = Math::computeMSB(enumCount);
|
||||
}
|
||||
void addLegacy(int oldValue, const char* name, Enum value)
|
||||
{
|
||||
RBXASSERT_VERY_FAST(value >= 0);
|
||||
|
||||
if (intToEnum.size()<=(size_t)oldValue)
|
||||
intToEnum.resize(oldValue+1, (Enum)-1);
|
||||
intToEnum[oldValue] = value;
|
||||
nameToEnumLegacy[&RBX::Name::declare(name)] = value;
|
||||
}
|
||||
void addLegacyName(const char* name, Enum value)
|
||||
{
|
||||
nameToEnumLegacy[&RBX::Name::declare(name)] = value;
|
||||
}
|
||||
public:
|
||||
const RBX::Name& convertToName(const Enum& value) const
|
||||
{
|
||||
RBXASSERT(value>=0);
|
||||
RBXASSERT(value<enumToItem.size());
|
||||
if (value<0)
|
||||
return RBX::Name::getNullName();
|
||||
if ((size_t)value>=enumToName.size())
|
||||
return RBX::Name::getNullName();
|
||||
|
||||
return *enumToName[value];
|
||||
}
|
||||
std::string convertToString(const Enum& value) const
|
||||
{
|
||||
RBXASSERT(value>=0);
|
||||
RBXASSERT((size_t)value<enumToItem.size());
|
||||
if (value<0)
|
||||
return "";
|
||||
if ((size_t)value>=enumToString.size())
|
||||
return "";
|
||||
|
||||
return enumToString[value];
|
||||
}
|
||||
const Item* convertToItem(const Enum& value) const
|
||||
{
|
||||
RBXASSERT(value>=0);
|
||||
RBXASSERT((size_t)value<enumToItem.size());
|
||||
if (value<0)
|
||||
return NULL;
|
||||
if ((size_t)value>=enumToItem.size())
|
||||
return NULL;
|
||||
|
||||
return enumToItem[value];
|
||||
}
|
||||
|
||||
bool mapIntValue(int intValue, Enum& value) const
|
||||
{
|
||||
if (intValue < 0)
|
||||
return false;
|
||||
|
||||
if ((size_t)intValue >= intToEnum.size())
|
||||
return false;
|
||||
|
||||
value = intToEnum[intValue];
|
||||
if ((int)value == -1)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool convertToValue(const RBX::Name& name, Enum& value) const
|
||||
{
|
||||
typename std::map<const RBX::Name*, Enum>::const_iterator iter = nameToEnum.find(&name);
|
||||
if (iter!=nameToEnum.end()) {
|
||||
value = iter->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
iter = nameToEnumLegacy.find(&name);
|
||||
if (iter!=nameToEnumLegacy.end()) {
|
||||
value = iter->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
/*implement*/ const Item* lookup(const char* text) const
|
||||
{
|
||||
Enum e;
|
||||
if (convertToValue(RBX::Name::lookup(text), e))
|
||||
return convertToItem(e);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
/*implement*/ const Item* lookup(const Variant& value) const
|
||||
{
|
||||
return convertToItem(value.cast<Enum>());
|
||||
}
|
||||
|
||||
/*implement*/ bool convertToValue(size_t index, Variant& value) const
|
||||
{
|
||||
Enum enumValue;
|
||||
bool result = convertToValue(index, enumValue);
|
||||
value = enumValue;
|
||||
return result;
|
||||
}
|
||||
/*implement*/ bool convertToString(size_t index, std::string& stringValue) const
|
||||
{
|
||||
Enum enumValue;
|
||||
if(convertToValue(index, enumValue)){
|
||||
stringValue = convertToString(enumValue);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool convertToValue(const char* text, Enum& value) const
|
||||
{
|
||||
return convertToValue(RBX::Name::lookup(text), value);
|
||||
}
|
||||
size_t convertToIndex(Enum value) const
|
||||
{
|
||||
RBXASSERT(value>=0);
|
||||
if ((size_t)value<enumToIndex.size())
|
||||
return enumToIndex[value];
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
bool convertToValue(size_t index, Enum& value) const
|
||||
{
|
||||
if (index<enumCount) {
|
||||
value = indexToEnum[index];
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Helper macro
|
||||
// GCC does not generate the registrar variable defination & fails at Link Time. Force Construct by passing in an dummy arg to ctor. That works. WEIRD huh?
|
||||
#define RBX_REGISTER_ENUM(Enum) namespace RBX { namespace Reflection { \
|
||||
template<> \
|
||||
const Type& Type::getSingleton<Enum>() \
|
||||
{ \
|
||||
return EnumDesc<Enum>::singleton(); \
|
||||
} \
|
||||
template<> EnumRegistrar<Enum> EnumRegistrar<Enum>::registrar(0); \
|
||||
template<> TypeRegistrar<Enum> TypeRegistrar<Enum>::registrar(0); \
|
||||
}}
|
||||
|
||||
// This class is intended to prevent clients of the library
|
||||
// from forgetting to initialize the enum descriptor
|
||||
template<typename Enum>
|
||||
class EnumRegistrar : boost::noncopyable
|
||||
{
|
||||
int x;
|
||||
|
||||
//// GCC does not generate the registrar variable defination & fails at Link Time. Force Construct by passing in an dummy arg to ctor. That works. WEIRD huh?
|
||||
EnumRegistrar(int i):x(i)
|
||||
{
|
||||
// This call registers the enum descriptor
|
||||
// in the reflection database
|
||||
EnumDesc<Enum>::singleton();
|
||||
}
|
||||
public:
|
||||
void dummy()
|
||||
{
|
||||
x++;
|
||||
}
|
||||
|
||||
// The instantiation of this static member must be in a unit
|
||||
// that is initialized in the main thread before any objects
|
||||
// are created. Otherwise the reflection database
|
||||
// can change at runtime, which would be a disaster
|
||||
static EnumRegistrar registrar;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,108 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "reflection/type.h"
|
||||
#include "security/securitycontext.h"
|
||||
#include "reflection/member.h"
|
||||
#include "util/G3DCore.h"
|
||||
#include "util/Region3.h"
|
||||
#include "util/Region3Int16.h"
|
||||
|
||||
struct lua_State;
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Reflection
|
||||
{
|
||||
class Function;
|
||||
class EnumDescriptor;
|
||||
|
||||
// Base that describes a Function
|
||||
class RBXBaseClass FunctionDescriptor : public MemberDescriptor
|
||||
{
|
||||
public:
|
||||
enum Kind
|
||||
{
|
||||
Kind_Default,
|
||||
Kind_Custom
|
||||
};
|
||||
|
||||
class RBXInterface Arguments
|
||||
{
|
||||
public:
|
||||
Variant returnValue;
|
||||
|
||||
virtual size_t size() const = 0;
|
||||
// Place the value for the requested parameter in "value".
|
||||
//
|
||||
// index: 1-based index into the argument list
|
||||
// returns: true if the index contains a valid argument
|
||||
// value: the value to set. the function returns false then value is unchanged
|
||||
virtual bool getVariant(int index, Variant& value) const = 0;
|
||||
virtual bool getBool(int index, bool& value) const = 0;
|
||||
virtual bool getLong(int index, long& value) const = 0;
|
||||
virtual bool getDouble(int index, double& value) const = 0;
|
||||
virtual bool getString(int index, std::string& value) const = 0;
|
||||
virtual bool getVector3int16(int index, Vector3int16& value) const = 0;
|
||||
virtual bool getRegion3int16(int index, Region3int16& value) const = 0;
|
||||
virtual bool getVector3(int index, Vector3& value) const = 0;
|
||||
virtual bool getRegion3(int index, Region3& value) const = 0;
|
||||
virtual bool getRect(int index, Rect2D& value) const = 0;
|
||||
virtual bool getObject(int index, shared_ptr<DescribedBase>& value) const = 0;
|
||||
virtual bool getEnum(int index, const EnumDescriptor& desc, int& value) const = 0;
|
||||
};
|
||||
typedef Function ConstMember;
|
||||
typedef Function Member;
|
||||
|
||||
protected:
|
||||
SignatureDescriptor signature;
|
||||
Kind kind;
|
||||
FunctionDescriptor(ClassDescriptor& classDescriptor, const char* name, Security::Permissions security, Attributes attributes);
|
||||
|
||||
public:
|
||||
const SignatureDescriptor& getSignature() const { return signature; }
|
||||
|
||||
Kind getKind() const { return kind; }
|
||||
|
||||
virtual int executeCustom(DescribedBase* instance, lua_State*) const { return 0; }
|
||||
|
||||
virtual void execute(DescribedBase* instance, Arguments& arguments) const = 0;
|
||||
};
|
||||
|
||||
|
||||
// A light-weight convenience class that associates a FunctionDescriptor
|
||||
// with a described object to create a "Function"
|
||||
class Function
|
||||
{
|
||||
protected:
|
||||
const FunctionDescriptor* descriptor;
|
||||
DescribedBase* instance;
|
||||
public:
|
||||
inline Function(const FunctionDescriptor& descriptor, DescribedBase* instance)
|
||||
:descriptor(&descriptor),instance(instance)
|
||||
{}
|
||||
|
||||
inline Function(const Function& other)
|
||||
:descriptor(other.descriptor),instance(other.instance)
|
||||
{}
|
||||
inline Function& operator =(const Function& other)
|
||||
{
|
||||
this->descriptor = other.descriptor;
|
||||
this->instance = other.instance;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const RBX::Name& getName() const {
|
||||
return descriptor->name;
|
||||
}
|
||||
|
||||
inline const FunctionDescriptor* getDescriptor() const {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
void execute(FunctionDescriptor::Arguments& arguments) const {
|
||||
return descriptor->execute(const_cast<DescribedBase*>(instance), arguments);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "reflection/Property.h"
|
||||
#include "reflection/Function.h"
|
||||
#include "reflection/YieldFunction.h"
|
||||
#include "Reflection/Event.h"
|
||||
#include "reflection/Callback.h"
|
||||
|
||||
#include <vector>
|
||||
#include "boost/crc.hpp"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Reflection
|
||||
{
|
||||
enum ReplicationLevel{
|
||||
NEVER_REPLICATE = 0, //Never replicate this object
|
||||
STANDARD_REPLICATE= 1, //Replicate to/from server according to standard rules
|
||||
PLAYER_REPLICATE = 2, //Replicate changes to/from the "player" who owns this object
|
||||
} ;
|
||||
|
||||
class ClassDescriptor
|
||||
: public Descriptor
|
||||
, public MemberDescriptorContainer<PropertyDescriptor>
|
||||
, public MemberDescriptorContainer<EventDescriptor>
|
||||
, public MemberDescriptorContainer<FunctionDescriptor>
|
||||
, public MemberDescriptorContainer<YieldFunctionDescriptor>
|
||||
, public MemberDescriptorContainer<CallbackDescriptor>
|
||||
{
|
||||
public:
|
||||
typedef std::vector<ClassDescriptor*> ClassDescriptors;
|
||||
|
||||
enum Functionality{
|
||||
PERSISTENT = 0x1 + 0x2 + 0x8 + 0x10, // isPublic, Replicate, canXmlWrite, isScriptable
|
||||
PERSISTENT_PLAYER = 0x1 + 0x4 + 0x8 + 0x10, // isPublic, ReplicatePlayer, canXmlWrite, isScriptable
|
||||
PERSISTENT_LOCAL = 0x1 + 0x0 + 0x8 + 0x10, // isPublic, canXmlWrite, isScriptable
|
||||
RUNTIME = 0x1 + 0x2 + 0x0 + 0x10, // isPublic, Replicate, isScriptable
|
||||
RUNTIME_PLAYER = 0x1 + 0x4 + 0x0 + 0x10, // isPublic, ReplicatePlayer, isScriptable
|
||||
RUNTIME_LOCAL = 0x1 + 0x0 + 0x0 + 0x10, // isPublic, isScriptable
|
||||
INTERNAL = 0x1 + 0x2 + 0x0 + 0x0, // isPublic, Replicate
|
||||
INTERNAL_PLAYER = 0x1 + 0x4 + 0x0 + 0x0, // isPublic, ReplicatePlayer,
|
||||
INTERNAL_LOCAL = 0x1 + 0x0 + 0x0 + 0x0, // isPublic
|
||||
PERSISTENT_HIDDEN = 0x1 + 0x2 + 0x8 + 0x0, // isPublic, Replicate, canXmlWrite
|
||||
PERSISTENT_LOCAL_INTERNAL = 0x1 + 0x0 + 0x8 + 0x0, // isPublic, canXmlWrite
|
||||
};
|
||||
|
||||
struct Attributes : public Descriptor::Attributes
|
||||
{
|
||||
Functionality flags;
|
||||
|
||||
Attributes(Functionality flags):flags(flags) {}
|
||||
static Attributes deprecated(Functionality flags, const ClassDescriptor* preferred);
|
||||
};
|
||||
|
||||
const Security::Permissions security;
|
||||
|
||||
private:
|
||||
ClassDescriptor();
|
||||
static ClassDescriptors& allClasses();
|
||||
|
||||
ClassDescriptors derivedClasses;
|
||||
ClassDescriptor* const base;
|
||||
const unsigned bReplicateType : 2;
|
||||
const unsigned bCanXmlWrite : 1;
|
||||
const unsigned bIsScriptable : 1;
|
||||
|
||||
static int count;
|
||||
|
||||
public:
|
||||
ClassDescriptor(ClassDescriptor& base, const char* name, Attributes attributes, Security::Permissions security);
|
||||
~ClassDescriptor() { count--; }
|
||||
|
||||
const ClassDescriptor* getBase() const { return base; }
|
||||
|
||||
bool isBaseOf(const ClassDescriptor& child) const;
|
||||
bool isA(const ClassDescriptor& test) const;
|
||||
|
||||
bool isBaseOf(const char* childName) const;
|
||||
bool isA(const char* testName) const;
|
||||
|
||||
inline ReplicationLevel getReplicationLevel() const { return (ReplicationLevel)bReplicateType; }
|
||||
inline bool isScriptCreatable() const { return bIsScriptable != 0; }
|
||||
inline bool isSerializable() const { return bCanXmlWrite != 0; }
|
||||
|
||||
// The root ClassDescriptor of all other Descriptors
|
||||
static ClassDescriptor& rootDescriptor()
|
||||
{
|
||||
static ClassDescriptor root;
|
||||
return root;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Class enumeration
|
||||
static ClassDescriptors::const_iterator all_begin() {
|
||||
return allClasses().begin();
|
||||
}
|
||||
static ClassDescriptors::const_iterator all_end() {
|
||||
return allClasses().end();
|
||||
}
|
||||
static size_t all_size()
|
||||
{
|
||||
return allClasses().size();
|
||||
}
|
||||
static unsigned int checksum();
|
||||
static unsigned int checksum(const PropertyDescriptor* t, boost::crc_32_type& result);
|
||||
static unsigned int checksum(const EventDescriptor* t, boost::crc_32_type& result);
|
||||
static unsigned int checksum(const ClassDescriptor* t, boost::crc_32_type& result);
|
||||
static unsigned int checksum(const Type* t, boost::crc_32_type& result);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Derived Class enumeration
|
||||
ClassDescriptors::const_iterator derivedClasses_begin() const {
|
||||
return derivedClasses.begin();
|
||||
}
|
||||
ClassDescriptors::const_iterator derivedClasses_end() const {
|
||||
return derivedClasses.end();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Convenience functions for enumerating and querying members of a Class
|
||||
PropertyDescriptor* findPropertyDescriptor(const char* name) const
|
||||
{
|
||||
return MemberDescriptorContainer<PropertyDescriptor>::findDescriptor(name);
|
||||
}
|
||||
FunctionDescriptor* findFunctionDescriptor(const char* name) const
|
||||
{
|
||||
return MemberDescriptorContainer<FunctionDescriptor>::findDescriptor(name);
|
||||
}
|
||||
YieldFunctionDescriptor* findYieldFunctionDescriptor(const char* name) const
|
||||
{
|
||||
return MemberDescriptorContainer<YieldFunctionDescriptor>::findDescriptor(name);
|
||||
}
|
||||
EventDescriptor* findEventDescriptor(const char* name) const
|
||||
{
|
||||
return MemberDescriptorContainer<EventDescriptor>::findDescriptor(name);
|
||||
}
|
||||
CallbackDescriptor* findCallbackDescriptor(const char* name) const
|
||||
{
|
||||
return MemberDescriptorContainer<CallbackDescriptor>::findDescriptor(name);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
typename MemberDescriptorContainer<T>::Collection::const_iterator begin() const {
|
||||
return MemberDescriptorContainer<T>::descriptors_begin();
|
||||
}
|
||||
template<class T>
|
||||
typename MemberDescriptorContainer<T>::Collection::const_iterator end() const {
|
||||
return MemberDescriptorContainer<T>::descriptors_end();
|
||||
}
|
||||
|
||||
bool operator==(const ClassDescriptor& other) const;
|
||||
bool operator!=(const ClassDescriptor& other) const;
|
||||
};
|
||||
|
||||
// Convenience typedefs:
|
||||
typedef MemberDescriptorContainer<PropertyDescriptor>::ConstIterator ConstPropertyIterator;
|
||||
typedef MemberDescriptorContainer<PropertyDescriptor>::Iterator PropertyIterator;
|
||||
typedef MemberDescriptorContainer<FunctionDescriptor>::ConstIterator FunctionIterator;
|
||||
typedef MemberDescriptorContainer<YieldFunctionDescriptor>::ConstIterator YieldFunctionIterator;
|
||||
typedef MemberDescriptorContainer<EventDescriptor>::ConstIterator ConstSignalIterator;
|
||||
typedef MemberDescriptorContainer<EventDescriptor>::Iterator SignalIterator;
|
||||
typedef MemberDescriptorContainer<CallbackDescriptor>::Iterator CallbackIterator;
|
||||
|
||||
// The base class of any class that supports Reflection
|
||||
class RBXBaseClass DescribedBase
|
||||
: public EventSource
|
||||
, public boost::enable_shared_from_this<DescribedBase>
|
||||
{
|
||||
protected:
|
||||
// Each instance has a reference to it's most-specific ClassDescriptor:
|
||||
const ClassDescriptor* descriptor;
|
||||
boost::scoped_ptr<std::string> xmlId;
|
||||
|
||||
public:
|
||||
// The ClassDescriptor for this base class
|
||||
static ClassDescriptor& classDescriptor()
|
||||
{
|
||||
return ClassDescriptor::rootDescriptor();
|
||||
}
|
||||
|
||||
DescribedBase()
|
||||
{
|
||||
Descriptor::lockedDown = true; // See Descriptor::checkLockedDown() for an explanation
|
||||
|
||||
// By default, each DescribedBase has a null ClassDescriptor
|
||||
this->descriptor = &classDescriptor();
|
||||
}
|
||||
|
||||
virtual ~DescribedBase()
|
||||
{
|
||||
}
|
||||
|
||||
inline const ClassDescriptor& getDescriptor() const { return *descriptor; };
|
||||
|
||||
template<class T>
|
||||
inline bool isA() const
|
||||
{
|
||||
return getDescriptor().isA(T::classDescriptor());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static inline bool isA(const DescribedBase* instance)
|
||||
{
|
||||
return instance ? instance->getDescriptor().isA(T::classDescriptor()) : false;
|
||||
}
|
||||
|
||||
// This function is slower than the others
|
||||
bool isA(std::string className)
|
||||
{
|
||||
return getDescriptor().isA(className.c_str());
|
||||
}
|
||||
|
||||
// Regular dynamic_casts are very slow. These faster versions uses our reflection framework to determine type then uses static_cast for speed.
|
||||
// Use these functions to replace dynamic_casts for classes that derives from DescribedCreatable or DescribedNonCreatable.
|
||||
template<class T>
|
||||
inline T* fastDynamicCast()
|
||||
{
|
||||
return (getDescriptor().isA(T::classDescriptor())) ? static_cast<T*>(this) : NULL;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline const T* fastDynamicCast() const
|
||||
{
|
||||
return (getDescriptor().isA(T::classDescriptor())) ? static_cast<const T*>(this) : NULL;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static inline T* fastDynamicCast(DescribedBase* instance)
|
||||
{
|
||||
return (instance && instance->getDescriptor().isA(T::classDescriptor())) ? static_cast<T*>(instance) : NULL;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static inline const T* fastDynamicCast(const DescribedBase* instance)
|
||||
{
|
||||
return (instance && instance->getDescriptor().isA(T::classDescriptor())) ? static_cast<const T*>(instance) : NULL;
|
||||
}
|
||||
|
||||
// This function replaces shared_dynamic_cast for classes that derives from DescribedCreatable or DescribedNonCreatable.
|
||||
template<class T, class U>
|
||||
static inline shared_ptr<T> fastSharedDynamicCast(const shared_ptr<U>& instance)
|
||||
{
|
||||
return isA<T>(instance.get()) ? shared_static_cast<T>(instance) : shared_ptr<T>();
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
// Convenience functions for getting members of a described object
|
||||
PropertyDescriptor* findPropertyDescriptor(const char* name)
|
||||
{
|
||||
return getDescriptor().MemberDescriptorContainer<PropertyDescriptor>::findDescriptor(name);
|
||||
}
|
||||
ConstPropertyIterator properties_begin() const {
|
||||
return getDescriptor().MemberDescriptorContainer<PropertyDescriptor>::members_begin(this);
|
||||
}
|
||||
ConstPropertyIterator properties_end() const {
|
||||
return getDescriptor().MemberDescriptorContainer<PropertyDescriptor>::members_end(this);
|
||||
}
|
||||
PropertyIterator properties_begin() {
|
||||
return getDescriptor().MemberDescriptorContainer<PropertyDescriptor>::members_begin(this);
|
||||
}
|
||||
PropertyIterator properties_end() {
|
||||
return getDescriptor().MemberDescriptorContainer<PropertyDescriptor>::members_end(this);
|
||||
}
|
||||
|
||||
FunctionDescriptor* findFunctionDescriptor(const char* name)
|
||||
{
|
||||
return getDescriptor().MemberDescriptorContainer<FunctionDescriptor>::findDescriptor(name);
|
||||
}
|
||||
FunctionIterator functions_begin() const {
|
||||
return getDescriptor().MemberDescriptorContainer<FunctionDescriptor>::members_begin(this);
|
||||
}
|
||||
FunctionIterator functions_end() const {
|
||||
return getDescriptor().MemberDescriptorContainer<FunctionDescriptor>::members_end(this);
|
||||
}
|
||||
|
||||
YieldFunctionDescriptor* findYieldFunctionDescriptor(const char* name) const
|
||||
{
|
||||
return getDescriptor().MemberDescriptorContainer<YieldFunctionDescriptor>::findDescriptor(name);
|
||||
}
|
||||
|
||||
YieldFunctionIterator yield_functions_begin() const {
|
||||
return getDescriptor().MemberDescriptorContainer<YieldFunctionDescriptor>::members_begin(this);
|
||||
}
|
||||
YieldFunctionIterator yield_functions_end() const {
|
||||
return getDescriptor().MemberDescriptorContainer<YieldFunctionDescriptor>::members_end(this);
|
||||
}
|
||||
|
||||
CallbackDescriptor* findCallbackDescriptor(const char* name)
|
||||
{
|
||||
return getDescriptor().MemberDescriptorContainer<CallbackDescriptor>::findDescriptor(name);
|
||||
}
|
||||
CallbackIterator callbacks_begin() {
|
||||
return getDescriptor().MemberDescriptorContainer<CallbackDescriptor>::members_begin(this);
|
||||
}
|
||||
CallbackIterator callbacks_end() {
|
||||
return getDescriptor().MemberDescriptorContainer<CallbackDescriptor>::members_end(this);
|
||||
}
|
||||
|
||||
EventDescriptor* findSignalDescriptor(const char* name) const
|
||||
{
|
||||
return getDescriptor().MemberDescriptorContainer<EventDescriptor>::findDescriptor(name);
|
||||
}
|
||||
|
||||
ConstSignalIterator signals_begin() const {
|
||||
return getDescriptor().MemberDescriptorContainer<EventDescriptor>::members_begin(this);
|
||||
}
|
||||
ConstSignalIterator signals_end() const {
|
||||
return getDescriptor().MemberDescriptorContainer<EventDescriptor>::members_end(this);
|
||||
}
|
||||
SignalIterator signals_begin() {
|
||||
return getDescriptor().MemberDescriptorContainer<EventDescriptor>::members_begin(this);
|
||||
}
|
||||
SignalIterator signals_end() {
|
||||
return getDescriptor().MemberDescriptorContainer<EventDescriptor>::members_end(this);
|
||||
}
|
||||
|
||||
const std::string* getXmlId() const {
|
||||
return xmlId.get();
|
||||
}
|
||||
|
||||
void setXmlId(const std::string& newId) {
|
||||
if (!xmlId)
|
||||
{
|
||||
xmlId.reset(new std::string(newId));
|
||||
}
|
||||
else
|
||||
{
|
||||
*xmlId = newId;
|
||||
}
|
||||
}
|
||||
|
||||
virtual const RBX::Name& getClassName() const = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "reflection/member.h"
|
||||
#include "reflection/enumconverter.h"
|
||||
#include "reflection/type.h"
|
||||
#include "v8xml/xmlelement.h"
|
||||
#include "V8Xml/Reference.h" // TODO: Reflection namespace should not know about V8Tree
|
||||
#include "boost/cast.hpp"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Reflection
|
||||
{
|
||||
class ConstProperty;
|
||||
class Property;
|
||||
|
||||
typedef enum {
|
||||
READONLY,
|
||||
READWRITE
|
||||
} Mutability;
|
||||
|
||||
// Base that describes a Property
|
||||
class RBXBaseClass PropertyDescriptor : public MemberDescriptor
|
||||
{
|
||||
private:
|
||||
unsigned bIsPublic : 1;
|
||||
unsigned bIsEditable : 1;
|
||||
unsigned bCanReplicate : 1;
|
||||
unsigned bCanXmlRead : 1;
|
||||
unsigned bCanXmlWrite : 1;
|
||||
unsigned bIsScriptable : 1;
|
||||
unsigned bAlwaysClone : 1;
|
||||
|
||||
public:
|
||||
typedef ConstProperty ConstMember;
|
||||
typedef Property Member;
|
||||
|
||||
public:
|
||||
// Note: isPublic == PropertyUI shown, and Can BaseScript against. ToDO: possibly split?
|
||||
|
||||
enum Functionality {
|
||||
STANDARD = 1 + 2 + 4 + 8 + 16, // isPublic, canReplicate, canXmlRead , canXmlWrite, isScriptable
|
||||
NO_XML_WRITE = 1 + 2 + 4 + 0 + 16, // isPublic, canReplicate, canXmlRead , , isScriptable
|
||||
UI = 1 + 0 +(4)+ 0 + 16, // isPublic, (canXmlRead), isScriptable //Remove canXmlRead from UI
|
||||
SCRIPTING = 1 + 2 + 0 + 0 + 16, // isPublic, canReplicate, isScriptable
|
||||
STREAMING = 0 + 2 + 4 + 8 + 0, // canReplicate, canXmlRead , canXmlWrite,
|
||||
CLUSTER = 0 + 0 + 4 + 8 + 0, // canXmlRead , canXmlWrite,
|
||||
LEGACY = 0 + 0 + 4 + 0 + 0, // canXmlRead ,
|
||||
REPLICATE_ONLY = 0 + 2 + 0 + 0 + 0, // canReplicate
|
||||
LEGACY_SCRIPTING = 0 + 0 + 4 + 0 + 16, // canXmlRead , isScriptable
|
||||
HIDDEN_SCRIPTING = 0 + 0 + 0 + 0 + 16, // isScriptable
|
||||
PUBLIC_SERIALIZED = 1 + 0 + 4 + 8 + 0, // isPublic, canXmlRead , canXmlWrite,
|
||||
REPLICATE_CLONE = 0 + 2 + 0 + 0 + 0 + 32, // canReplicate alwaysClone
|
||||
STANDARD_NO_REPLICATE = 1 + 0 + 4 + 8 + 16, // isPublic, canXmlRead , canXmlWrite, isScriptable
|
||||
STANDARD_NO_SCRIPTING = 1 + 2 + 4 + 8 + 0, // isPublic, canReplicate, canXmlRead , canXmlWrite
|
||||
PUBLIC_REPLICATE = 1 + 2 + 0 + 0 + 0, // isPublic, canReplicate
|
||||
};
|
||||
|
||||
struct Attributes : public Descriptor::Attributes
|
||||
{
|
||||
Functionality flags;
|
||||
|
||||
Attributes():flags(STANDARD) {}
|
||||
Attributes(Functionality flags):flags(flags) {}
|
||||
static Attributes deprecated(const MemberDescriptor& preferred, Functionality flags = UI);
|
||||
static Attributes deprecated(Functionality flags = UI);
|
||||
};
|
||||
|
||||
const Type& type;
|
||||
const bool bIsEnum;
|
||||
|
||||
protected:
|
||||
PropertyDescriptor(ClassDescriptor& classDescriptor, const Type& type, const char* name, const char* category, Attributes attributes, Security::Permissions security, bool isEnum = false);
|
||||
|
||||
inline void checkFlags()
|
||||
{
|
||||
if (isWriteOnly())
|
||||
{
|
||||
bCanXmlWrite = 0;
|
||||
bCanReplicate = 0;
|
||||
}
|
||||
if (isReadOnly())
|
||||
{
|
||||
bCanXmlRead = 0;
|
||||
bCanReplicate = 0;
|
||||
}
|
||||
}
|
||||
public:
|
||||
inline bool isPublic() const { return bIsPublic != 0; }
|
||||
inline bool isScriptable() const { return bIsScriptable != 0; }
|
||||
|
||||
void setEditable(bool editable) { bIsEditable = editable ? 1 : 0; }
|
||||
inline bool isEditable() const { return bIsEditable != 0; }
|
||||
|
||||
virtual bool isReadOnly() const = 0;
|
||||
virtual bool isWriteOnly() const = 0;
|
||||
inline bool canXmlRead() const
|
||||
{
|
||||
RBXASSERT(bCanXmlRead == 0 || !isReadOnly());
|
||||
return bCanXmlRead != 0;
|
||||
}
|
||||
inline bool canXmlWrite() const
|
||||
{
|
||||
RBXASSERT(bCanXmlWrite == 0 || !isWriteOnly());
|
||||
return bCanXmlWrite != 0;
|
||||
}
|
||||
inline bool canReplicate() const
|
||||
{
|
||||
RBXASSERT(bCanReplicate == 0 || (!isReadOnly() && !isWriteOnly()));
|
||||
return bCanReplicate != 0;
|
||||
}
|
||||
inline bool alwaysClone() const
|
||||
{
|
||||
return bAlwaysClone != 0;
|
||||
}
|
||||
|
||||
bool operator==(const PropertyDescriptor& other) const {
|
||||
return this == &other;
|
||||
}
|
||||
bool operator!=(const PropertyDescriptor& other) const {
|
||||
return this != &other;
|
||||
}
|
||||
|
||||
virtual bool equalValues(const DescribedBase* a, const DescribedBase* b) const = 0;
|
||||
|
||||
virtual void getVariant(const DescribedBase* instance, Variant& value) const = 0;
|
||||
virtual void setVariant(DescribedBase* instance, const Variant& value) const = 0;
|
||||
virtual void copyValue(const DescribedBase* source, DescribedBase* destination) const = 0;
|
||||
|
||||
virtual int getDataSize(const DescribedBase* instance) const = 0;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// String conversion interface
|
||||
public:
|
||||
virtual bool hasStringValue() const = 0;
|
||||
virtual std::string getStringValue(const DescribedBase* instance) const {
|
||||
if (hasStringValue())
|
||||
debugAssertM(false, "you must implement getStringValue");
|
||||
else
|
||||
debugAssertM(false, "don't call getStringValue when hasStringValue()==false");
|
||||
return "";
|
||||
}
|
||||
virtual bool setStringValue(DescribedBase* instance, const std::string& text) const {
|
||||
if (hasStringValue())
|
||||
debugAssertM(false, "you must implement setStringValue");
|
||||
else
|
||||
debugAssertM(false, "don't call setStringValue when hasStringValue()==false");
|
||||
return false;
|
||||
}
|
||||
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Xml streaming interface
|
||||
public:
|
||||
XmlElement* write(const DescribedBase* instance, bool ignoreWriteProtection = false) const;
|
||||
virtual void read(DescribedBase* instance, const XmlElement* element, RBX::IReferenceBinder& binder) const;
|
||||
private:
|
||||
virtual void writeValue(const DescribedBase* instance, XmlElement* element) const = 0;
|
||||
virtual void readValue(DescribedBase* instance, const XmlElement* element, RBX::IReferenceBinder& binder) const = 0;
|
||||
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename V>
|
||||
class TypedPropertyDescriptor : public PropertyDescriptor
|
||||
{
|
||||
private:
|
||||
typedef PropertyDescriptor Super;
|
||||
|
||||
public:
|
||||
class RBXInterface GetSet
|
||||
{
|
||||
public:
|
||||
virtual bool isReadOnly() const = 0;
|
||||
virtual bool isWriteOnly() const = 0;
|
||||
virtual V getValue(const DescribedBase* object) const = 0;
|
||||
virtual void setValue(DescribedBase* object, const V& value) const = 0;
|
||||
};
|
||||
protected:
|
||||
std::auto_ptr<GetSet> getset;
|
||||
TypedPropertyDescriptor(ClassDescriptor& classDescriptor, const Type& type, const char* name, const char* category, std::auto_ptr<GetSet> getset, Attributes flags, Security::Permissions security)
|
||||
:PropertyDescriptor(classDescriptor, type, name, category, flags, security),getset(getset)
|
||||
{
|
||||
if (this->getset.get())
|
||||
this->checkFlags();
|
||||
}
|
||||
TypedPropertyDescriptor(ClassDescriptor& classDescriptor, const char* name, const char* category, std::auto_ptr<GetSet> getset, Attributes flags, Security::Permissions security)
|
||||
:PropertyDescriptor(classDescriptor, Type::singleton<V>(), name, category, flags, security),getset(getset)
|
||||
{
|
||||
if (this->getset.get())
|
||||
this->checkFlags();
|
||||
}
|
||||
public:
|
||||
/*implement*/ V get(const DescribedBase* instance) const
|
||||
{
|
||||
return getset->getValue(instance);
|
||||
}
|
||||
/*implement*/ void set(DescribedBase* instance, const V& value) const
|
||||
{
|
||||
getset->setValue(instance, value);
|
||||
}
|
||||
|
||||
/*implement*/ void getVariant(const DescribedBase* instance, Variant& value) const
|
||||
{
|
||||
value = getset->getValue(instance);
|
||||
}
|
||||
/*implement*/ void setVariant(DescribedBase* instance, const Variant& value) const
|
||||
{
|
||||
// TODO: This might be inefficient. How is the value stored in getset???
|
||||
getset->setValue(instance, value.get<V>());
|
||||
}
|
||||
/*implement*/ void copyValue(const DescribedBase* source, DescribedBase* destination) const
|
||||
{
|
||||
set(destination, get(source));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Variant interface
|
||||
public:
|
||||
virtual bool isReadOnly() const {
|
||||
return getset->isReadOnly();
|
||||
}
|
||||
|
||||
virtual bool isWriteOnly() const {
|
||||
return getset->isWriteOnly();
|
||||
}
|
||||
|
||||
V getValue(const DescribedBase* object) const {
|
||||
return getset->getValue(object);
|
||||
}
|
||||
|
||||
void setValue(DescribedBase* object, const V& value) const {
|
||||
getset->setValue(object, value);
|
||||
}
|
||||
|
||||
/*implement*/ bool equalValues(const DescribedBase* a, const DescribedBase* b) const {
|
||||
return getValue(a) == getValue(b);
|
||||
}
|
||||
|
||||
virtual int getDataSize(const DescribedBase* instance) const;
|
||||
|
||||
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/
|
||||
|
||||
virtual bool hasStringValue() const;
|
||||
virtual std::string getStringValue(const DescribedBase* instance) const;
|
||||
virtual bool setStringValue(DescribedBase* instance, const std::string& text) const;
|
||||
private:
|
||||
virtual void readValue(DescribedBase* instance, const XmlElement* element, IReferenceBinder& binder) const;
|
||||
virtual void writeValue(const DescribedBase* instance, XmlElement* element) const;
|
||||
};
|
||||
|
||||
// A light-weight convenience class that associates a PropertyDescriptor
|
||||
// with a described object to create a "Property"
|
||||
class ConstProperty
|
||||
{
|
||||
protected:
|
||||
const PropertyDescriptor* descriptor;
|
||||
const DescribedBase* instance;
|
||||
public:
|
||||
inline ConstProperty():descriptor(0),instance(0) {}
|
||||
inline ConstProperty(const PropertyDescriptor& descriptor, const DescribedBase* instance)
|
||||
:descriptor(&descriptor),instance(instance)
|
||||
{
|
||||
RBXASSERT(!instance || descriptor.isMemberOf(instance));
|
||||
}
|
||||
|
||||
inline ConstProperty(const ConstProperty& other)
|
||||
:descriptor(other.descriptor),instance(other.instance)
|
||||
{}
|
||||
|
||||
inline const DescribedBase* getInstance() const { return instance; }
|
||||
inline const PropertyDescriptor& getDescriptor() const { return *descriptor; }
|
||||
|
||||
inline ConstProperty& operator =(const ConstProperty& other)
|
||||
{
|
||||
this->descriptor = other.descriptor;
|
||||
this->instance = other.instance;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool operator ==(const ConstProperty& other) const
|
||||
{
|
||||
return (this->descriptor == other.descriptor) && (this->instance == other.instance);
|
||||
}
|
||||
|
||||
inline const RBX::Name& getName() const {
|
||||
return descriptor->name;
|
||||
}
|
||||
|
||||
template<typename V>
|
||||
inline bool isValueType() const
|
||||
{
|
||||
return descriptor->type==Type::singleton<V>();
|
||||
}
|
||||
template<typename V>
|
||||
inline V getValue() const
|
||||
{
|
||||
RBXASSERT(isValueType<V>());
|
||||
return static_cast<const TypedPropertyDescriptor<V>*>(descriptor)->getValue(instance);
|
||||
}
|
||||
|
||||
inline bool hasStringValue() const
|
||||
{
|
||||
return descriptor->hasStringValue();
|
||||
}
|
||||
inline std::string getStringValue() const
|
||||
{
|
||||
return descriptor->getStringValue(instance);
|
||||
}
|
||||
|
||||
inline XmlElement* write() const
|
||||
{
|
||||
return descriptor->write(instance);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// A light-weight convenience class that associates a PropertyDescriptor
|
||||
// with a described object to create a "Property"
|
||||
class Property : public ConstProperty
|
||||
{
|
||||
public:
|
||||
inline Property(const PropertyDescriptor& descriptor, DescribedBase* instance)
|
||||
:ConstProperty(descriptor, instance)
|
||||
{}
|
||||
inline Property(const Property& other)
|
||||
:ConstProperty(*other.descriptor, other.instance)
|
||||
{}
|
||||
inline Property& operator =(const Property& other)
|
||||
{
|
||||
this->descriptor = other.descriptor;
|
||||
this->instance = other.instance;
|
||||
return *this;
|
||||
}
|
||||
inline bool operator ==(const Property& other) const
|
||||
{
|
||||
return this->descriptor==other.descriptor && this->instance==other.instance;
|
||||
}
|
||||
|
||||
inline bool operator !=(const Property& other) const
|
||||
{
|
||||
return this->descriptor!=other.descriptor || this->instance!=other.instance;
|
||||
}
|
||||
|
||||
DescribedBase* getInstance() const { return const_cast<DescribedBase*>(instance); }
|
||||
|
||||
template<typename V>
|
||||
inline void setValue(const V& value)
|
||||
{
|
||||
RBXASSERT(isValueType<V>());
|
||||
static_cast<const TypedPropertyDescriptor<V>*>(descriptor)->setValue(const_cast<DescribedBase*>(instance), value);
|
||||
}
|
||||
|
||||
inline bool setStringValue(const std::string& text)
|
||||
{
|
||||
return descriptor->setStringValue(const_cast<DescribedBase*>(instance), text);
|
||||
}
|
||||
|
||||
inline void read(const XmlElement* element, RBX::IReferenceBinder& binder)
|
||||
{
|
||||
descriptor->read(const_cast<DescribedBase*>(instance), element, binder);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
std::size_t hash_value(const ConstProperty& prop);
|
||||
|
||||
// Interface
|
||||
// maps enums to an index (Used by UIs like a property grid)
|
||||
class RBXInterface EnumPropertyDescriptor : public PropertyDescriptor {
|
||||
public:
|
||||
const EnumDescriptor& enumDescriptor;
|
||||
virtual size_t getIndexValue(const DescribedBase* instance) const = 0;
|
||||
virtual bool setIndexValue(DescribedBase* instance, size_t value) const = 0; // throws an exception if value is illegal
|
||||
virtual int getEnumValue(const DescribedBase* instance) const = 0;
|
||||
virtual bool setEnumValue(DescribedBase* instance, int index) const = 0;
|
||||
virtual const EnumDescriptor::Item* getEnumItem(const DescribedBase* instance) const = 0;
|
||||
bool setEnumItem(DescribedBase* instance, const EnumDescriptor::Item& item) const {
|
||||
if (item.owner!=enumDescriptor)
|
||||
return false;
|
||||
return setEnumValue(instance, item.value);
|
||||
}
|
||||
virtual int getDataSize(const DescribedBase* instance) const
|
||||
{ return sizeof(int); }
|
||||
protected:
|
||||
EnumPropertyDescriptor(ClassDescriptor& classDescriptor, const EnumDescriptor& enumDescriptor, const char* name, const char* category, Attributes flags = STANDARD, Security::Permissions security=Security::None)
|
||||
:PropertyDescriptor(classDescriptor, enumDescriptor, name, category, flags, security, true)
|
||||
,enumDescriptor(enumDescriptor)
|
||||
{}
|
||||
};
|
||||
|
||||
class RBXBaseClass RefPropertyDescriptor : public PropertyDescriptor {
|
||||
|
||||
private:
|
||||
typedef PropertyDescriptor Super;
|
||||
|
||||
public:
|
||||
virtual DescribedBase* getRefValue(const DescribedBase* instance) const = 0;
|
||||
virtual void setRefValue(DescribedBase* instance, DescribedBase* value) const = 0;
|
||||
virtual void setRefValueUnsafe(DescribedBase* instance, DescribedBase* value) const = 0;
|
||||
|
||||
RefPropertyDescriptor(ClassDescriptor& classDescriptor, const Type& type, const char* name, const char* category, Attributes flags = STANDARD, Security::Permissions security=Security::None)
|
||||
:PropertyDescriptor(classDescriptor, type, name, category, flags, security)
|
||||
{}
|
||||
|
||||
virtual int getDataSize(const DescribedBase* instance) const
|
||||
{ return 0; }
|
||||
|
||||
bool hasStringValue() const {
|
||||
return false;
|
||||
}
|
||||
std::string getStringValue(const DescribedBase* instance) const{
|
||||
return Super::getStringValue(instance);
|
||||
}
|
||||
bool setStringValue(DescribedBase* instance, const std::string& text) const {
|
||||
return Super::setStringValue(instance, text);
|
||||
}
|
||||
|
||||
|
||||
static bool isRefPropertyDescriptor(const Reflection::Type& type)
|
||||
{
|
||||
static const RBX::Name& name = RBX::Name::lookup("Object");
|
||||
return (type.name == name);
|
||||
}
|
||||
|
||||
static bool isRefPropertyDescriptor(const PropertyDescriptor& descriptor)
|
||||
{
|
||||
// See RefType in reflection.h
|
||||
bool result = isRefPropertyDescriptor(descriptor.type);
|
||||
RBXASSERT(result == (0 != dynamic_cast<const Reflection::RefPropertyDescriptor*>(&descriptor)));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// A very useful class for binding Instance members to PropertyDescriptors
|
||||
template<typename V, Mutability mutability = READWRITE>
|
||||
class BoundProp : public Reflection::TypedPropertyDescriptor<V>
|
||||
{
|
||||
template<class Class>
|
||||
class BoundPropGetSet : public TypedPropertyDescriptor<V>::GetSet
|
||||
{
|
||||
BoundProp& desc;
|
||||
V Class::*member;
|
||||
typedef void (Class::*ChangedMember)(const Reflection::PropertyDescriptor&);
|
||||
ChangedMember changed;
|
||||
public:
|
||||
BoundPropGetSet(BoundProp& desc, V Class::*member, ChangedMember changed):desc(desc),member(member),changed(changed) {}
|
||||
virtual bool isReadOnly() const {
|
||||
return mutability == READONLY;
|
||||
}
|
||||
virtual bool isWriteOnly() const {
|
||||
return false;
|
||||
}
|
||||
virtual V getValue(const Reflection::DescribedBase* object) const {
|
||||
const Class* c = static_cast<const Class*>(object);
|
||||
return c->*member;
|
||||
}
|
||||
virtual void setValue(Reflection::DescribedBase* object, const V& value) const {
|
||||
if (mutability == READONLY)
|
||||
throw std::runtime_error("can't set value");
|
||||
|
||||
Class* c = static_cast<Class*>(object);
|
||||
if (c->*member != value)
|
||||
{
|
||||
c->*member = value;
|
||||
if (changed)
|
||||
(c->*changed)(desc);
|
||||
c->raisePropertyChanged(desc);
|
||||
}
|
||||
}
|
||||
};
|
||||
public:
|
||||
template<class Class>
|
||||
BoundProp(const char* name, const char* category, V Class::*member, void (Class::*changed)(const Reflection::PropertyDescriptor&), typename PropertyDescriptor::Attributes flags = PropertyDescriptor::STANDARD, Security::Permissions security = Security::None)
|
||||
:Reflection::TypedPropertyDescriptor<V>(Class::classDescriptor(), name, category, std::auto_ptr<typename TypedPropertyDescriptor<V>::GetSet>(), flags, security)
|
||||
{
|
||||
this->getset.reset(new BoundPropGetSet<Class>(*this, member, changed));
|
||||
this->checkFlags();
|
||||
}
|
||||
template<class Class>
|
||||
BoundProp(const char* name, const char* category, V Class::*member, typename PropertyDescriptor::Attributes flags = PropertyDescriptor::STANDARD, Security::Permissions security = Security::None)
|
||||
:Reflection::TypedPropertyDescriptor<V>(Class::classDescriptor(), name, category, std::auto_ptr<typename TypedPropertyDescriptor<V>::GetSet>(), flags, security)
|
||||
{
|
||||
this->getset.reset(new BoundPropGetSet<Class>(*this, member, NULL));
|
||||
this->checkFlags();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "reflection/Descriptor.h"
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <util/utilities.h>
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <list>
|
||||
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Reflection
|
||||
{
|
||||
template<typename T> class TypeRegistrar;
|
||||
|
||||
// Types supported by the Reflection framework
|
||||
class Type : public Descriptor
|
||||
{
|
||||
template<class T>
|
||||
friend class TypeRegistrar;
|
||||
|
||||
template<class T>
|
||||
static const Type& getSingleton(); // Must be implemented for each type used
|
||||
void addToAllTypes();
|
||||
|
||||
public:
|
||||
const Name& tag;
|
||||
const bool isFloat;
|
||||
const bool isNumber;
|
||||
const bool isEnum;
|
||||
|
||||
static const std::vector<const Type*>& getAllTypes();
|
||||
|
||||
template<class T>
|
||||
static inline const Type& singleton()
|
||||
{
|
||||
return getSingleton<T>();
|
||||
}
|
||||
|
||||
bool operator==(const Type& right) const {
|
||||
return this==&right;
|
||||
}
|
||||
bool operator!=(const Type& right) const {
|
||||
return this!=&right;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool isType() const {
|
||||
return this == &getSingleton<T>();
|
||||
}
|
||||
|
||||
protected:
|
||||
template<class T>
|
||||
Type(const char* name, T* dummy)
|
||||
:Descriptor(name, Descriptor::Attributes())
|
||||
,tag(Name::lookup(name))
|
||||
,isNumber(boost::is_arithmetic<T>::value)
|
||||
,isFloat(boost::is_float<T>::value)
|
||||
,isEnum(false)
|
||||
{
|
||||
*isOutdated = false;
|
||||
*isReplicable = true;
|
||||
RBXASSERT(!this->tag.empty());
|
||||
addToAllTypes();
|
||||
}
|
||||
template<class T>
|
||||
Type(const char* name, const char* tag, T* dummy)
|
||||
:Descriptor(name, Descriptor::Attributes())
|
||||
,tag(Name::declare(tag))
|
||||
,isNumber(boost::is_arithmetic<T>::value)
|
||||
,isFloat(boost::is_float<T>::value)
|
||||
,isEnum(false)
|
||||
{
|
||||
RBXASSERT(!this->tag.empty());
|
||||
addToAllTypes();
|
||||
}
|
||||
|
||||
Type(const char* name, const char* tag, bool isNumber, bool isFloat, bool isEnum)
|
||||
:Descriptor(name, Descriptor::Attributes())
|
||||
,tag(Name::declare(tag))
|
||||
,isNumber(isNumber)
|
||||
,isFloat(isFloat)
|
||||
,isEnum(isEnum)
|
||||
{
|
||||
RBXASSERT(!this->tag.empty());
|
||||
addToAllTypes();
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const RBX::Reflection::Type& type);
|
||||
|
||||
// Handy macro for registering a type
|
||||
#define RBX_REGISTER_TYPE(mType) template<> RBX::Reflection::TypeRegistrar<mType> RBX::Reflection::TypeRegistrar<mType>::registrar(0)
|
||||
|
||||
// This class is designed to prevent clients of the library
|
||||
// from forgetting to initialize their class descriptors
|
||||
template<class T>
|
||||
class TypeRegistrar : boost::noncopyable
|
||||
{
|
||||
int x;
|
||||
|
||||
//// GCC does not generate the registrar variable defination & fails at Link Time. Force Construct by passing in an dummy arg to ctor. That works. WEIRD huh?
|
||||
TypeRegistrar(int i):x(i)
|
||||
{
|
||||
// This assertion is added to catch a nasty implicit use of boost::any with Variant objects.
|
||||
// If you get a tricky link error, add your own assertion here
|
||||
BOOST_STATIC_ASSERT((!boost::is_same<T, boost::any>::value));
|
||||
// This call registers the Type descriptor
|
||||
// in the reflection database
|
||||
Type::getSingleton<T>();
|
||||
}
|
||||
|
||||
public:
|
||||
// The instantiation of this static member must be in a unit
|
||||
// that is initialized in the main thread before any objects
|
||||
// are created. Otherwise the reflection database
|
||||
// can change at runtime, which would be a disaster
|
||||
static TypeRegistrar registrar;
|
||||
};
|
||||
|
||||
// Helper class
|
||||
template<typename T>
|
||||
class TType : public Type
|
||||
{
|
||||
friend class Type;
|
||||
protected:
|
||||
TType(const char* name)
|
||||
:Type(name, (T*)NULL)
|
||||
{
|
||||
}
|
||||
TType(const char* name, const char* tag)
|
||||
:Type(name, tag, (T*)NULL)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class Variant
|
||||
{
|
||||
struct Storage
|
||||
{
|
||||
char data[96];
|
||||
};
|
||||
|
||||
const Type* _type;
|
||||
rbx::placement_any<Storage> value;
|
||||
|
||||
public:
|
||||
inline Variant()
|
||||
: _type(&Type::singleton<void>())
|
||||
, value()
|
||||
{}
|
||||
|
||||
inline Variant(const Variant& other)
|
||||
: _type(other._type)
|
||||
, value(other.value)
|
||||
{}
|
||||
|
||||
inline Variant& operator=(const Variant& rhs)
|
||||
{
|
||||
_type = rhs._type;
|
||||
value = rhs.value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
inline Variant(const ValueType& value)
|
||||
: _type(&Type::singleton<ValueType>())
|
||||
, value(value)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
inline Variant& operator=(const ValueType& rhs)
|
||||
{
|
||||
_type = &Type::singleton<ValueType>();
|
||||
value = rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const Type& type() const {
|
||||
return *_type;
|
||||
}
|
||||
|
||||
inline bool isVoid() const
|
||||
{
|
||||
return *_type==Type::singleton<void>();
|
||||
}
|
||||
inline bool isFloat() const { return type().isFloat; }
|
||||
inline bool isNumber() const { return type().isNumber; }
|
||||
inline bool isString() const { return isType<std::string>();}
|
||||
|
||||
template<class ValueType>
|
||||
inline bool isType() const {
|
||||
return _type->isType<ValueType>();
|
||||
}
|
||||
|
||||
// throws an exception if unable to convert
|
||||
template<typename ValueType>
|
||||
ValueType& convert();
|
||||
|
||||
// throws an exception if unable to convert
|
||||
template<typename ValueType>
|
||||
inline ValueType get() const
|
||||
{
|
||||
if (isType<ValueType>())
|
||||
return cast<ValueType>();
|
||||
else
|
||||
{
|
||||
// Create a non-const copy to extract the value from
|
||||
Variant v(*this);
|
||||
return v.convert<ValueType>();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline const T& cast() const {
|
||||
if (!isType<T>())
|
||||
throw std::runtime_error("Variant cast failed");
|
||||
return *reinterpret_cast<const T*>(value.getData());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T& cast() {
|
||||
if (!isType<T>())
|
||||
throw std::runtime_error("Variant cast failed");
|
||||
return *reinterpret_cast<T*>(value.getData());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline const T* tryCast() const {
|
||||
if (!isType<T>())
|
||||
return NULL;
|
||||
return reinterpret_cast<const T*>(value.getData());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T* tryCast() {
|
||||
if (!isType<T>())
|
||||
return NULL;
|
||||
return reinterpret_cast<T*>(value.getData());
|
||||
}
|
||||
|
||||
private:
|
||||
template<class ValueType>
|
||||
ValueType& genericConvert();
|
||||
|
||||
};
|
||||
|
||||
// Equivalent to an array in Lua
|
||||
typedef std::vector<Variant> ValueArray;
|
||||
|
||||
// A limited table in Lua (keys must be strings for now)
|
||||
typedef boost::unordered_map<std::string, Variant> ValueTable;
|
||||
|
||||
struct Tuple
|
||||
{
|
||||
ValueArray values;
|
||||
Tuple() {}
|
||||
Tuple(size_t count):values(count) {}
|
||||
Tuple(const Tuple& other):values(other.values) {}
|
||||
//Tuple(const ValueArray& values):values(values) {}
|
||||
Variant& at(size_t i) { return values[i]; }
|
||||
const Variant& at(size_t i) const { return values[i]; }
|
||||
};
|
||||
|
||||
// The same as a ValueTable for now, but will always have a string key.
|
||||
// TODO: Use boost::unordered_map<> or vector<> instead?
|
||||
typedef std::map<std::string, Variant> ValueMap;
|
||||
|
||||
// Describes a function's signature
|
||||
class SignatureDescriptor
|
||||
{
|
||||
public:
|
||||
struct Item {
|
||||
friend class SignatureDescriptor;
|
||||
public:
|
||||
Item(const RBX::Name* name, const Type* type, const Variant& defaultValue);
|
||||
Item(const RBX::Name* name, const Type* type);
|
||||
const RBX::Name* name;
|
||||
const Type* type;
|
||||
const Variant defaultValue;
|
||||
bool hasDefaultValue() const
|
||||
{
|
||||
return defaultValue.type() == *type;
|
||||
}
|
||||
};
|
||||
// TODO: Would vector be more efficient?
|
||||
typedef std::list<Item> Arguments;
|
||||
|
||||
const Type* resultType;
|
||||
Arguments arguments;
|
||||
|
||||
void addArgument(const RBX::Name& name, const Type& type);
|
||||
void addArgument(const RBX::Name& name, const Type& type, const Variant& defaultValue);
|
||||
|
||||
SignatureDescriptor();
|
||||
};
|
||||
|
||||
template<class ValueType>
|
||||
ValueType& RBX::Reflection::Variant::genericConvert()
|
||||
{
|
||||
ValueType* id = tryCast<ValueType>();
|
||||
if (id!=NULL)
|
||||
return *id;
|
||||
|
||||
if (_type->isType<std::string>())
|
||||
{
|
||||
ValueType v;
|
||||
if (StringConverter<ValueType>::convertToValue(cast<std::string>(), v))
|
||||
{
|
||||
value = v;
|
||||
_type = &Type::singleton<ValueType>();
|
||||
return cast<ValueType>();
|
||||
}
|
||||
}
|
||||
|
||||
throw RBX::runtime_error("Unable to cast %s to %s", _type->tag.c_str(), Type::singleton<ValueType>().tag.c_str() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#include "Reflection/Function.h"
|
||||
#include <boost/function.hpp>
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Reflection
|
||||
{
|
||||
class YieldFunction;
|
||||
|
||||
// Base that describes a YieldFunction
|
||||
class RBXBaseClass YieldFunctionDescriptor : public MemberDescriptor
|
||||
{
|
||||
public:
|
||||
|
||||
typedef YieldFunction ConstMember;
|
||||
typedef YieldFunction Member;
|
||||
|
||||
protected:
|
||||
SignatureDescriptor signature;
|
||||
YieldFunctionDescriptor(ClassDescriptor& classDescriptor, const char* name, Security::Permissions security, Attributes attributes);
|
||||
|
||||
public:
|
||||
const SignatureDescriptor& getSignature() const { return signature; }
|
||||
virtual void execute(DescribedBase* instance, FunctionDescriptor::Arguments& arguments, boost::function<void(Variant)> resumeFunction, boost::function<void(std::string)> errorFunction) const = 0;
|
||||
};
|
||||
|
||||
|
||||
// A light-weight convenience class that associates a FunctionDescriptor
|
||||
// with a described object to create a "Function"
|
||||
class YieldFunction
|
||||
{
|
||||
protected:
|
||||
const YieldFunctionDescriptor* descriptor;
|
||||
DescribedBase* instance;
|
||||
public:
|
||||
inline YieldFunction(const YieldFunctionDescriptor& descriptor, DescribedBase* instance)
|
||||
:descriptor(&descriptor),instance(instance)
|
||||
{}
|
||||
|
||||
inline YieldFunction(const YieldFunction& other)
|
||||
:descriptor(other.descriptor),instance(other.instance)
|
||||
{}
|
||||
inline YieldFunction& operator =(const YieldFunction& other)
|
||||
{
|
||||
this->descriptor = other.descriptor;
|
||||
this->instance = other.instance;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const RBX::Name& getName() const {
|
||||
return descriptor->name;
|
||||
}
|
||||
|
||||
inline const YieldFunctionDescriptor* getDescriptor() const {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
void execute(FunctionDescriptor::Arguments& arguments, boost::function<void(Variant)> resumeFunction, boost::function<void(std::string)> errorFunction) const {
|
||||
return descriptor->execute(const_cast<DescribedBase*>(instance), arguments, resumeFunction, errorFunction);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,353 @@
|
||||
#pragma once
|
||||
|
||||
#include "reflection/Descriptor.h"
|
||||
#include "util/Exception.h"
|
||||
#include <vector>
|
||||
#include "security/SecurityContext.h"
|
||||
|
||||
#include "rbx/DenseHash.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Reflection
|
||||
{
|
||||
class ClassDescriptor;
|
||||
class DescribedBase;
|
||||
|
||||
struct StringHashPredicate
|
||||
{
|
||||
size_t operator()(const char* s) const;
|
||||
};
|
||||
|
||||
struct StringEqualPredicate
|
||||
{
|
||||
bool operator()(const char* lhs, const char* rhs) const
|
||||
{
|
||||
return strcmp(lhs, rhs) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Base class of describing a described object's member: (Member, Event, etc.)
|
||||
class RBXBaseClass MemberDescriptor : public Descriptor
|
||||
{
|
||||
public:
|
||||
static void (*memberHidingHook)(MemberDescriptor*, MemberDescriptor*);
|
||||
|
||||
// Category is a name used to group properties in the UI
|
||||
const RBX::Name& category;
|
||||
|
||||
const ClassDescriptor& owner;
|
||||
const Security::Permissions security;
|
||||
|
||||
protected:
|
||||
MemberDescriptor(const ClassDescriptor& owner, const char* name, const char* category, Attributes attributes, Security::Permissions security)
|
||||
:Descriptor(name, attributes)
|
||||
,owner(owner)
|
||||
,category(RBX::Name::declare(category))
|
||||
,security(security)
|
||||
{
|
||||
}
|
||||
virtual ~MemberDescriptor() {}
|
||||
public:
|
||||
bool isMemberOf(const ClassDescriptor& classDescriptor) const;
|
||||
bool isMemberOf(const DescribedBase* instance) const;
|
||||
};
|
||||
|
||||
|
||||
class MemberException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
const MemberDescriptor& desc;
|
||||
MemberException(const MemberDescriptor& desc, const std::string& _Message)
|
||||
:std::runtime_error(_Message)
|
||||
,desc(desc)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template<class MemberDescriptorType>
|
||||
class MemberDescriptorContainer
|
||||
{
|
||||
// Used for sorting
|
||||
static bool compare(const MemberDescriptorType* a, const MemberDescriptorType* b)
|
||||
{
|
||||
return a->name < b->name;
|
||||
}
|
||||
public:
|
||||
class Collection : public std::vector<MemberDescriptorType*>
|
||||
{
|
||||
};
|
||||
|
||||
typedef DenseHashMap<const char*, MemberDescriptorType*, StringHashPredicate, StringEqualPredicate> DescriptorLookup;
|
||||
|
||||
typedef typename MemberDescriptorType::ConstMember ConstMemberType;
|
||||
typedef typename MemberDescriptorType::Member MemberType;
|
||||
class ConstIterator : public std::iterator<std::forward_iterator_tag, MemberType, void, MemberType>
|
||||
{
|
||||
friend class ClassDescriptor;
|
||||
const DescribedBase* instance;
|
||||
typename Collection::const_iterator iter;
|
||||
public:
|
||||
ConstIterator(const typename Collection::const_iterator& iter, const DescribedBase* instance)
|
||||
:iter(iter),instance(instance)
|
||||
{}
|
||||
ConstMemberType operator*() const
|
||||
{ // return designated object
|
||||
return ConstMemberType(**iter, instance);
|
||||
}
|
||||
|
||||
bool operator==(const ConstIterator& other) const { return iter==other.iter; }
|
||||
bool operator!=(const ConstIterator& other) const { return iter!=other.iter; }
|
||||
ConstIterator& operator++()
|
||||
{ // preincrement
|
||||
++iter;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
ConstIterator operator++(int)
|
||||
{ // postincrement
|
||||
ConstIterator _Tmp = *this;
|
||||
++*this;
|
||||
return (_Tmp);
|
||||
}
|
||||
|
||||
const MemberDescriptorType& getDescriptor() const { return **iter; }
|
||||
};
|
||||
|
||||
class Iterator : public std::iterator<std::forward_iterator_tag, MemberType, void, MemberType>
|
||||
{
|
||||
friend class ClassDescriptor;
|
||||
DescribedBase* instance;
|
||||
// iter is a const iterator, since we never modifiy the collection of descriptors
|
||||
typename Collection::const_iterator iter;
|
||||
public:
|
||||
Iterator(const typename Collection::const_iterator& iter, DescribedBase* instance)
|
||||
:iter(iter),instance(instance)
|
||||
{}
|
||||
MemberType operator*() const
|
||||
{ // return designated object
|
||||
return MemberType(**iter, instance);
|
||||
}
|
||||
|
||||
bool operator==(const Iterator& other) const { return iter==other.iter; }
|
||||
bool operator!=(const Iterator& other) const { return iter!=other.iter; }
|
||||
Iterator& operator++()
|
||||
{ // preincrement
|
||||
++iter;
|
||||
return (*this);
|
||||
}
|
||||
|
||||
Iterator operator++(int)
|
||||
{ // postincrement
|
||||
Iterator _Tmp = *this;
|
||||
++*this;
|
||||
return (_Tmp);
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
Collection descriptors;
|
||||
DescriptorLookup descriptorLookup;
|
||||
private:
|
||||
static Collection& staticData()
|
||||
{
|
||||
static Collection result;
|
||||
return result;
|
||||
}
|
||||
static void initStaticData()
|
||||
{
|
||||
staticData();
|
||||
}
|
||||
static Collection& allDescriptors()
|
||||
{
|
||||
static boost::once_flag flag = BOOST_ONCE_INIT;
|
||||
boost::call_once(&initStaticData, flag);
|
||||
return staticData();
|
||||
}
|
||||
|
||||
protected:
|
||||
// This is a list of "subclasses"
|
||||
std::vector<MemberDescriptorContainer*> derivedContainers;
|
||||
|
||||
MemberDescriptorContainer* const base;
|
||||
protected:
|
||||
MemberDescriptorContainer(MemberDescriptorContainer* base)
|
||||
:base(base), descriptorLookup("")
|
||||
{
|
||||
if (base!=NULL)
|
||||
{
|
||||
// Grab base members that have already been declared
|
||||
mergeMembers(base);
|
||||
|
||||
// Subsequent members declared in a base class will be pushed down in the declare() function
|
||||
base->derivedContainers.push_back(this);
|
||||
}
|
||||
}
|
||||
|
||||
void declareSub(MemberDescriptorType* descriptor, MemberDescriptorType* replaceable)
|
||||
{
|
||||
RBXASSERT(replaceable != descriptor);
|
||||
{
|
||||
typename Collection::iterator iter = std::lower_bound(descriptors.begin(), descriptors.end(), descriptor, compare);
|
||||
if (iter == descriptors.end())
|
||||
{
|
||||
descriptors.insert(iter, descriptor);
|
||||
descriptorLookup[descriptor->name.c_str()] = descriptor;
|
||||
}
|
||||
else
|
||||
{
|
||||
RBXASSERT(*iter != descriptor);
|
||||
|
||||
if (*iter == replaceable)
|
||||
{
|
||||
// Replace it
|
||||
*iter = descriptor;
|
||||
descriptorLookup[descriptor->name.c_str()] = descriptor;
|
||||
}
|
||||
else if ((*iter)->name != descriptor->name)
|
||||
{
|
||||
descriptors.insert(iter, descriptor);
|
||||
descriptorLookup[descriptor->name.c_str()] = descriptor;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We've hit upon a member that will hide this member
|
||||
if (MemberDescriptor::memberHidingHook)
|
||||
(*MemberDescriptor::memberHidingHook)(descriptor, replaceable);
|
||||
return; // No need to continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// recurse:
|
||||
for (typename std::vector<MemberDescriptorContainer*>::iterator iter = derivedContainers.begin(); iter != derivedContainers.end(); ++iter)
|
||||
(*iter)->declareSub(descriptor, replaceable);
|
||||
}
|
||||
public:
|
||||
void declare(MemberDescriptorType* descriptor)
|
||||
{
|
||||
MemberDescriptorType* replaceable = NULL;
|
||||
|
||||
{
|
||||
typename Collection::iterator iter = std::lower_bound(descriptors.begin(), descriptors.end(), descriptor, compare);
|
||||
if (iter == descriptors.end())
|
||||
{
|
||||
// add a new one
|
||||
descriptors.insert(iter, descriptor);
|
||||
descriptorLookup[descriptor->name.c_str()] = descriptor;
|
||||
}
|
||||
else if (*iter == descriptor)
|
||||
{
|
||||
// drop out if we've been here before
|
||||
return;
|
||||
}
|
||||
else if ((*iter)->name != descriptor->name)
|
||||
{
|
||||
// add a new one
|
||||
descriptors.insert(iter, descriptor);
|
||||
descriptorLookup[descriptor->name.c_str()] = descriptor;
|
||||
}
|
||||
else
|
||||
{
|
||||
// hide a member of a base class
|
||||
// TODO: Eventually we'd like to nuke this feature, but it is
|
||||
// required for some legacy things, like BoolValue
|
||||
replaceable = *iter;
|
||||
*iter = descriptor;
|
||||
descriptorLookup[descriptor->name.c_str()] = descriptor;
|
||||
if (MemberDescriptor::memberHidingHook)
|
||||
(*MemberDescriptor::memberHidingHook)(descriptor, replaceable);
|
||||
}
|
||||
}
|
||||
|
||||
// Also declare this member in sub-classes
|
||||
for (typename std::vector<MemberDescriptorContainer*>::iterator iter = derivedContainers.begin(); iter != derivedContainers.end(); ++iter)
|
||||
(*iter)->declareSub(descriptor, replaceable);
|
||||
|
||||
// Add this to allDescriptors (in a determanistic order)
|
||||
{
|
||||
typename Collection::iterator iter = allDescriptors().begin();
|
||||
while (iter!=allDescriptors().end())
|
||||
{
|
||||
MemberDescriptorType* desc = *iter;
|
||||
if (desc==descriptor)
|
||||
goto SKIP;
|
||||
int compare = RBX::Name::compare(descriptor->name, desc->name);
|
||||
if (compare<0)
|
||||
break;
|
||||
if (compare==0)
|
||||
{
|
||||
// This descriptor name already exists in a different class
|
||||
compare = RBX::Name::compare(descriptor->owner.name, desc->owner.name);
|
||||
// Enforce order using class name
|
||||
if (compare<0)
|
||||
break;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
allDescriptors().insert(iter, descriptor);
|
||||
SKIP: ;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Type info enumeration
|
||||
typename Collection::const_iterator descriptors_begin() const {
|
||||
return descriptors.begin();
|
||||
}
|
||||
typename Collection::const_iterator descriptors_end() const {
|
||||
return descriptors.end();
|
||||
}
|
||||
size_t descriptor_size() const
|
||||
{
|
||||
return descriptors.size();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Enumeration of all descriptors
|
||||
static typename Collection::const_iterator all_begin() {
|
||||
return allDescriptors().begin();
|
||||
}
|
||||
static typename Collection::const_iterator all_end() {
|
||||
return allDescriptors().end();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Type info query
|
||||
MemberDescriptorType* findDescriptor(const char* name) const
|
||||
{
|
||||
MemberDescriptorType* const * item = descriptorLookup.find(name);
|
||||
|
||||
return item ? *item : NULL;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// Member enumeration
|
||||
ConstIterator members_begin(const DescribedBase* instance) const {
|
||||
return ConstIterator(descriptors.begin(), instance);
|
||||
}
|
||||
ConstIterator members_end(const DescribedBase* instance) const {
|
||||
return ConstIterator(descriptors.end(), instance);
|
||||
}
|
||||
|
||||
Iterator members_begin(DescribedBase* instance) const {
|
||||
return Iterator(descriptors.begin(), instance);
|
||||
}
|
||||
Iterator members_end(DescribedBase* instance) const {
|
||||
return Iterator(descriptors.end(), instance);
|
||||
}
|
||||
protected:
|
||||
void mergeMembers(const MemberDescriptorContainer* source)
|
||||
{
|
||||
for (typename Collection::const_iterator iter = source->descriptors.begin(); iter != source->descriptors.end(); ++iter)
|
||||
declare(*iter);
|
||||
|
||||
// Recursively merge parent members as well
|
||||
if (source->base!=NULL)
|
||||
mergeMembers(source->base);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ template<>
|
||||
int Bridge<EventInstance>::on_index(const EventInstance& object, const char* name, lua_State *L)
|
||||
{
|
||||
// The pre-defined "connect()" method
|
||||
if (strcmp(name, "connect") == 0 || strcmp(name, "Connect") == 0)
|
||||
if (strcmp(name, "connect")==0)
|
||||
{
|
||||
lua_pushcfunction(L, EventBridge::connect);
|
||||
return 1;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "Security/FuzzyTokens.h"
|
||||
#include "Security/RandomConstant.h"
|
||||
|
||||
#if defined(RBX_PLATFORM_DURANGO)
|
||||
#define NOINLINE __declspec(noinline)
|
||||
#elif defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
#undef min
|
||||
|
||||
#define FORCEINLINE __forceinline
|
||||
#define NOINLINE __declspec(noinline)
|
||||
|
||||
// All of the .text
|
||||
namespace RBX{ namespace Security {
|
||||
extern volatile const uintptr_t rbxTextBase;
|
||||
extern volatile const size_t rbxTextSize;
|
||||
extern volatile const uintptr_t rbxTextEndNeg;
|
||||
extern volatile const size_t rbxTextSizeNeg;
|
||||
extern volatile const uintptr_t rbxVmpBase;
|
||||
extern volatile const size_t rbxVmpSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
#define FORCEINLINE inline __attribute__((always_inline))
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
#endif
|
||||
|
||||
|
||||
// This file defines some secure caller function to prevent key functions
|
||||
// from being called from a dll.
|
||||
//
|
||||
// For many functions, this is actually intractable. With just a return address
|
||||
// check, someone can simply push the location of a "C3" byte (ret) in our code
|
||||
// and then jump to our function. The return address will appear to be in our code.
|
||||
//
|
||||
// When the check becomes stronger, it is a simple matter to find the target
|
||||
// function called from another function in our code. From this point it is easy
|
||||
// to call (into) that function. Even if the result isn't directly returned, it
|
||||
// will typically be on the stack.
|
||||
//
|
||||
// callbacks are problematic. On one hand, we can check callbacks before setting
|
||||
// and before calling them. However, callbacks could be set to "CC" bytes (int 3) in
|
||||
// our code, which would throw an exception that could be handled.
|
||||
//
|
||||
// Secure calling in this file almost certainly will not work within a VM protected
|
||||
// section as the registers and stack will be nonstandard.
|
||||
//
|
||||
// It will be trivial to find where these checks are done as well, as they all
|
||||
// modify the same global values.
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
FORCEINLINE static bool isRbxTextAddr(const void* const ptr)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(RBX_PLATFORM_DURANGO) && !defined(RBX_STUDIO_BUILD)
|
||||
return (reinterpret_cast<uintptr_t>(ptr) - RBX::Security::rbxTextBase < RBX::Security::rbxTextSize);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<unsigned int value> FORCEINLINE void callCheckSetBasicFlag(unsigned int flags)
|
||||
{
|
||||
Tokens::sendStatsToken.addFlagFast(value);
|
||||
Tokens::simpleToken |= value;
|
||||
}
|
||||
|
||||
// 33222222222 2 1 111 11111100 000 0 0 000
|
||||
// 10987654321 0 9 876 54321098 765 4 3 210
|
||||
// rsvd cpy pi veh ntapi cs locked name
|
||||
static const unsigned int kNameApiOffset = 0;
|
||||
static const unsigned int kRbxLockedApiOffset = 3;
|
||||
static const unsigned int kChangeStateApiOffset = 4;
|
||||
static const unsigned int kNtApiNoNtdll = (1<<8);
|
||||
static const unsigned int kNtApiNoText = (1<<9);
|
||||
static const unsigned int kNtApiNoApi = (1<<10);
|
||||
static const unsigned int kNtApiNoSyscall = (1<<11);
|
||||
static const unsigned int kNtApiNoTemplate = (1<<12);
|
||||
static const unsigned int kNtApiEarly = (1<<13);
|
||||
static const unsigned int kNtApiHash = (1<<14);
|
||||
static const unsigned int kNtApiNoCall = (1<<15);
|
||||
static const unsigned int kVehWpmFail = (1<<16);
|
||||
static const unsigned int kVehPrologFail = (1<<17);
|
||||
static const unsigned int kVehNoNtdll = (1<<18);
|
||||
static const unsigned int kPingItem = (1<<19);
|
||||
static const unsigned int kScriptContextCopy = (1<<20);
|
||||
static const unsigned int kLuaHooked = (1<<21);
|
||||
|
||||
|
||||
template<unsigned int offset> FORCEINLINE void callCheckSetApiFlag(unsigned int flags)
|
||||
{
|
||||
Tokens::apiToken.addFlagSafe(flags << offset);
|
||||
}
|
||||
|
||||
FORCEINLINE void callCheckNop(unsigned int flags)
|
||||
{
|
||||
}
|
||||
|
||||
// This checks that the return address:
|
||||
// 1) is within the .text section
|
||||
// 2) calling instruction has a correct relative offset. (must be call imm32)
|
||||
// 3) caller of calling function is within our .text section
|
||||
// Disabled in NoOpt because this won't be inlined.
|
||||
static const int kCallCheckCodeOnly = 1;
|
||||
static const int kCallCheckCallArg = 2;
|
||||
static const int kCallCheckCallersCode = 3;
|
||||
static const int kCallCheckRegCall = 4;
|
||||
|
||||
template<int level, void(*action)(unsigned int)>
|
||||
FORCEINLINE static unsigned int checkRbxCaller(const void* const funcAddress)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(_NOOPT) && !defined(LOVE_ALL_ACCESS) && !defined(RBX_STUDIO_BUILD) && !defined(RBX_PLATFORM_DURANGO)
|
||||
unsigned int flags = 0;
|
||||
|
||||
void* returnAddress = _ReturnAddress();
|
||||
flags |= isRbxTextAddr(returnAddress) ? 0 : (1<<0);
|
||||
if (!flags)
|
||||
{
|
||||
switch(level)
|
||||
{
|
||||
case kCallCheckCallersCode:
|
||||
{
|
||||
void* aora = _AddressOfReturnAddress();
|
||||
void* secondReturnAddress = (*((void***)(aora)-1))[1];
|
||||
flags |= isRbxTextAddr(secondReturnAddress) ? 0 : (1<<2);
|
||||
}
|
||||
// continue
|
||||
case kCallCheckCallArg:
|
||||
{
|
||||
unsigned int offset = *((unsigned int*)(returnAddress) - 1);
|
||||
flags |= (offset == ((unsigned int)(funcAddress)
|
||||
- (unsigned int)(returnAddress))) ? 0 : (1<<1);
|
||||
}
|
||||
break;
|
||||
case kCallCheckRegCall:
|
||||
{
|
||||
// this is a weaker check. call r32 is a prefixed 2 byte instruction.
|
||||
// because the register may have changed before this is called, there
|
||||
// isn't much point in checking it.
|
||||
static const unsigned short kX86RegCall = 0xD7FF; // due to little endian
|
||||
unsigned short opcode = *((unsigned short*)(returnAddress) - 1);
|
||||
flags |= ((opcode|0x0700) == kX86RegCall) ? 0 : (1<<3);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flags)
|
||||
{
|
||||
action(flags);
|
||||
}
|
||||
return flags;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace Security{
|
||||
static const unsigned int kCheckDefault = 0;
|
||||
static const unsigned int kCheckReturnAddr = 1;
|
||||
static const unsigned int kCheckNoThreadInit = 2;
|
||||
static const unsigned int kAllowVmpAll = 4; // I'm not sure if I only need to look at mutant, mutant+plain, etc...
|
||||
}
|
||||
|
||||
// Only supporting ntdll for now.
|
||||
#if defined(_WIN32) && !defined(RBX_PLATFORM_DURANGO)
|
||||
|
||||
inline const WCHAR* getUnicodeDllName(const UNICODE_STRING& str)
|
||||
{
|
||||
USHORT idx;
|
||||
for (idx = str.Length/sizeof(WCHAR); idx != 0; --idx)
|
||||
{
|
||||
if (str.Buffer[idx] == L'\\')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return str.Buffer + idx + 1;
|
||||
}
|
||||
|
||||
// This gets the location of ntdll using the documented parts of the PE format.
|
||||
// The intent is to make it harder for anyone who wants to hook GetModuleHandle.
|
||||
// This is not foolproof as the PEB or PEB pointer could be modified.
|
||||
inline HMODULE rbxGetNtdll()
|
||||
{
|
||||
const WCHAR* kNtDll = L"ntdll.dll";
|
||||
PEB* peb = reinterpret_cast<PEB*>(__readfsdword(0x30));
|
||||
PEB_LDR_DATA* pebLdrData = peb->Ldr;
|
||||
LIST_ENTRY imoListBase = pebLdrData->InMemoryOrderModuleList;
|
||||
LIST_ENTRY* imoListWalk = &imoListBase;
|
||||
int moduleLimit = 256;
|
||||
while ((imoListWalk->Flink != imoListBase.Blink) && --moduleLimit)
|
||||
{
|
||||
imoListWalk = imoListWalk->Flink;
|
||||
LDR_DATA_TABLE_ENTRY* thisPe = reinterpret_cast<LDR_DATA_TABLE_ENTRY*>(reinterpret_cast<BYTE*>(imoListWalk) - 8);
|
||||
const WCHAR* dllName = getUnicodeDllName(thisPe->FullDllName);
|
||||
const int dllNameLen = (thisPe->FullDllName.Length - (dllName - thisPe->FullDllName.Buffer))/sizeof(WCHAR);
|
||||
|
||||
//filter here
|
||||
unsigned int dest = ((unsigned int)(kNtDll) + RBX_BUILDSEED);
|
||||
volatile unsigned int tmp = dest;
|
||||
const WCHAR* const ntdllName = (const WCHAR* const)(tmp - RBX_BUILDSEED);
|
||||
if (_wcsnicmp(dllName, ntdllName, std::min(dllNameLen, 9)) == 0)
|
||||
{
|
||||
return reinterpret_cast<HMODULE>(thisPe->DllBase);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Find the location of the function matched by "filter" within ntdll's export table.
|
||||
// Doesn't directly expose the name of the function that has been matched.
|
||||
inline void* rbxNtdllProcAddress(HMODULE module, bool filter(const char*) )
|
||||
{
|
||||
DWORD* loc = 0;
|
||||
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)module;
|
||||
PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)(pDosHeader->e_lfanew + (char *)pDosHeader);
|
||||
IMAGE_DATA_DIRECTORY* imageDataDir = pNTHeader->OptionalHeader.DataDirectory;
|
||||
DWORD exportVa = imageDataDir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||
DWORD base = reinterpret_cast<DWORD>(module);
|
||||
PIMAGE_EXPORT_DIRECTORY pExport = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(base + exportVa);
|
||||
DWORD* pAddressOfNames = reinterpret_cast<DWORD*>(pExport->AddressOfNames + base);
|
||||
DWORD* pAddressOfFuncs = reinterpret_cast<DWORD*>(pExport->AddressOfFunctions + base);
|
||||
WORD* pAddressOfOrds = reinterpret_cast<WORD*> (pExport->AddressOfNameOrdinals + base);
|
||||
for (DWORD i = 0; i < pExport->NumberOfNames; ++i)
|
||||
{
|
||||
if (filter(reinterpret_cast<const char*>(base + pAddressOfNames[i])))
|
||||
{
|
||||
return reinterpret_cast<DWORD*>(base + pAddressOfFuncs[pAddressOfOrds[i]]);
|
||||
}
|
||||
}
|
||||
return loc;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
struct CallChainInfo
|
||||
{
|
||||
uint32_t handler;
|
||||
uint32_t ret;
|
||||
CallChainInfo() : handler(0), ret(0) {}
|
||||
CallChainInfo(uint32_t handler, uint32_t ret) : handler(handler), ret(ret) {}
|
||||
};
|
||||
|
||||
#if defined(_WIN32) && !defined(RBX_STUDIO_BUILD) && !defined(RBX_RCC_SECURITY) && !defined(RBX_PLATFORM_DURANGO)
|
||||
// Call Stack, function with:
|
||||
//
|
||||
// == C++ Exceptions == | == SEH3 Exceptions ==
|
||||
// +1C locals | +20 locals
|
||||
// ... | ...
|
||||
// +10 GS Cookie | +10 *nextHandler()
|
||||
// + C *nextHandler | + C *handler()
|
||||
// + 8 *handler() | + 8 scopeTable
|
||||
// + 4 state | + 4 tryLevel
|
||||
// +00 saved ebp | +00 saved ebp
|
||||
// - 4 return address | - 4 return address
|
||||
// - 8 first arg | - 8 first arg
|
||||
// -xx last arg | -xx last arg
|
||||
//
|
||||
// This will get generated in some functions that don't have try-catch blocks. Basically
|
||||
// if something could throw, objects might need to be destroyed.
|
||||
//
|
||||
// fs:[0] also contains a pointer to nextHandler, but is out of place in the middle of a
|
||||
// function.
|
||||
//
|
||||
// The list will always have a size of at least 2 -- the entry in ntdll and the entry we
|
||||
// started with.
|
||||
//
|
||||
// There is a case with boost::threads, as these get created with msvcr's threadstartex
|
||||
// (after ntdll rtlInitThread). However, boost::threads will have three exception handlers
|
||||
// in the boost code before getting into msvcr.
|
||||
|
||||
template<size_t kMaxDepth> FORCEINLINE uint32_t detectDllByExceptionChain(void* addrOfChain, unsigned int kFlags)
|
||||
{
|
||||
static const size_t kStackNextIdx = 0;
|
||||
static const size_t kStackHandlerIdx = 1;
|
||||
static const size_t kStackReturnIdx = 4;
|
||||
static const size_t kStackEndingArgIdx = 6;
|
||||
DWORD* stkPtr = reinterpret_cast<DWORD*>(addrOfChain);
|
||||
uintptr_t textEndNeg = RBX::Security::rbxTextEndNeg;
|
||||
size_t textSizeNeg = RBX::Security::rbxTextSizeNeg;
|
||||
uintptr_t vmpBase = RBX::Security::rbxVmpBase;
|
||||
size_t vmpSize = RBX::Security::rbxVmpSize;
|
||||
uint32_t result = 0;
|
||||
for (size_t i = 0; i < kMaxDepth; ++i)
|
||||
{
|
||||
// check for end of chain in ntdll.
|
||||
if (!(kFlags & Security::kCheckNoThreadInit) && (stkPtr[0] == 0xFFFFFFFF))
|
||||
{
|
||||
// check if handler chain init in roblox. (equivalent to "addr - base >= size")
|
||||
if ((stkPtr[kStackEndingArgIdx] + textEndNeg ) <= textSizeNeg)
|
||||
{
|
||||
result |= 1 << (i*3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
// check if handler in roblox code. (equivalent to "addr - base >= size")
|
||||
if ((stkPtr[kStackHandlerIdx] + textEndNeg ) <= textSizeNeg)
|
||||
{
|
||||
result |= 1 << (i*3 + 1);
|
||||
break;
|
||||
}
|
||||
if ( (kFlags & Security::kCheckReturnAddr) // check return enabled
|
||||
&& (stkPtr[kStackReturnIdx] + textEndNeg ) <= textSizeNeg) // not in .text
|
||||
{
|
||||
if (!((kFlags&Security::kAllowVmpAll) // allow vmp
|
||||
&& (stkPtr[kStackReturnIdx] - vmpBase ) > vmpSize)) // not in vmp
|
||||
{
|
||||
result |= 1 << (i*3 + 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// follow next
|
||||
stkPtr = reinterpret_cast<DWORD*>(stkPtr[kStackNextIdx]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<size_t kMaxDepth> FORCEINLINE void generateCallInfo(void* addrOfFirstArg, std::vector<CallChainInfo>& info)
|
||||
{
|
||||
static const size_t kStackNextIdx = 0;
|
||||
static const size_t kStackHandlerIdx = 1;
|
||||
static const size_t kStackReturnIdx = 4;
|
||||
static const size_t kStackEndingArgIdx = 6;
|
||||
static const size_t kStackFirstArgToNextHandler = 5;
|
||||
DWORD* stkPtr = reinterpret_cast<DWORD*>(addrOfFirstArg) - kStackFirstArgToNextHandler;
|
||||
for (size_t i = 0; i < kMaxDepth; ++i)
|
||||
{
|
||||
info.push_back(CallChainInfo(stkPtr[kStackHandlerIdx],stkPtr[kStackReturnIdx]));
|
||||
// check for end of chain in ntdll.
|
||||
if (stkPtr[0] == 0xFFFFFFFF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// follow next
|
||||
stkPtr = reinterpret_cast<DWORD*>(stkPtr[kStackNextIdx]);
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t kMaxDepth> FORCEINLINE uint32_t detectDllByExceptionChainStack(void* addrOfFirstArg, unsigned int kFlags)
|
||||
{
|
||||
static const size_t kStackFirstArgToNextHandler = 5;
|
||||
DWORD* stkPtr = reinterpret_cast<DWORD*>(addrOfFirstArg) - kStackFirstArgToNextHandler;
|
||||
return detectDllByExceptionChain<kMaxDepth>(stkPtr, kFlags);
|
||||
}
|
||||
|
||||
// not all functions add an exception handler to the chain, so the stack based method doesn't
|
||||
// always work.
|
||||
template<size_t kMaxDepth> FORCEINLINE uint32_t detectDllByExceptionChainTeb(unsigned int kFlags)
|
||||
{
|
||||
return detectDllByExceptionChain<kMaxDepth>(reinterpret_cast<void*>(__readfsdword(0)), kFlags );
|
||||
}
|
||||
#else
|
||||
template<size_t kMaxDepth> FORCEINLINE uint32_t detectDllByExceptionChainTeb(unsigned int kFlags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
template<size_t kMaxDepth> FORCEINLINE uint32_t detectDllByExceptionChainStack(void* addrOfFirstArg, unsigned int kFlags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<size_t kMaxDepth> FORCEINLINE void generateCallInfo(void* addrOfFirstArg, std::vector<CallChainInfo>& info)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
#include "boost/thread/mutex.hpp"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
// This is designed to be an anti-tamper security reporting mechanism.
|
||||
// Add flag is based on the number of bits in the flag, and succeeds
|
||||
// with probability 1 - 0.5**N per transmitted packet. This might
|
||||
// seem like an issue, but most of the checks will re-trigger an addition
|
||||
// meaning an exploiter is unlikely to be in the game for more than 30
|
||||
// seconds. Attempts to modify the packet are very likely to fail.
|
||||
|
||||
namespace Security
|
||||
{
|
||||
unsigned long long teaDecrypt(unsigned long long inTag);
|
||||
unsigned long long teaEncrypt(unsigned long long inTag);
|
||||
}
|
||||
|
||||
namespace Tokens
|
||||
{
|
||||
union binaryTag
|
||||
{
|
||||
unsigned int asHalf[2];
|
||||
unsigned long long asFull;
|
||||
};
|
||||
}
|
||||
|
||||
class ClientFuzzySecurityToken
|
||||
{
|
||||
Tokens::binaryTag tag;
|
||||
Tokens::binaryTag prevTag;
|
||||
Tokens::binaryTag savedTag;
|
||||
boost::mutex tokenMutex;
|
||||
public:
|
||||
ClientFuzzySecurityToken(unsigned long long inTag);
|
||||
void set(unsigned long long inTag);
|
||||
|
||||
#ifdef WIN32
|
||||
__forceinline
|
||||
#else
|
||||
inline
|
||||
#endif
|
||||
void addFlagFast(unsigned long long flags)
|
||||
{
|
||||
tag.asFull |= flags;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
__forceinline
|
||||
#else
|
||||
inline
|
||||
#endif
|
||||
void addFlagSafe(unsigned long long flags)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(tokenMutex);
|
||||
tag.asFull |= flags;
|
||||
}
|
||||
unsigned long long crypt();
|
||||
unsigned long long getPrev()
|
||||
{
|
||||
return prevTag.asFull;
|
||||
}
|
||||
};
|
||||
|
||||
// The server can check this. Each '1' transmitted from the client has
|
||||
// a 50% chance of being a '0' here, thus it it fuzzy.
|
||||
class ServerFuzzySecurityToken
|
||||
{
|
||||
Tokens::binaryTag lastTag;
|
||||
Tokens::binaryTag tag;
|
||||
unsigned int ignoreFlags;
|
||||
public:
|
||||
ServerFuzzySecurityToken(unsigned long long inTag, unsigned int ignoreFlags = 0);
|
||||
void setLastTag(unsigned long long tag) { lastTag.asFull = tag;}
|
||||
unsigned long long decrypt(unsigned long long inTag);
|
||||
};
|
||||
|
||||
namespace Tokens
|
||||
{
|
||||
extern ClientFuzzySecurityToken sendStatsToken;
|
||||
extern unsigned int simpleToken;
|
||||
extern ClientFuzzySecurityToken apiToken;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(_WIN32) && !defined(RBX_STUDIO_BUILD) && !defined(RBX_PLATFORM_DURANGO)
|
||||
#include "Security/RandomConstant.h"
|
||||
|
||||
// This is junk code generation. All of this is intended to be inlined
|
||||
// and generally do nothing.
|
||||
|
||||
// there are 15*17 different seeds from this.
|
||||
// (RBX_BUILDSEED%15 + 1) is between 1 and 16, and is coprime to 17.
|
||||
#define RBX_JUNK (junk< ((RBX_BUILDSEED%15 + 1)*__LINE__ + RBX_BUILDSEED) % 17>())
|
||||
|
||||
template <int N> inline void junk() {}
|
||||
|
||||
#define RBX_NOP0 __asm _emit 0x0f __asm _emit 0x1f __asm _emit 0x00
|
||||
#define RBX_NOP1 __asm _emit 0x8d __asm _emit 0x76 __asm _emit 0x00
|
||||
#define RBX_NOP2 __asm _emit 0x0f __asm _emit 0x1f __asm _emit 0x40 __asm _emit 0x00
|
||||
#define RBX_NOP3 __asm _emit 0x8d __asm _emit 0x74 __asm _emit 0x26 __asm _emit 0x00
|
||||
#define RBX_NOP4 __asm _emit 0x90 __asm _emit 0x8d __asm _emit 0x74 __asm _emit 0x26 __asm _emit 0x00
|
||||
#define RBX_NOP5 __asm _emit 0x66 __asm _emit 0x0f __asm _emit 0x1f __asm _emit 0x44 __asm _emit 0x00 __asm _emit 0x00
|
||||
#define RBX_NOP6 __asm _emit 0x8d __asm _emit 0xb6 __asm _emit 0x00 __asm _emit 0x00 __asm _emit 0x00 __asm _emit 0x00
|
||||
template<> inline void junk<0>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<> inline void junk<1>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP1;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void junk<2>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP2;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void junk<3>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP3;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void junk<4>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP4;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void junk<5>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP5;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void junk<6>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP6;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void junk<7>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP0;
|
||||
RBX_NOP1;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void junk<8>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP1;
|
||||
RBX_NOP2;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void junk<9>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP1;
|
||||
RBX_NOP3;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void junk<10>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP4;
|
||||
RBX_NOP0;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void junk<11>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP3;
|
||||
RBX_NOP5;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void junk<12>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP2;
|
||||
RBX_NOP5;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void junk<13>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP6;
|
||||
RBX_NOP0;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void junk<14>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP2;
|
||||
RBX_NOP1;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void junk<15>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP4;
|
||||
RBX_NOP5;
|
||||
}
|
||||
}
|
||||
|
||||
template<> inline void junk<16>()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
RBX_NOP3;
|
||||
RBX_NOP2;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define RBX_JUNK
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
#pragma once
|
||||
#define RBX_BUILDSEED 3942749
|
||||
@@ -0,0 +1,117 @@
|
||||
|
||||
#pragma once
|
||||
#include "rbxformat.h"
|
||||
#include "rbx/boost.hpp"
|
||||
#include "g3d/format.h"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template<typename T> class thread_specific_ptr;
|
||||
}
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
namespace Security
|
||||
{
|
||||
typedef enum {
|
||||
Anonymous = 0,
|
||||
LocalGUI_, // Any action initiated by Roblox Studio or the mouse
|
||||
GameScript_, // Execution of a BaseScript object inside any DataModel
|
||||
GameScriptInRobloxPlace_, // Execution of a BaseScript object inside any DataModel, if the place was authored by Roblox
|
||||
RobloxGameScript_, // Execution of a BaseScript object written by Roblox inside any DataModel
|
||||
CmdLine_, // Any script executed from the Studio command line
|
||||
#if defined(RBX_STUDIO_BUILD)
|
||||
StudioPlugin, // Any Studio plug-in script
|
||||
#endif
|
||||
COM, // Scripts executed via the COM API (usually comes from watrbx.wtf)
|
||||
WebService, // Scripts executed via the Web Service API (usually comes from watrbx.wtf)
|
||||
Replicator_, // Receiving data via replication
|
||||
COUNT_Identities // Not a true identity. Used for enumeration
|
||||
} Identities;
|
||||
|
||||
typedef enum {
|
||||
None =0, // Any identity can access this feature, including in-game scripts
|
||||
Plugin =1, // Second-lowest access level, just above in-game script
|
||||
RobloxPlace =2, // A Roblox place that we own. Therefore scripts are more trusted and we allow
|
||||
// preliminary features
|
||||
LocalUser =3, // non-game permission. Usually for IDE
|
||||
WritePlayer =4, // Permissions for changing player name, userId, etc.
|
||||
RobloxScript =5, // A script, such as a CoreScript, that we run inside a game
|
||||
Roblox =6, // Highest level of permission
|
||||
|
||||
#ifdef RBX_TEST_BUILD
|
||||
TestLocalUser =None, //For exposing Lua functions to the ReleaseTest build
|
||||
#else
|
||||
TestLocalUser =LocalUser,
|
||||
#endif
|
||||
} Permissions;
|
||||
|
||||
// different classes of VM that derive from the permission level
|
||||
typedef enum {
|
||||
VM_Default = 0, // most scripts go here
|
||||
#if defined(RBX_STUDIO_BUILD)
|
||||
VM_StudioPlugin, // Sandbox for studio plugin scripts
|
||||
#endif
|
||||
VM_RobloxScriptPlus, // scripts with the permission level of RobloxScript or higher go here
|
||||
COUNT_VM_Classes
|
||||
} VMClasses;
|
||||
|
||||
class Impersonator;
|
||||
|
||||
class Context
|
||||
{
|
||||
friend class Impersonator;
|
||||
|
||||
public:
|
||||
const Identities identity;
|
||||
static Context& current();
|
||||
|
||||
// Throws an exception if the current thread's Context doesn't have the requested Role
|
||||
void requirePermission(Permissions permission, const char* operation = 0) const
|
||||
{
|
||||
if (!isInRole(identity, permission)) {
|
||||
#ifndef _DEBUG
|
||||
// obfuscate error string
|
||||
// TODO: Can we obfuscate the code without obfuscating the error?
|
||||
// Daniel: NO
|
||||
//if (operation)
|
||||
// throw RBX::runtime_error("s %s", operation);
|
||||
//else
|
||||
// throw RBX::runtime_error("s");
|
||||
throw std::runtime_error("");
|
||||
#else
|
||||
if (operation) {
|
||||
throw RBX::runtime_error("The current identity (%d) cannot %s (requires %d)", identity, operation, permission);
|
||||
} else {
|
||||
throw RBX::runtime_error("The current identity (%d) cannot perform the requested operation (requires %d)", identity, permission);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool hasPermission(Permissions permission)
|
||||
{
|
||||
return isInRole(identity, permission);
|
||||
}
|
||||
|
||||
static bool isInRole(Identities identity, Permissions permission);
|
||||
|
||||
static void tssCleanup(Context*);
|
||||
|
||||
private:
|
||||
Context(Identities identity):identity(identity) {}
|
||||
static boost::thread_specific_ptr<Context>& ptr();
|
||||
};
|
||||
|
||||
// Impersonates an identity for the lifetime of the object
|
||||
class Impersonator
|
||||
{
|
||||
Context current;
|
||||
Context* previous;
|
||||
public:
|
||||
Impersonator(Identities identity);
|
||||
~Impersonator();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,682 @@
|
||||
#pragma once
|
||||
|
||||
#include "solver/SolverConfig.h"
|
||||
#include "solver/ConstraintJacobian.h"
|
||||
#include "solver/SolverBody.h"
|
||||
#include "v8kernel/SimBody.h"
|
||||
#include "v8world/RotateJoint.h"
|
||||
|
||||
#include "simd/simd.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
|
||||
class PGSSolver;
|
||||
class DebugSerializer;
|
||||
|
||||
//
|
||||
// ConstraintVariables: inputs to the solver, initialized by the constraint interface
|
||||
//
|
||||
class ConstraintVariables
|
||||
{
|
||||
public:
|
||||
void serialize( DebugSerializer& s ) const;
|
||||
|
||||
static RBX_SIMD_INLINE void setReaction( ConstraintVariables* _vars, const Vector3& _r )
|
||||
{
|
||||
_vars[0].reaction = _r.x;
|
||||
_vars[1].reaction = _r.y;
|
||||
_vars[2].reaction = _r.z;
|
||||
}
|
||||
|
||||
static RBX_SIMD_INLINE void setReaction( ConstraintVariables* _vars, float x, float y )
|
||||
{
|
||||
_vars[0].reaction = x;
|
||||
_vars[1].reaction = y;
|
||||
}
|
||||
|
||||
static RBX_SIMD_INLINE void setImpulse( ConstraintVariables* _vars, const Vector3& _i )
|
||||
{
|
||||
_vars[0].impulse = _i.x;
|
||||
_vars[1].impulse = _i.y;
|
||||
_vars[2].impulse = _i.z;
|
||||
}
|
||||
|
||||
static RBX_SIMD_INLINE void setImpulse( ConstraintVariables* _vars, float x, float y )
|
||||
{
|
||||
_vars[0].impulse = x;
|
||||
_vars[1].impulse = y;
|
||||
}
|
||||
|
||||
static RBX_SIMD_INLINE void setMinImpulses( ConstraintVariables* _vars, const Vector3& _min )
|
||||
{
|
||||
_vars[0].minImpulseValue = _min.x;
|
||||
_vars[1].minImpulseValue = _min.y;
|
||||
_vars[2].minImpulseValue = _min.z;
|
||||
}
|
||||
|
||||
static RBX_SIMD_INLINE void setMinImpulses( ConstraintVariables* _vars, float x, float y )
|
||||
{
|
||||
_vars[0].minImpulseValue = x;
|
||||
_vars[1].minImpulseValue = y;
|
||||
}
|
||||
|
||||
static RBX_SIMD_INLINE void setMaxImpulses( ConstraintVariables* _vars, const Vector3& _max )
|
||||
{
|
||||
_vars[0].maxImpulseValue = _max.x;
|
||||
_vars[1].maxImpulseValue = _max.y;
|
||||
_vars[2].maxImpulseValue = _max.z;
|
||||
}
|
||||
|
||||
static RBX_SIMD_INLINE void setMaxImpulses( ConstraintVariables* _vars, float x, float y )
|
||||
{
|
||||
_vars[0].maxImpulseValue = x;
|
||||
_vars[1].maxImpulseValue = y;
|
||||
}
|
||||
|
||||
static RBX_SIMD_INLINE void gatherComponents( simd::v4f& _impulses, simd::v4f& _reactions, simd::v4f& _min, simd::v4f& _max, const ConstraintVariables& _vars0 )
|
||||
{
|
||||
_min = simd::splat< 0 >( simd::v4f( _vars0.v ) );
|
||||
_max = simd::splat< 1 >( simd::v4f( _vars0.v ) );
|
||||
_reactions = simd::splat< 2 >( simd::v4f( _vars0.v ) );
|
||||
_impulses = simd::splat< 3 >( simd::v4f( _vars0.v ) );
|
||||
}
|
||||
|
||||
static RBX_SIMD_INLINE void gatherComponents( simd::v4f& _impulses, simd::v4f& _reactions, simd::v4f& _min, simd::v4f& _max, const ConstraintVariables& _vars0, const ConstraintVariables& _vars1 )
|
||||
{
|
||||
transpose2x4( _min, _max, _reactions, _impulses, simd::v4f(_vars0.v), simd::v4f(_vars1.v) );
|
||||
}
|
||||
|
||||
static RBX_SIMD_INLINE void gatherComponents( simd::v4f& _impulses, simd::v4f& _reactions, simd::v4f& _min, simd::v4f& _max, const ConstraintVariables& _vars0, const ConstraintVariables& _vars1, const ConstraintVariables& _vars2 )
|
||||
{
|
||||
transpose3x4( _min, _max, _reactions, _impulses, (simd::v4f)_vars0.v, (simd::v4f)_vars1.v, (simd::v4f)_vars2.v );
|
||||
}
|
||||
|
||||
static RBX_SIMD_INLINE void gatherComponents( simd::v4f& _impulses, simd::v4f& _reactions, simd::v4f& _min, simd::v4f& _max, const ConstraintVariables& _vars0, const ConstraintVariables& _vars1, const ConstraintVariables& _vars2, const ConstraintVariables& _vars3 )
|
||||
{
|
||||
transpose( _min, _max, _reactions, _impulses, (simd::v4f)_vars0.v, (simd::v4f)_vars1.v, (simd::v4f)_vars2.v, (simd::v4f)_vars3.v );
|
||||
}
|
||||
|
||||
// Values that must be set by the Constraint::buildEquation
|
||||
// Inputs expected by the solver
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
float minImpulseValue;
|
||||
float maxImpulseValue;
|
||||
|
||||
// Constraint must set this to the desired reaction
|
||||
float reaction;
|
||||
|
||||
// The Constraint must set this to the impulse computed in the previous frame or 0.0f if it is not available.
|
||||
// This will contain the result.
|
||||
float impulse;
|
||||
};
|
||||
simd::v4f_pod v;
|
||||
};
|
||||
};
|
||||
|
||||
//
|
||||
// MovingRegression: Fit best 2nd degree curve to the last few data points
|
||||
//
|
||||
class MovingRegression
|
||||
{
|
||||
public:
|
||||
MovingRegression()
|
||||
{
|
||||
lastPoint = 0.0f;
|
||||
lastTangent = 0.0f;
|
||||
lastCurvature = 0.0f;
|
||||
confidence = 0.0f;
|
||||
}
|
||||
|
||||
inline float testFitNextDataPointZeroOrder( float y ) const
|
||||
{
|
||||
float predicted = lastPoint;
|
||||
return confidence * std::abs( y - predicted ) / ( std::max( std::abs( y ), std::abs( predicted ) ) + 0.00001f ) ;
|
||||
}
|
||||
|
||||
inline float testFitNextDataPointFirstOrder( float y ) const
|
||||
{
|
||||
float predicted = lastPoint + lastTangent;
|
||||
return confidence * std::abs( y - predicted ) / ( std::max( std::abs( y ), std::abs( predicted ) ) + 0.00001f ) ;
|
||||
}
|
||||
|
||||
inline float testFitNextDataPointSecondOrder( float y ) const
|
||||
{
|
||||
float predicted = lastPoint + lastTangent + lastCurvature;
|
||||
return confidence * std::abs( y - predicted ) / ( std::max( std::abs( y ), std::abs( predicted ) ) + 0.00001f ) ;
|
||||
}
|
||||
|
||||
float predict( ) const
|
||||
{
|
||||
return lastPoint;
|
||||
}
|
||||
|
||||
void addDataPoint( float y, float weight )
|
||||
{
|
||||
float newTangent = y - lastPoint;
|
||||
float newCurvature = newTangent - lastTangent;
|
||||
lastCurvature = newCurvature;
|
||||
lastTangent = newTangent;
|
||||
lastPoint = y;
|
||||
confidence += 0.1f * ( 1.0f - confidence );
|
||||
}
|
||||
|
||||
void serialize( DebugSerializer& s) const;
|
||||
|
||||
float confidence;
|
||||
float lastPoint;
|
||||
float lastTangent;
|
||||
float lastCurvature;
|
||||
};
|
||||
|
||||
//
|
||||
// Cached values for each constraint equation
|
||||
//
|
||||
class ConstraintCache
|
||||
{
|
||||
public:
|
||||
ConstraintCache():
|
||||
velocityImpulse( 0.0f ),
|
||||
velocityReaction( 0.0f ),
|
||||
positionImpulse( 0.0f ),
|
||||
positionReaction( 0.0f ),
|
||||
// These need to be initialized to the values in SolverConfig!
|
||||
velocitySor( 1.9f ),
|
||||
positionSor( 1.9f ),
|
||||
velocityCacheDamping( 1.0f ),
|
||||
positionCacheDamping( 1.0f ) { }
|
||||
|
||||
void cache( const ConstraintVariables& _velocityStage, const ConstraintVariables& _positionStage, float _sorVel, float _sorPos, bool _isCollision, const SolverConfig& config );
|
||||
|
||||
inline void readCache( ConstraintVariables& _velocityStage, ConstraintVariables& _positionStage, float& _sorVel, float& _sorPos ) const
|
||||
{
|
||||
_velocityStage.impulse = velocityImpulse;
|
||||
_sorVel = velocitySor;
|
||||
_velocityStage.reaction = velocityReaction;
|
||||
_positionStage.impulse = positionImpulse;
|
||||
_sorPos = positionSor;
|
||||
_positionStage.reaction = positionReaction;
|
||||
}
|
||||
|
||||
void serialize( DebugSerializer& s ) const;
|
||||
|
||||
float velocityImpulse;
|
||||
float velocityReaction;
|
||||
float velocitySor;
|
||||
float velocityCacheDamping;
|
||||
float positionImpulse;
|
||||
float positionReaction;
|
||||
float positionSor;
|
||||
float positionCacheDamping;
|
||||
|
||||
MovingRegression velocityImpulseRegression;
|
||||
MovingRegression positionImpulseRegression;
|
||||
};
|
||||
|
||||
//
|
||||
// Constraint definition: Base class for all constraints and collision classes
|
||||
//
|
||||
class Constraint
|
||||
{
|
||||
public:
|
||||
enum Types
|
||||
{
|
||||
Types_Collision, // Special constraint type: only generated inside the solver from ContactConnectors
|
||||
Types_Align2Axes,
|
||||
Types_BallInSocket,
|
||||
Types_AngularVelocity,
|
||||
Types_LinearVelocity,
|
||||
Types_AchievePosition,
|
||||
Types_BodyAngularVelocity,
|
||||
Types_LinearSpring,
|
||||
Types_LegacyBreakableBallInSocket,
|
||||
Types_LegacyAngularVelocity,
|
||||
Types_Count
|
||||
};
|
||||
|
||||
// Number of degrees of freedom constrained
|
||||
inline unsigned getDimension() const { return dimensions; }
|
||||
|
||||
inline bool isBroken() const { return broken; }
|
||||
|
||||
// Read from the constraint cache, and call the overloaded build equation
|
||||
// This should only be called by the solver
|
||||
inline void restoreCacheAndBuildEquation(
|
||||
ConstraintJacobianPair* _jacobian,
|
||||
ConstraintVariables* _velocityStage,
|
||||
ConstraintVariables* _positionStage,
|
||||
float* _sorVel,
|
||||
float* _sorPos,
|
||||
boost::uint8_t* _useBlock,
|
||||
const SolverBodyDynamicProperties& _bodyA,
|
||||
const SolverBodyDynamicProperties& _bodyB,
|
||||
const SolverConfig& _solverConfig,
|
||||
float _dt );
|
||||
|
||||
// Write into the constraint cache
|
||||
// This should only be called by the solver
|
||||
inline void cache(
|
||||
const ConstraintVariables* _velocityStage,
|
||||
const ConstraintVariables* _positionStage,
|
||||
const float* _sorVel, const float* _sorPos,
|
||||
const SolverConfig& _config );
|
||||
|
||||
// Each breakable constraint will need to implement this, and return /true/ if the constraint changes state to broken
|
||||
// This should only be called by the solver
|
||||
inline void updateBrokenState(
|
||||
const ConstraintVariables* _velocityStage,
|
||||
const ConstraintVariables* _positionStage,
|
||||
const SolverConfig& _config );
|
||||
|
||||
void setBodyA( Body* _a ) { bodyA = _a; }
|
||||
void setBodyB( Body* _b ) { bodyB = _b; }
|
||||
const Body* getBodyA() const { return bodyA; }
|
||||
const Body* getBodyB() const { return bodyB; }
|
||||
Body* getBodyA() { return bodyA; }
|
||||
Body* getBodyB() { return bodyB; }
|
||||
Types getType() const { return type; }
|
||||
|
||||
virtual ~Constraint();
|
||||
|
||||
void setUID( boost::uint64_t _index ) { uid = _index; }
|
||||
bool hasValidUID() const { return uid != 0; }
|
||||
boost::uint64_t getUID() const { return uid; }
|
||||
|
||||
// After the PGS has updated all i ts iterations, the last iteration reaction delta is passed in as parameter
|
||||
enum Convergence
|
||||
{
|
||||
Convergence_Converges,
|
||||
Convergence_Diverges,
|
||||
Convergence_Undetermined
|
||||
};
|
||||
virtual Convergence testPGSConvergence( const float* _disp, const float* _residuals, const float* _deltaResiduals, const SolverConfig& _solverConfig ) { return Convergence_Converges; }
|
||||
|
||||
virtual void serialize( DebugSerializer& s ) const;
|
||||
|
||||
protected:
|
||||
const ConstraintCache& getCache( unsigned d ) const { return cacheData[ d ]; }
|
||||
ConstraintCache& getCache( unsigned d ) { return cacheData[ d ]; }
|
||||
|
||||
inline Constraint( Types _type, Body* _bodyA, Body* _bodyB, uint8_t _dimensions );
|
||||
|
||||
private:
|
||||
// Main constraint interface to the solver
|
||||
// Initializes the Jacobian and ConstraintVariables for the two stages
|
||||
virtual void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) = 0;
|
||||
|
||||
// Each breakable constraint will need to implement this, and return /true/ if the constraint changes state to broken
|
||||
virtual bool computeBrokenState(
|
||||
const ConstraintVariables* _velocityStage,
|
||||
const ConstraintVariables* _positionStage,
|
||||
const SolverConfig& _config ) const { return false; }
|
||||
|
||||
// Disable copy constructs
|
||||
Constraint( const Constraint& );
|
||||
Constraint& operator=( const Constraint& );
|
||||
|
||||
protected:
|
||||
uint8_t dimensions;
|
||||
Types type : 8;
|
||||
bool broken : 1;
|
||||
private:
|
||||
Body* bodyA;
|
||||
Body* bodyB;
|
||||
ConstraintCache* cacheData;
|
||||
boost::uint64_t uid; // Current index if registered in the solver
|
||||
};
|
||||
|
||||
//
|
||||
// Constraint: inline implementation
|
||||
//
|
||||
inline Constraint::Constraint( Types _type, Body* _bodyA, Body* _bodyB, uint8_t _dimensions ): type( _type ), dimensions( _dimensions ), bodyA( _bodyA ), bodyB( _bodyB ), uid( 0 ), broken( false )
|
||||
{
|
||||
RBXASSERT( _bodyA != NULL );
|
||||
cacheData = new ConstraintCache[ dimensions ];
|
||||
}
|
||||
|
||||
#ifdef __RBX_NOT_RELEASE
|
||||
static inline void checkConstraintVariables( const ConstraintVariables& _vars )
|
||||
{
|
||||
RBXASSERT( !RBX::Math::isNanInf( _vars.impulse ) );
|
||||
RBXASSERT( !RBX::Math::isNanInf( _vars.reaction ) );
|
||||
RBXASSERT( !RBX::Math::isNan( _vars.minImpulseValue ) );
|
||||
RBXASSERT( !RBX::Math::isNan( _vars.maxImpulseValue ) );
|
||||
}
|
||||
|
||||
static inline void checkJacobian( const ConstraintJacobianPair& _j )
|
||||
{
|
||||
RBXASSERT( !RBX::Math::isNanInfVector3( _j.a.lin ) );
|
||||
RBXASSERT( !RBX::Math::isNanInfVector3( _j.b.lin ) );
|
||||
RBXASSERT( !RBX::Math::isNanInfVector3( _j.a.ang ) );
|
||||
RBXASSERT( !RBX::Math::isNanInfVector3( _j.b.ang ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
RBX_SIMD_INLINE void Constraint::restoreCacheAndBuildEquation(
|
||||
ConstraintJacobianPair* __restrict _jacobian,
|
||||
ConstraintVariables* __restrict _varsVel,
|
||||
ConstraintVariables* __restrict _varsPos,
|
||||
float* __restrict _sorVel,
|
||||
float* __restrict _sorPos,
|
||||
boost::uint8_t* _useBlock,
|
||||
const SolverBodyDynamicProperties& _bodyA,
|
||||
const SolverBodyDynamicProperties& _bodyB,
|
||||
const SolverConfig& _solverConfig,
|
||||
float _dt )
|
||||
{
|
||||
for( unsigned i = 0; i < dimensions; i++ )
|
||||
{
|
||||
// Initialize to some reasonable default values
|
||||
_varsVel[i].minImpulseValue = -std::numeric_limits<float>::infinity();
|
||||
_varsVel[i].maxImpulseValue = std::numeric_limits<float>::infinity();
|
||||
|
||||
_varsPos[i].minImpulseValue = -std::numeric_limits<float>::infinity();
|
||||
_varsPos[i].maxImpulseValue = std::numeric_limits<float>::infinity();
|
||||
|
||||
_jacobian[i].reset();
|
||||
|
||||
// Unless specified by the constraint, use the entire constraint as a Block in the Gauss-Seidel
|
||||
_useBlock[i] = _solverConfig.blockPGSEnabled;
|
||||
|
||||
// Read previous frame impulse/SOR/reaction values
|
||||
getCache(i).readCache(_varsVel[i],_varsPos[i], _sorVel[i], _sorPos[i]);
|
||||
|
||||
// Optionally disable the cache
|
||||
_varsVel[i].impulse = _solverConfig.velCacheDamping * _varsVel[i].impulse;
|
||||
_varsPos[i].impulse = _solverConfig.posCacheDamping * _varsPos[i].impulse;
|
||||
}
|
||||
|
||||
buildEquation( _jacobian, _useBlock, _varsVel, _varsPos, _bodyA, _bodyB, _solverConfig, _dt );
|
||||
|
||||
// Run some sanity checks
|
||||
#ifdef __RBX_NOT_RELEASE
|
||||
for( unsigned i = 0; i < dimensions; i++ )
|
||||
{
|
||||
checkConstraintVariables( _varsVel[ i ] );
|
||||
checkConstraintVariables( _varsPos[ i ] );
|
||||
checkJacobian( _jacobian[ i ] );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE void Constraint::updateBrokenState(
|
||||
const ConstraintVariables* _velocityStage,
|
||||
const ConstraintVariables* _positionStage,
|
||||
const SolverConfig& _config )
|
||||
{
|
||||
if( !broken )
|
||||
{
|
||||
broken = computeBrokenState(_velocityStage, _positionStage, _config);
|
||||
}
|
||||
}
|
||||
|
||||
inline void Constraint::cache( const ConstraintVariables* _velocityStage, const ConstraintVariables* _positionStage, const float* _sorVel, const float* _sorPos, const SolverConfig& _config )
|
||||
{
|
||||
// Cache Constraint base class data
|
||||
for( unsigned i = 0; i < dimensions; i++ )
|
||||
{
|
||||
cacheData[ i ].cache( _velocityStage[ i ], _positionStage[ i ], _sorVel[ i ], _sorPos[ i ], getType() == Types_Collision, _config );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ConstraintBallInSocket
|
||||
//
|
||||
class ConstraintBallInSocket: public Constraint
|
||||
{
|
||||
public:
|
||||
ConstraintBallInSocket( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_BallInSocket, _bodyA, _bodyB, 3 ) { }
|
||||
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||
|
||||
inline void setPivotA( const Vector3& _pivotA ) { pointA = _pivotA; }
|
||||
inline void setPivotB( const Vector3& _pivotB ) { pointB = _pivotB; }
|
||||
|
||||
Convergence testPGSConvergence( const float* _disp, const float* _residuals, const float* _deltaResiduals, const SolverConfig& _solverConfig ) override;
|
||||
void serialize( DebugSerializer& s ) const override;
|
||||
|
||||
private:
|
||||
// Points on object A and B in object space, relative to center of mass
|
||||
Vector3 pointA;
|
||||
Vector3 pointB;
|
||||
};
|
||||
|
||||
//
|
||||
// ConstraintLegacyBreakableBallInSocket
|
||||
//
|
||||
class ConstraintLegacyBreakableBallInSocket: public Constraint
|
||||
{
|
||||
public:
|
||||
ConstraintLegacyBreakableBallInSocket( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_LegacyBreakableBallInSocket, _bodyA, _bodyB, 3 ), pointA(0.0f), pointB(0.0f), broken( false ), maxNormalForce( std::numeric_limits<float>::infinity() )
|
||||
{
|
||||
setNormalOnA( Vector3(1.0f, 0.0f, 0.0f ) );
|
||||
}
|
||||
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||
|
||||
void setPivotA( const Vector3& _pivotA ) { pointA = _pivotA; }
|
||||
void setPivotB( const Vector3& _pivotB ) { pointB = _pivotB; }
|
||||
void setNormalOnA( const Vector3& _normal );
|
||||
void setMaxNormalForce( float _maxForce ) { maxNormalForce = _maxForce; }
|
||||
bool computeBrokenState(
|
||||
const ConstraintVariables* _velocityStage,
|
||||
const ConstraintVariables* _positionStage,
|
||||
const SolverConfig& _config ) const override;
|
||||
|
||||
void serialize( DebugSerializer& s ) const override;
|
||||
|
||||
private:
|
||||
// Points on object A and B in object space, relative to center of mass
|
||||
Vector3 pointA;
|
||||
Vector3 pointB;
|
||||
Vector3 normalA;
|
||||
Vector3 tangentA1;
|
||||
Vector3 tangentA2;
|
||||
float maxNormalForce;
|
||||
bool broken;
|
||||
};
|
||||
|
||||
//
|
||||
// ConstraintAlign2Axes
|
||||
//
|
||||
class ConstraintAlign2Axes: public Constraint
|
||||
{
|
||||
public:
|
||||
ConstraintAlign2Axes( Body* _bodyA, Body* _bodyB );
|
||||
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||
|
||||
void setAxisA( const Vector3& a );
|
||||
void setAxisB( const Vector3& b );
|
||||
Vector3 getAxisA() const { return axisA; }
|
||||
Vector3 getAxisB() const { return axisB; }
|
||||
|
||||
Convergence testPGSConvergence( const float* _disp, const float* _residuals, const float* _deltaResiduals, const SolverConfig& _solverConfig ) override;
|
||||
void serialize( DebugSerializer& s ) const override;
|
||||
|
||||
private:
|
||||
// Axis on body A in object space
|
||||
Vector3 axisA;
|
||||
|
||||
// 2 normal axes to the axis on body B
|
||||
// In object space
|
||||
Vector3 axisB;
|
||||
Vector3 orthogonalAxisB1;
|
||||
Vector3 orthogonalAxisB2;
|
||||
|
||||
// Cache
|
||||
Vector3 worldSpaceOrthogonalB1;
|
||||
Vector3 worldSpaceOrthogonalB2;
|
||||
};
|
||||
|
||||
//
|
||||
// ConstraintAngularVelocity
|
||||
//
|
||||
class ConstraintAngularVelocity: public Constraint
|
||||
{
|
||||
public:
|
||||
ConstraintAngularVelocity( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_AngularVelocity, _bodyA, _bodyB, 1 ),
|
||||
maxForce( 0.0f ),
|
||||
desiredAngularVelocity( 0.0f ) { }
|
||||
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||
|
||||
void setAxisA( const Vector3& a ) { axisA = a; }
|
||||
void setAxisB( const Vector3& b ) { axisB = b; }
|
||||
void setDesiredAngularVelocity( float _v ) { desiredAngularVelocity = _v; }
|
||||
void setMaxForce( float _f ) { maxForce = _f; }
|
||||
|
||||
void serialize( DebugSerializer& s ) const override;
|
||||
|
||||
private:
|
||||
Vector3 axisA;
|
||||
Vector3 axisB;
|
||||
float maxForce;
|
||||
float desiredAngularVelocity;
|
||||
};
|
||||
|
||||
//
|
||||
// ConstraintLinearVelocity
|
||||
//
|
||||
class ConstraintLinearVelocity: public Constraint
|
||||
{
|
||||
public:
|
||||
ConstraintLinearVelocity( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_LinearVelocity, _bodyA, _bodyB, 3 ), maxForce(0.0f), desiredVelocity(0.0f, 0.0f, 0.0f) { }
|
||||
|
||||
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||
|
||||
void setDesiredVelocity( const Vector3& _v ) { desiredVelocity = _v; }
|
||||
void setMaxForce( const Vector3& _f ) { maxForce = _f; }
|
||||
|
||||
void serialize( DebugSerializer& s ) const override;
|
||||
|
||||
private:
|
||||
Vector3 maxForce;
|
||||
Vector3 desiredVelocity;
|
||||
};
|
||||
|
||||
class ConstraintLinearSpring: public Constraint
|
||||
{
|
||||
public:
|
||||
ConstraintLinearSpring( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_LinearSpring, _bodyA, _bodyB, 3 ), pivotA(0.0f), pivotB(0.0f), maxForce(0.0f), p(0.0f), d(0.0f) { }
|
||||
|
||||
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||
|
||||
void setPivotA( const Vector3& _pivotA ) { pivotA = _pivotA; }
|
||||
void setPivotB( const Vector3& _pivotB ) { pivotB = _pivotB; }
|
||||
void setMaxForce( const Vector3& _f ) { maxForce = _f; }
|
||||
void setPD( float _p, float _d ) { p = _p; d = _d; }
|
||||
|
||||
void serialize( DebugSerializer& s ) const override;
|
||||
|
||||
private:
|
||||
Vector3 pivotA;
|
||||
Vector3 pivotB;
|
||||
Vector3 maxForce;
|
||||
float p, d;
|
||||
};
|
||||
|
||||
class ConstraintAchievePosition: public Constraint
|
||||
{
|
||||
public:
|
||||
ConstraintAchievePosition( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_AchievePosition, _bodyA, _bodyB, 3 ), maxForce( 0.0f ), targetVelocity( 0.0f ) { }
|
||||
|
||||
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||
|
||||
void setPivotA( const Vector3& _pivotA ) { pivotA = _pivotA; }
|
||||
void setPivotB( const Vector3& _pivotB ) { pivotB = _pivotB; }
|
||||
void setTargetVelocity( const Vector3& _v ) { targetVelocity = _v; }
|
||||
void setMaxForce( const Vector3& _f ) { maxForce = _f; }
|
||||
void setMinForce( const Vector3& _f ) { minForce = _f; }
|
||||
|
||||
void serialize( DebugSerializer& s ) const override;
|
||||
|
||||
private:
|
||||
Vector3 pivotA;
|
||||
Vector3 pivotB;
|
||||
Vector3 maxForce;
|
||||
Vector3 minForce;
|
||||
Vector3 targetVelocity;
|
||||
};
|
||||
|
||||
class ConstraintBodyAngularVelocity: public Constraint
|
||||
{
|
||||
public:
|
||||
ConstraintBodyAngularVelocity( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_BodyAngularVelocity, _bodyA, _bodyB, 3 ), targetAngularVelocity( 0.0f ), maxTorque( 0.0f ), minTorque( 0.0f ), useIntegratedVelocities( false ) { }
|
||||
|
||||
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||
|
||||
void serialize( DebugSerializer& s ) const override;
|
||||
|
||||
// The vector values need to be provided in object space of body A
|
||||
void setTarget( const Vector3& v ) { targetAngularVelocity = v; }
|
||||
void setMaxTorque( const Vector3& v ) { maxTorque = v; }
|
||||
void setMinTorque( const Vector3& v ) { minTorque = v; }
|
||||
void setUseIntegratedVelocities( bool flag ) { useIntegratedVelocities = flag; }
|
||||
|
||||
private:
|
||||
Vector3 targetAngularVelocity;
|
||||
Vector3 maxTorque;
|
||||
Vector3 minTorque;
|
||||
bool useIntegratedVelocities;
|
||||
};
|
||||
|
||||
class ConstraintLegacyAngularVelocity: public Constraint
|
||||
{
|
||||
public:
|
||||
ConstraintLegacyAngularVelocity( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_LegacyAngularVelocity, _bodyA, _bodyB, 3 ), targetAngularVelocity( 0.0f ), maxTorque( 0.0f ), minTorque( 0.0f ), useIntegratedVelocities( false ) { }
|
||||
|
||||
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||
|
||||
void serialize( DebugSerializer& s ) const override;
|
||||
|
||||
// The vector values need to be provided in object space of body A
|
||||
void setTarget( const Vector3& v ) { targetAngularVelocity = v; }
|
||||
void setMaxTorque( const Vector3& v ) { maxTorque = v; }
|
||||
void setMinTorque( const Vector3& v ) { minTorque = v; }
|
||||
void setUseIntegratedVelocities( bool flag ) { useIntegratedVelocities = flag; }
|
||||
|
||||
private:
|
||||
Vector3 targetAngularVelocity;
|
||||
Vector3 maxTorque;
|
||||
Vector3 minTorque;
|
||||
bool useIntegratedVelocities;
|
||||
};
|
||||
|
||||
//
|
||||
// ConstraintCollision
|
||||
//
|
||||
class ConstraintCollision: public Constraint
|
||||
{
|
||||
public:
|
||||
ConstraintCollision( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_Collision, _bodyA, _bodyB, 3 )
|
||||
{
|
||||
cachedTangent1 = Vector3( 1.0f, 0.0f, 0.0f );
|
||||
getCache(0).positionSor = 1.0f;
|
||||
getCache(0).velocitySor = 1.0f;
|
||||
getCache(1).positionSor = 1.0f;
|
||||
getCache(1).velocitySor = 1.0f;
|
||||
getCache(2).positionSor = 1.0f;
|
||||
getCache(2).velocitySor = 1.0f;
|
||||
}
|
||||
|
||||
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||
void setNormal( const Vector3& _normal ) { normal = _normal; }
|
||||
void setPointA( const Vector3& _pointA ) { pointA = _pointA; }
|
||||
void setDepth( float _d ) { depth = _d; }
|
||||
void setFriction( float _f ) { friction = _f; }
|
||||
void setResititution( float _r ) { restitution = _r; }
|
||||
|
||||
Convergence testPGSConvergence( const float* _disp, const float* _residuals, const float* _deltaResiduals, const SolverConfig& _solverConfig ) override;
|
||||
void serialize( DebugSerializer& s ) const override;
|
||||
private:
|
||||
Vector3 normal;
|
||||
Vector3 pointA;
|
||||
float depth;
|
||||
float friction;
|
||||
float restitution;
|
||||
|
||||
// Cache
|
||||
Vector3 cachedTangent1;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,274 @@
|
||||
#pragma once
|
||||
|
||||
#include "solver/SolverConfig.h"
|
||||
#include "solver/SolverContainers.h"
|
||||
#include "G3D/Vector3.h"
|
||||
|
||||
#include "boost/limits.hpp"
|
||||
#include "boost/math/constants/constants.hpp"
|
||||
#include "boost/container/vector.hpp"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "simd/simd.h"
|
||||
#include "rbx/ArrayDynamic.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
|
||||
class DebugSerializer;
|
||||
class ConstraintJacobianPair;
|
||||
|
||||
//
|
||||
// Use class definition rather than typedef so we can forward declare
|
||||
//
|
||||
class BodyPairIndices: public std::pair< int, int >
|
||||
{
|
||||
public:
|
||||
inline BodyPairIndices() { }
|
||||
inline BodyPairIndices( int a, int b ): std::pair< int, int >( a, b ) { }
|
||||
};
|
||||
|
||||
//
|
||||
// VirtualDisplacement: http://en.wikipedia.org/wiki/Virtual_displacement
|
||||
// A 6-dimensional vector with a linear part and angular part
|
||||
//
|
||||
|
||||
// This is a version that allows conversion from non-simd to simd types.
|
||||
// The non-simd is still used by integration.
|
||||
class VirtualDisplacementPOD
|
||||
{
|
||||
public:
|
||||
void serialize( DebugSerializer& s ) const;
|
||||
union
|
||||
{
|
||||
simd::v4f_pod linV4;
|
||||
Vector3Pod lin;
|
||||
};
|
||||
union
|
||||
{
|
||||
simd::v4f_pod angV4;
|
||||
Vector3Pod ang;
|
||||
};
|
||||
};
|
||||
|
||||
// This is a version that can be worked with in simd
|
||||
// It's only ever used on the stack
|
||||
class VirtualDisplacement
|
||||
{
|
||||
public:
|
||||
RBX_SIMD_INLINE VirtualDisplacement( ){ }
|
||||
RBX_SIMD_INLINE VirtualDisplacement( const simd::v4f& linear, const simd::v4f& angular ): lin( linear ), ang( angular ) { }
|
||||
RBX_SIMD_INLINE VirtualDisplacement( const VirtualDisplacementPOD& _v ): lin( _v.linV4 ), ang( _v.angV4 ) { }
|
||||
RBX_SIMD_INLINE operator VirtualDisplacementPOD()
|
||||
{
|
||||
VirtualDisplacementPOD r;
|
||||
r.linV4 = lin;
|
||||
r.angV4 = ang;
|
||||
return r;
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE void reset()
|
||||
{
|
||||
lin = simd::zerof();
|
||||
ang = simd::zerof();
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE simd::v4f getLin() const { return lin; }
|
||||
RBX_SIMD_INLINE simd::v4f getAng() const { return ang; }
|
||||
|
||||
void serialize( DebugSerializer& s ) const;
|
||||
|
||||
private:
|
||||
simd::v4f lin;
|
||||
simd::v4f ang;
|
||||
};
|
||||
|
||||
//
|
||||
// Array of virtual displacements
|
||||
//
|
||||
class VirtualDisplacementArray
|
||||
{
|
||||
public:
|
||||
RBX_SIMD_INLINE VirtualDisplacementArray( size_t _size, size_t alignment ): size( _size ), data( _size, ArrayNoInit(), alignment )
|
||||
{ }
|
||||
|
||||
inline void reset()
|
||||
{
|
||||
VirtualDisplacement z( simd::zerof(), simd::zerof() );
|
||||
for( size_t i = 0; i < size; i++ )
|
||||
{
|
||||
data[ i ] = z;
|
||||
}
|
||||
}
|
||||
|
||||
const VirtualDisplacementPOD* getData() const { return data.data(); }
|
||||
VirtualDisplacementPOD* getData() { return data.data(); }
|
||||
RBX_SIMD_INLINE size_t getSize() const { return size; }
|
||||
|
||||
RBX_SIMD_INLINE VirtualDisplacementPOD operator[]( int i ) const
|
||||
{
|
||||
RBXASSERT_VERY_FAST( (size_t)i < size );
|
||||
return data[ i ];
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE VirtualDisplacementPOD& operator[]( int i )
|
||||
{
|
||||
RBXASSERT_VERY_FAST( (size_t)i < size );
|
||||
return data[ i ];
|
||||
}
|
||||
|
||||
void serialize( DebugSerializer& s ) const;
|
||||
|
||||
private:
|
||||
size_t size;
|
||||
ArrayDynamic< VirtualDisplacementPOD > data;
|
||||
};
|
||||
|
||||
//
|
||||
// Effective mass vectors: inverse mass matrix * jacobian
|
||||
//
|
||||
class EffectiveMass
|
||||
{
|
||||
public:
|
||||
RBX_SIMD_INLINE EffectiveMass() { }
|
||||
RBX_SIMD_INLINE EffectiveMass( const simd::v4f& linear, const simd::v4f& angular ): lin( linear ), ang( angular ) { }
|
||||
RBX_SIMD_INLINE void applyMultiplier( const simd::v4f& m )
|
||||
{
|
||||
lin = m * lin;
|
||||
ang = m * ang;
|
||||
}
|
||||
RBX_SIMD_INLINE void reset()
|
||||
{
|
||||
lin = simd::zerof();
|
||||
ang = simd::zerof();
|
||||
}
|
||||
RBX_SIMD_INLINE simd::v4f getLin() const { return lin; }
|
||||
RBX_SIMD_INLINE simd::v4f getAng() const { return ang; }
|
||||
|
||||
private:
|
||||
simd::v4f lin;
|
||||
simd::v4f ang;
|
||||
};
|
||||
|
||||
class EffectiveMassPair
|
||||
{
|
||||
public:
|
||||
RBX_SIMD_INLINE EffectiveMassPair( const EffectiveMass& _a, const EffectiveMass& _b ): a( _a ), b( _b ) { }
|
||||
|
||||
RBX_SIMD_INLINE EffectiveMassPair( ) { }
|
||||
|
||||
RBX_SIMD_INLINE void reset()
|
||||
{
|
||||
a.reset();
|
||||
b.reset();
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE void applyMultipliers( const simd::v4f& mA, const simd::v4f& mB )
|
||||
{
|
||||
a.applyMultiplier( mA );
|
||||
b.applyMultiplier( mB );
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE simd::v4f getLinA() const { return a.getLin(); }
|
||||
RBX_SIMD_INLINE simd::v4f getLinB() const { return b.getLin(); }
|
||||
RBX_SIMD_INLINE simd::v4f getAngA() const { return a.getAng(); }
|
||||
RBX_SIMD_INLINE simd::v4f getAngB() const { return b.getAng(); }
|
||||
|
||||
RBX_SIMD_INLINE EffectiveMass getPartA() const { return a; }
|
||||
RBX_SIMD_INLINE EffectiveMass getPartB() const { return b; }
|
||||
|
||||
void serialize( DebugSerializer& s ) const;
|
||||
|
||||
private:
|
||||
EffectiveMass a;
|
||||
EffectiveMass b;
|
||||
};
|
||||
|
||||
//
|
||||
// Jacobian of a binary constraint
|
||||
//
|
||||
class ConstraintJacobian
|
||||
{
|
||||
public:
|
||||
RBX_SIMD_INLINE void reset()
|
||||
{
|
||||
linV4 = simd::zerof();
|
||||
angV4 = simd::zerof();
|
||||
}
|
||||
|
||||
union
|
||||
{
|
||||
Vector3Pod lin;
|
||||
simd::v4f_pod linV4;
|
||||
};
|
||||
union
|
||||
{
|
||||
Vector3Pod ang;
|
||||
simd::v4f_pod angV4;
|
||||
};
|
||||
};
|
||||
|
||||
class ConstraintJacobianPair
|
||||
{
|
||||
public:
|
||||
class LinA;
|
||||
class LinB;
|
||||
class AngA;
|
||||
class AngB;
|
||||
|
||||
template< class PartSelect >
|
||||
RBX_SIMD_INLINE simd::v4f get() const;
|
||||
|
||||
RBX_SIMD_INLINE simd::v4f getLinA() const { return a.linV4; }
|
||||
RBX_SIMD_INLINE simd::v4f getLinB() const { return b.linV4; }
|
||||
RBX_SIMD_INLINE simd::v4f getAngA() const { return a.angV4; }
|
||||
RBX_SIMD_INLINE simd::v4f getAngB() const { return b.angV4; }
|
||||
|
||||
template< class PartSelect >
|
||||
RBX_SIMD_INLINE void set( const simd::v4f& v );
|
||||
|
||||
RBX_SIMD_INLINE void setLinA( const simd::v4f& v ) { a.linV4 = v; }
|
||||
RBX_SIMD_INLINE void setLinB( const simd::v4f& v ) { b.linV4 = v; }
|
||||
RBX_SIMD_INLINE void setAngA( const simd::v4f& v ) { a.angV4 = v; }
|
||||
RBX_SIMD_INLINE void setAngB( const simd::v4f& v ) { b.angV4 = v; }
|
||||
|
||||
RBX_SIMD_INLINE void reset()
|
||||
{
|
||||
a.reset();
|
||||
b.reset();
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE simd::v4f dot( const EffectiveMassPair& _v ) const
|
||||
{
|
||||
simd::v4f partA = getLinA() * _v.getLinA() + getAngA() * _v.getAngA();
|
||||
simd::v4f partB = getLinB() * _v.getLinB() + getAngB() * _v.getAngB();
|
||||
simd::v4f r = partA + partB;
|
||||
return simd::splat<0>(r) + simd::splat<1>(r) + simd::splat<2>(r);
|
||||
}
|
||||
|
||||
void serialize( DebugSerializer& s ) const;
|
||||
|
||||
ConstraintJacobian a;
|
||||
ConstraintJacobian b;
|
||||
};
|
||||
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f ConstraintJacobianPair::get< ConstraintJacobianPair::LinA >() const { return a.linV4; }
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f ConstraintJacobianPair::get< ConstraintJacobianPair::LinB >() const { return b.linV4; }
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f ConstraintJacobianPair::get< ConstraintJacobianPair::AngA >() const { return a.angV4; }
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f ConstraintJacobianPair::get< ConstraintJacobianPair::AngB >() const { return b.angV4; }
|
||||
|
||||
template< >
|
||||
RBX_SIMD_INLINE void ConstraintJacobianPair::set< ConstraintJacobianPair::LinA >( const simd::v4f& v ) { a.linV4 = v; }
|
||||
template< >
|
||||
RBX_SIMD_INLINE void ConstraintJacobianPair::set< ConstraintJacobianPair::LinB >( const simd::v4f& v ) { b.linV4 = v; }
|
||||
template< >
|
||||
RBX_SIMD_INLINE void ConstraintJacobianPair::set< ConstraintJacobianPair::AngA >( const simd::v4f& v ) { a.angV4 = v; }
|
||||
template< >
|
||||
RBX_SIMD_INLINE void ConstraintJacobianPair::set< ConstraintJacobianPair::AngB >( const simd::v4f& v ) { b.angV4 = v; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/G3DCore.h"
|
||||
#include "util/Quaternion.h"
|
||||
|
||||
#include "boost/type_traits.hpp"
|
||||
#include "boost/utility.hpp"
|
||||
#include "boost/cstdint.hpp"
|
||||
#include "boost/container/map.hpp"
|
||||
|
||||
#include "simd/simd.h"
|
||||
#include "rbx/ArrayDynamic.h"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
|
||||
class DebugSerializer;
|
||||
|
||||
// Compile time 'Has X Method' implementation using 'Substitution Failure is not an Error'
|
||||
template< typename T >
|
||||
struct HasSerializeMethod
|
||||
{
|
||||
private:
|
||||
template<typename U, void (U::*)( DebugSerializer& ) const> struct SFINAE {};
|
||||
template<typename U> static char Test(SFINAE<U, &U::serialize>*);
|
||||
template<typename U> static int Test(...);
|
||||
public:
|
||||
static const bool value = sizeof(Test<T>(0)) == sizeof(char);
|
||||
};
|
||||
|
||||
class DebugSerializerScope
|
||||
{
|
||||
public:
|
||||
DebugSerializerScope( DebugSerializer& s );
|
||||
~DebugSerializerScope();
|
||||
|
||||
private:
|
||||
DebugSerializer& serializer;
|
||||
size_t reservedBufferIndex;
|
||||
size_t currentSize;
|
||||
};
|
||||
|
||||
class DebugSerializer
|
||||
{
|
||||
public:
|
||||
void clear()
|
||||
{
|
||||
data.clear();
|
||||
}
|
||||
|
||||
template< class T >
|
||||
typename boost::enable_if< boost::is_arithmetic< T >, DebugSerializer >::type& storeAt( const T& t, size_t index )
|
||||
{
|
||||
union
|
||||
{
|
||||
T t;
|
||||
char bytes[ sizeof( T ) ];
|
||||
} u;
|
||||
u.t = t;
|
||||
for( size_t i = 0; i < sizeof( T ); i++ )
|
||||
{
|
||||
data[ index + i ] = u.bytes[ i ];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< class T >
|
||||
typename boost::enable_if< boost::is_arithmetic< T >, DebugSerializer >::type& operator&( const T& t )
|
||||
{
|
||||
size_t index = data.size();
|
||||
data.resize( data.size() + sizeof( T ) );
|
||||
storeAt( t, index );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< class T >
|
||||
typename boost::enable_if< boost::is_enum< T >, DebugSerializer >::type& operator&( const T& t )
|
||||
{
|
||||
union
|
||||
{
|
||||
T t;
|
||||
boost::uint8_t bytes[ sizeof( T ) ];
|
||||
} u;
|
||||
u.t = t;
|
||||
for( size_t i = 0; i < sizeof( T ); i++ )
|
||||
{
|
||||
data.push_back( u.bytes[ i ] );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
DebugSerializer& operator&( const Vector3& v )
|
||||
{
|
||||
*this & v.x & v.y & v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
DebugSerializer& operator&( const Quaternion& q )
|
||||
{
|
||||
*this & q.x & q.y & q.z & q.w;
|
||||
return *this;
|
||||
}
|
||||
|
||||
DebugSerializer& operator&( const Matrix3& m )
|
||||
{
|
||||
*this & m.row( 0 ) & m.row( 1 ) & m.row( 2 );
|
||||
return *this;
|
||||
}
|
||||
|
||||
DebugSerializer& operator&( const simd::v4f& v )
|
||||
{
|
||||
*this & simd::extractSlow( v, 0 ) & simd::extractSlow( v, 1 ) & simd::extractSlow( v, 2 ) & simd::extractSlow( v, 3 );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< class T, class U >
|
||||
DebugSerializer& operator&( const std::pair< T, U >& p )
|
||||
{
|
||||
*this & p.first & p.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< class T >
|
||||
DebugSerializer& operator&( const ArrayBase<T>& v )
|
||||
{
|
||||
*this & boost::uint32_t( v.size() );
|
||||
for( const auto& e : v )
|
||||
{
|
||||
*this & e;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< class T >
|
||||
DebugSerializer& operator&( const std::vector<T>& v )
|
||||
{
|
||||
*this & boost::uint32_t( v.size() );
|
||||
for( const auto& e : v )
|
||||
{
|
||||
*this & e;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< class T >
|
||||
typename boost::enable_if_c< HasSerializeMethod< T >::value && !boost::is_pointer< T >::value, DebugSerializer >::type& operator&( const T& t )
|
||||
{
|
||||
t.serialize( *this );
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< class T >
|
||||
typename boost::enable_if_c< HasSerializeMethod< T >::value, DebugSerializer >::type& operator&( const T* const t )
|
||||
{
|
||||
t->serialize( *this );
|
||||
return *this;
|
||||
}
|
||||
|
||||
DebugSerializer& tag( const char* name )
|
||||
{
|
||||
boost::uint8_t length = strlen(name);
|
||||
*this & length;
|
||||
for( boost::uint8_t i = 0; i < length; i++ )
|
||||
{
|
||||
*this & name[ i ];
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::vector< char > data;
|
||||
};
|
||||
|
||||
inline DebugSerializerScope::DebugSerializerScope( DebugSerializer& s ): serializer( s )
|
||||
{
|
||||
reservedBufferIndex = s.data.size();
|
||||
size_t size = 0;
|
||||
s & size;
|
||||
// size_t checkSum = 0;
|
||||
// s & checkSum;
|
||||
currentSize = s.data.size();
|
||||
}
|
||||
|
||||
inline DebugSerializerScope::~DebugSerializerScope()
|
||||
{
|
||||
size_t size = serializer.data.size() - currentSize;
|
||||
serializer.storeAt( size, reservedBufferIndex );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
#pragma once
|
||||
|
||||
#include "solver/SolverConfig.h"
|
||||
#include "solver/Constraint.h"
|
||||
#include "solver/SolverContainers.h"
|
||||
#include "solver/SolverProfiler.h"
|
||||
#include "solver/SolverSerializer.h"
|
||||
|
||||
#include "v8kernel/SimBody.h"
|
||||
|
||||
#include "boost/unordered/unordered_map.hpp"
|
||||
#include "boost/unordered/unordered_set.hpp"
|
||||
#include "boost/container/vector.hpp"
|
||||
#include <map>
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
|
||||
class ContactConnector;
|
||||
class RotateJoint;
|
||||
class ContactManifold;
|
||||
class Body;
|
||||
|
||||
typedef std::pair< boost::uint64_t, boost::uint64_t > BodyUIDPair;
|
||||
|
||||
class InconsistentBodyPair
|
||||
{
|
||||
public:
|
||||
bool operator<( const InconsistentBodyPair& pair ) const
|
||||
{
|
||||
return bodyPair < pair.bodyPair;
|
||||
}
|
||||
|
||||
Body* bodyA;
|
||||
Body* bodyB;
|
||||
BodyUIDPair bodyPair;
|
||||
Constraint::Convergence convergence;
|
||||
};
|
||||
|
||||
class OrderedConnector
|
||||
{
|
||||
public:
|
||||
ContactConnector* connector;
|
||||
bool swap;
|
||||
};
|
||||
|
||||
class BadConnector
|
||||
{
|
||||
public:
|
||||
Vector3 position;
|
||||
Constraint::Convergence convergence;
|
||||
};
|
||||
|
||||
class PGSSolver
|
||||
{
|
||||
public:
|
||||
PGSSolver();
|
||||
|
||||
// Add/remove SimBodies
|
||||
// High priority bodies will be simulated even if throttled
|
||||
void addSimBody( SimBody* body, bool highPriority );
|
||||
void removeSimBody( SimBody* body );
|
||||
|
||||
// Add/remove constraints
|
||||
void addConstraint( Constraint* _constraint );
|
||||
void removeConstraint( Constraint* _constraint );
|
||||
|
||||
// Solver
|
||||
// If throttled is set to true, only high priority bodies will be simulated.
|
||||
void solve( const std::vector< ContactConnector* >& connectors, float dt, boost::uint64_t debugTime, bool throttled );
|
||||
void solvePositions( const std::vector< ContactConnector* >& _contactConnectors );
|
||||
// Exactly like it was before the physics analyzer (sleeping islands) were submitted
|
||||
void solveLegacy( const std::vector< ContactConnector* >& _contactConnectors, float _dt, boost::uint64_t debugTime, bool _throttled );
|
||||
|
||||
// Create and delete contact manifolds
|
||||
// The parameters are uid's of both Object instances.
|
||||
void addContactManifold( boost::uint64_t _uidA, boost::uint64_t _uidB );
|
||||
void removeContactManifold( boost::uint64_t _uidA, boost::uint64_t _uidB );
|
||||
|
||||
// Clear body cache
|
||||
void clearBodyCache( boost::uint64_t _uid );
|
||||
|
||||
// Switch inconsistent constraint detector
|
||||
void setInconsistentConstraintDetectorEnabled( bool value ) { inconsistentConstraintDetectorEnabled = value; }
|
||||
void setPhysicsAnalyzerBreakOnIssue( bool value ) { physicsAnalyzerBreakOnIssue = value; }
|
||||
bool getPhysicsAnalyzerBreakOnIssue( ) const { return physicsAnalyzerBreakOnIssue; }
|
||||
|
||||
const ArrayBase< InconsistentBodyPair >& getInconsistentBodyPairs() const { return inconsistentBodyPairs; }
|
||||
const ArrayBase< ArrayDynamic< boost::uint64_t > >& getInconsistentBodies() const { return inconsistentBodies; }
|
||||
|
||||
void dumpLog( bool enable );
|
||||
void setUserId( int id ) { userId = id; }
|
||||
|
||||
private:
|
||||
void solveInternal( const std::vector< ContactConnector* >& connectors, float dt, boost::uint64_t debugTime, bool throttled, const SolverConfig& _solverConfig );
|
||||
void solveIsland( const ArrayDynamic< Constraint* >& constraints, const ArrayDynamic< SimBody* >& selectedSimBodies,
|
||||
float _dt, const SolverConfig& _solverConfig );
|
||||
ContactManifold* updateContactManifold( const BodyUIDPair& _pairId, const ArrayBase< OrderedConnector >& _manifold );
|
||||
size_t addContactConnectors( ArrayDynamic< ContactManifold* >& _activeManifolds, const std::vector< ContactConnector* >& _connectors, const boost::unordered_set< SimBody* >& _simBodies );
|
||||
void initAnchoredObjects(
|
||||
ArrayDynamic< SolverBodyDynamicProperties >& _bodyVariableData,
|
||||
ArrayDynamic< SolverBodyStaticProperties >& _bodyStaticData,
|
||||
ArrayDynamic< SolverBodyMassAndInertia >& _massAndInertia,
|
||||
ArrayDynamic< float >& _effectiveMassMultipliers,
|
||||
VirtualDisplacementArray& _velocityDeltas,
|
||||
VirtualDisplacementArray& _positionDeltas,
|
||||
int offsetToAnchoredObjects,
|
||||
const ArrayBase< SimBody* >& _anchoredBodyList,
|
||||
const SolverConfig& _config ) const;
|
||||
void integratePositionsAndUpdateSimBodies(
|
||||
SimBody* const * _simBodies,
|
||||
SolverBodyDynamicProperties* const _bodyVariableData,
|
||||
const SolverBodyStaticProperties* const _bodyStaticData,
|
||||
size_t _simBodyCount,
|
||||
const VirtualDisplacementArray& _velocityDeltas,
|
||||
const VirtualDisplacementArray& _positionDeltas,
|
||||
float _dt );
|
||||
void integratePositionsIgnoreVelocitiesAndUpdateSimBodies(
|
||||
SimBody* const * _simBodies,
|
||||
SolverBodyDynamicProperties* const _bodyVariableData,
|
||||
const SolverBodyStaticProperties* const _bodyStaticData,
|
||||
size_t _simBodyCount,
|
||||
const VirtualDisplacementArray& _positionDeltas,
|
||||
float _dt );
|
||||
void detectInconsistentConstraints(
|
||||
VirtualDisplacementArray& positionDeltasSIMD,
|
||||
ArrayBase< ConstraintVariables >& positionStage,
|
||||
const ArrayBase< ConstraintJacobianPair >& jacobians,
|
||||
const ArrayBase< ConstraintJacobianPair >& preconditionedJacobiansPosStage,
|
||||
const ArrayBase< EffectiveMassPair >& effectiveMassesPos,
|
||||
const ArrayBase< float >& sorPos,
|
||||
const ArrayBase< boost::uint8_t >& dimensions,
|
||||
const ArrayBase< boost::uint32_t >& offsets,
|
||||
const ArrayBase< BodyPairIndices >& simBodyPairs,
|
||||
const ArrayBase< Constraint* >& constraints,
|
||||
size_t collisionCount,
|
||||
const SolverConfig& solverConfig );
|
||||
|
||||
|
||||
boost::uint64_t constraintUIDGenerator;
|
||||
// Pure constraints - not including the Collision constraints
|
||||
SolverOrderedMap< boost::uint64_t, Constraint* >::Type pureConstraintSet;
|
||||
|
||||
SolverUnorderedMap< BodyUIDPair, ContactManifold* >::Type contactManifolds;
|
||||
|
||||
class SolverBodyCache
|
||||
{
|
||||
public:
|
||||
void serialize( DebugSerializer& s ) const;
|
||||
Vector3 virDPosStageLin;
|
||||
Vector3 virDPosStageAng;
|
||||
Vector3 virDVelStageLin;
|
||||
Vector3 virDVelStageAng;
|
||||
Vector3 linearVelocity;
|
||||
Vector3 angularVelocity;
|
||||
Vector3 integratedLinearVelocity;
|
||||
Vector3 integratedAngularVelocity;
|
||||
SimBody* simBodyDebug;
|
||||
};
|
||||
|
||||
SolverUnorderedMap< boost::uint64_t, SolverBodyCache >::Type bodyCache;
|
||||
boost::unordered_set< SimBody* > simBodies;
|
||||
boost::unordered_set< SimBody* > highPrioritySimBodies;
|
||||
|
||||
// Inconsistent constraint detector
|
||||
bool inconsistentConstraintDetectorEnabled;
|
||||
bool physicsAnalyzerBreakOnIssue;
|
||||
ArrayDynamic< InconsistentBodyPair > inconsistentBodyPairs;
|
||||
ArrayDynamic< ArrayDynamic< boost::uint64_t > > inconsistentBodies;
|
||||
|
||||
// Serializer
|
||||
SolverSerializer serializer;
|
||||
|
||||
// Profilers
|
||||
SolverProfiler gatherCollisionsProfiler;
|
||||
SolverProfiler islandSplitProfiler;
|
||||
SolverProfiler integrateVelocitiesProfiler;
|
||||
SolverProfiler initAnchoredBodiesProfiler;
|
||||
SolverProfiler buildEquationsProfiler;
|
||||
SolverProfiler computeEffectiveMassesProfiler;
|
||||
SolverProfiler preconditioningProfiler;
|
||||
SolverProfiler multiplyEffectiveMassMultipliersProfiler;
|
||||
SolverProfiler initVirDProfiler;
|
||||
SolverProfiler kernelProfiler;
|
||||
SolverProfiler integratePositionsProfiler;
|
||||
SolverProfiler writeCacheProfiler;
|
||||
SolverProfiler solverProfiler;
|
||||
|
||||
bool dumpLogSwitch;
|
||||
int userId;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
#pragma once
|
||||
|
||||
#include "G3D/Vector3.h"
|
||||
#include "simd/simd.h"
|
||||
#include "solver/SolverContainers.h"
|
||||
#include "solver/ConstraintJacobian.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
class DebugSerializer;
|
||||
|
||||
//
|
||||
// Internal representation of dynamic properties of a body (for both simulated and anchored)
|
||||
//
|
||||
class SolverBodyDynamicProperties
|
||||
{
|
||||
public:
|
||||
void serialize( DebugSerializer& s ) const;
|
||||
|
||||
Vector3 integratedLinearVelocity;
|
||||
Vector3 integratedAngularVelocity;
|
||||
Matrix3 orientation;
|
||||
Vector3 position;
|
||||
Vector3 linearVelocity;
|
||||
Vector3 angularVelocity;
|
||||
};
|
||||
|
||||
//
|
||||
// Symmetric matrix for use as inertia matrix
|
||||
//
|
||||
class SymmetricMatrix
|
||||
{
|
||||
public:
|
||||
RBX_SIMD_INLINE Vector3 operator*( const Vector3& v ) const
|
||||
{
|
||||
Vector3 r;
|
||||
r.x = diagonals.x * v.x + offDiagonals.x * v.y + offDiagonals.y * v.z;
|
||||
r.y = offDiagonals.x * v.x + diagonals.y * v.y + offDiagonals.z * v.z;
|
||||
r.z = offDiagonals.y * v.x + offDiagonals.z * v.y + diagonals.z * v.z;
|
||||
return r;
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE SymmetricMatrix operator*( float s ) const
|
||||
{
|
||||
SymmetricMatrix r;
|
||||
r.diagonals = s * diagonals;
|
||||
r.offDiagonals = s * offDiagonals;
|
||||
return r;
|
||||
}
|
||||
|
||||
void serialize( DebugSerializer& s ) const;
|
||||
|
||||
// [ d0 a b ]
|
||||
// [ a d1 c ]
|
||||
// [ b c d2]
|
||||
Vector3Pod diagonals; // [d0, d1, d2]
|
||||
Vector3Pod offDiagonals; // [a, b, c]
|
||||
};
|
||||
|
||||
class SymmetricMatrixPOD
|
||||
{
|
||||
public:
|
||||
simd::v4f_pod diagonals;
|
||||
simd::v4f_pod offDiagonals;
|
||||
};
|
||||
|
||||
//
|
||||
// SymmetricMatrixSIMD
|
||||
//
|
||||
class SymmetricMatrixSIMD
|
||||
{
|
||||
public:
|
||||
RBX_SIMD_INLINE SymmetricMatrixSIMD( const float* _m )
|
||||
{
|
||||
diagonals = simd::load3( _m );
|
||||
offDiagonals = simd::load3( _m + 3 );
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE SymmetricMatrixSIMD( const simd::v4f& _diagonal, const simd::v4f& _offDiagonal ): diagonals( _diagonal ), offDiagonals( _offDiagonal ) { }
|
||||
|
||||
RBX_SIMD_INLINE SymmetricMatrixSIMD( const SymmetricMatrixPOD& _m ): diagonals( _m.diagonals ), offDiagonals( _m.offDiagonals ) { }
|
||||
|
||||
template< int row, int column >
|
||||
RBX_SIMD_INLINE simd::v4f get() const;
|
||||
|
||||
RBX_SIMD_INLINE simd::v4f operator*( const simd::v4f& v ) const
|
||||
{
|
||||
simd::v4f t0 = diagonals * v;
|
||||
simd::v4f t1 = simd::permute<0, 2, 1, 3>( offDiagonals ) * simd::permute< 1, 2, 0, 3>( v );
|
||||
simd::v4f t2 = simd::permute<1, 0, 2, 3>( offDiagonals ) * simd::permute< 2, 0, 1, 3>( v );
|
||||
return t0 + t1 + t2;
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE void invert()
|
||||
{
|
||||
simd::v4f x00x00x02x01 = simd::shuffle< 0, 0, 1, 0 >( diagonals, offDiagonals );
|
||||
simd::v4f x11x00x01x12 = simd::shuffle< 1, 0, 0, 2 >( diagonals, offDiagonals );
|
||||
simd::v4f x22x00x12x02 = simd::shuffle< 2, 0, 2, 1 >( diagonals, offDiagonals );
|
||||
|
||||
simd::v4f x00x00x11x22 = simd::permute< 0, 0, 1, 2 >( diagonals );
|
||||
simd::v4f x12x12x02x01 = simd::permute< 2, 2, 1, 0 >( offDiagonals );
|
||||
|
||||
simd::v4f r = x00x00x02x01 * x11x00x01x12 * x22x00x12x02 - x00x00x11x22 * x12x12x02x01 * x12x12x02x01;
|
||||
simd::v4f d = simd::splat< 0 >( r ) + simd::splat< 2 >( r ) + simd::splat< 3 >( r );
|
||||
simd::v4f dInv = ( simd::splat( 1.0f ) / d );
|
||||
|
||||
simd::v4f x11x22x00 = simd::permute< 1, 2, 0, 3 >( diagonals );
|
||||
simd::v4f x22x00x11 = simd::permute< 2, 0, 1, 3 >( diagonals );
|
||||
simd::v4f x12x02x01 = simd::permute< 2, 1, 0, 3 >( offDiagonals );
|
||||
simd::v4f newDiagonals = dInv * ( x11x22x00 * x22x00x11 - x12x02x01 * x12x02x01 );
|
||||
|
||||
simd::v4f x12x01x02 = simd::permute< 2, 0, 1, 3 >( offDiagonals );
|
||||
simd::v4f x02x12x01 = simd::permute< 1, 2, 0, 3 >( offDiagonals );
|
||||
simd::v4f x01x02x12 = offDiagonals;
|
||||
simd::v4f x22x11x00 = simd::permute< 2, 1, 0, 3 >( diagonals );
|
||||
simd::v4f newOffdiagonals = dInv * ( x12x01x02 * x02x12x01 - x01x02x12 * x22x11x00 );
|
||||
|
||||
diagonals = newDiagonals;
|
||||
offDiagonals = newOffdiagonals;
|
||||
}
|
||||
|
||||
simd::v4f diagonals;
|
||||
simd::v4f offDiagonals;
|
||||
};
|
||||
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<0,0>() const { return simd::splat<0>( diagonals ); }
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<1,1>() const { return simd::splat<1>( diagonals ); }
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<2,2>() const { return simd::splat<2>( diagonals ); }
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<0,1>() const { return simd::splat<0>( offDiagonals ); }
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<0,2>() const { return simd::splat<1>( offDiagonals ); }
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<1,2>() const { return simd::splat<2>( offDiagonals ); }
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<1,0>() const { return get<0,1>(); }
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<2,0>() const { return get<0,2>(); }
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<2,1>() const { return get<1,2>(); }
|
||||
|
||||
static RBX_SIMD_INLINE SymmetricMatrixSIMD operator*( const simd::v4f& s, const SymmetricMatrixSIMD& m )
|
||||
{
|
||||
return SymmetricMatrixSIMD( s * m.diagonals, s* m.offDiagonals );
|
||||
}
|
||||
|
||||
//
|
||||
// SymmetricMatrix2SIMD
|
||||
//
|
||||
class SymmetricMatrix2SIMD
|
||||
{
|
||||
public:
|
||||
RBX_SIMD_INLINE SymmetricMatrix2SIMD( ) { }
|
||||
|
||||
RBX_SIMD_INLINE SymmetricMatrix2SIMD( const simd::v4f& d00, const simd::v4f& d11, const simd::v4f& d01 )
|
||||
{
|
||||
m = simd::gatherX( d00, d01, d01, d11 );
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE void load( const float* _m )
|
||||
{
|
||||
m = simd::form( _m[0], _m[2], _m[2], _m[1] );
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE void form( const simd::v4f& d00, const simd::v4f& d11, const simd::v4f& d01 )
|
||||
{
|
||||
m = simd::gatherX( d00, d01, d01, d11 );
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE simd::v4f operator*( const simd::v4f& v ) const
|
||||
{
|
||||
simd::v4f t0 = m * simd::permute< 0, 0, 1, 1 >( v );
|
||||
simd::v4f t1 = simd::permute< 2, 3, 0, 1 >( t0 );
|
||||
return t0 + t1;
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE void invert()
|
||||
{
|
||||
simd::v4f xt = simd::splat< 1 >( m );
|
||||
simd::v4f det = simd::splat< 0 >( m ) * simd::splat< 3 >( m ) - xt * xt;
|
||||
simd::v4f t = simd::select< 0, 1, 1, 0 >( simd::splat( 1.0f ), simd::splat( -1.0f ) ) * simd::permute< 3, 2, 1, 0 >( m );
|
||||
m = ( t / det );
|
||||
}
|
||||
|
||||
template< int row, int column >
|
||||
RBX_SIMD_INLINE simd::v4f get() const;
|
||||
|
||||
simd::v4f m;
|
||||
};
|
||||
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f SymmetricMatrix2SIMD::get<0,0>() const { return simd::splat<0>( m ); }
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f SymmetricMatrix2SIMD::get<1,0>() const { return simd::splat<1>( m ); }
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f SymmetricMatrix2SIMD::get<0,1>() const { return simd::splat<1>( m ); }
|
||||
template< >
|
||||
RBX_SIMD_INLINE simd::v4f SymmetricMatrix2SIMD::get<1,1>() const { return simd::splat<3>( m ); }
|
||||
|
||||
class SolverBodyMassAndInertia
|
||||
{
|
||||
public:
|
||||
void serialize( DebugSerializer& s ) const;
|
||||
|
||||
RBX_SIMD_INLINE SymmetricMatrixSIMD getInvInertiaVelStage() const
|
||||
{
|
||||
return inertiaSIMD;
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE SymmetricMatrixSIMD getInvInertiaPosStage( float scale ) const
|
||||
{
|
||||
simd::v4f inertiaScale = simd::splat( scale ) * simd::splat( posToVelMassRatio );
|
||||
SymmetricMatrixSIMD r( inertiaSIMD );
|
||||
return inertiaScale * r;
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE simd::v4f getInvMassVelStage() const
|
||||
{
|
||||
return simd::splat( massInvVelStage );
|
||||
}
|
||||
|
||||
RBX_SIMD_INLINE simd::v4f getInvMassPosStage() const
|
||||
{
|
||||
return simd::splat( massInvVelStage * posToVelMassRatio );
|
||||
}
|
||||
|
||||
class VelStage;
|
||||
class PosStage;
|
||||
|
||||
template< class StageSelect >
|
||||
RBX_SIMD_INLINE simd::v4f getInvMass() const;
|
||||
|
||||
template< class StageSelect >
|
||||
RBX_SIMD_INLINE SymmetricMatrixSIMD getInvInertia( float scale ) const;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
Vector3Pod inertiaDiagonal;
|
||||
float massInvVelStage;
|
||||
Vector3Pod inertiaOffDiagonal;
|
||||
float posToVelMassRatio;
|
||||
};
|
||||
SymmetricMatrixPOD inertiaSIMD;
|
||||
};
|
||||
};
|
||||
|
||||
template<>
|
||||
RBX_SIMD_INLINE simd::v4f SolverBodyMassAndInertia::getInvMass< SolverBodyMassAndInertia::VelStage >() const
|
||||
{
|
||||
return getInvMassVelStage();
|
||||
}
|
||||
|
||||
template<>
|
||||
RBX_SIMD_INLINE simd::v4f SolverBodyMassAndInertia::getInvMass< SolverBodyMassAndInertia::PosStage >() const
|
||||
{
|
||||
return getInvMassPosStage();
|
||||
}
|
||||
|
||||
template< >
|
||||
RBX_SIMD_INLINE SymmetricMatrixSIMD SolverBodyMassAndInertia::getInvInertia< SolverBodyMassAndInertia::VelStage >( float scale ) const
|
||||
{
|
||||
return getInvInertiaVelStage();
|
||||
}
|
||||
|
||||
template< >
|
||||
RBX_SIMD_INLINE SymmetricMatrixSIMD SolverBodyMassAndInertia::getInvInertia< SolverBodyMassAndInertia::PosStage >( float scale ) const
|
||||
{
|
||||
return getInvInertiaPosStage( scale );
|
||||
}
|
||||
|
||||
//
|
||||
// Static properties of a body
|
||||
//
|
||||
class SolverBodyStaticProperties
|
||||
{
|
||||
public:
|
||||
void serialize( DebugSerializer& s ) const;
|
||||
|
||||
boost::uint64_t bodyUID;
|
||||
boost::uint32_t guid;
|
||||
bool isStatic;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
#pragma once
|
||||
|
||||
#define ENABLE_SOR_CONSTRAINTS
|
||||
#define ENABLE_SOR_COLLISIONS
|
||||
#define ENABLE_LOCAL_SOR_MODULATION
|
||||
#define ENABLE_HINGE_FRICTION
|
||||
#define ENABLE_IMPULSE_CACHE_DAMPING_PER_EQUATION
|
||||
//#define ENABLE_SOLVER_PROFILER
|
||||
#define ENABLE_SOLVER_DEBUG_SERIALIZER
|
||||
//#define MIN_NORM_REPROJECT
|
||||
//#define PGS_MIN_NORM
|
||||
|
||||
//#define DISABLE_ANGULAR_CONSTRAINTS
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
|
||||
class SolverConfig
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
Type_Default,
|
||||
Type_InconsistencyDetector,
|
||||
Type_PositionalCorrection,
|
||||
};
|
||||
SolverConfig( Type type = Type_Default );
|
||||
|
||||
//
|
||||
// Kernel
|
||||
//
|
||||
unsigned pgsIterations;
|
||||
|
||||
//
|
||||
// Collisions
|
||||
//
|
||||
|
||||
// Minimum normal velocity for restitution to be applied
|
||||
float collisionRestitutionThreshold;
|
||||
|
||||
// Ignore penetrations that are smaller than this parameter
|
||||
float collisionPenetrationMargin;
|
||||
|
||||
// Params for variable penetration margin
|
||||
float collisionPenetrationMarginMax;
|
||||
float collisionPenetrationMarginMin;
|
||||
|
||||
// The max height of a bump that a rolling object (sphere) can have, in proportion to it's size, due to hitting an edge between two primitives.
|
||||
float collisionPenetrationMarginMaxBumpProportions;
|
||||
|
||||
// Damping of the penetration resolution
|
||||
float collisionPenetrationResolutionDamping;
|
||||
|
||||
// The velocity at which the penetration allowed will be minimum
|
||||
float collisionPenetrationVelocityForMinMargin;
|
||||
|
||||
// Threshold tangential velocity between static and dynamic friction
|
||||
float collisionFrictionStaticToDynamicThreshold;
|
||||
|
||||
// Tunning constant for static friction
|
||||
float collisionFrictionStaticScale;
|
||||
|
||||
// Tunning constant for dynamic friction
|
||||
float collisionFrictionDynamicScale;
|
||||
|
||||
//
|
||||
// Align2Axes Constraint
|
||||
//
|
||||
|
||||
// Angular friction velocity stage
|
||||
float align2AxesFrictionConstant;
|
||||
|
||||
// Angular friction position stage
|
||||
float align2AxesPositionStageFrictionConstant;
|
||||
|
||||
// Maximum angle for angular correction in degrees
|
||||
float align2AxesMaxCorrectiveAngle;
|
||||
|
||||
float align2AxesCorrectionDamping;
|
||||
|
||||
//
|
||||
// BallInSocket
|
||||
//
|
||||
|
||||
// Maximum corrective distance
|
||||
float ballInSocketMaxCorrectionByStabilization;
|
||||
|
||||
float ballInSocketCorrectionDamping;
|
||||
|
||||
//
|
||||
// SOR Modulation
|
||||
//
|
||||
|
||||
// Create a common structure for these...
|
||||
// Constraints
|
||||
struct ModulationParams
|
||||
{
|
||||
float thresholdMax;
|
||||
float thresholdMin;
|
||||
float aggressiveValue;
|
||||
float conservativeValue;
|
||||
float easingUpToAggressive;
|
||||
float easingDownToConservative;
|
||||
};
|
||||
|
||||
ModulationParams sorConstraintsModulation;
|
||||
ModulationParams sorCollisionsModulation;
|
||||
ModulationParams cacheVStageModulation;
|
||||
ModulationParams cachePStageModulation;
|
||||
|
||||
//
|
||||
// Stabilization
|
||||
//
|
||||
float stabilizationMassReductionPower;
|
||||
float stabilizationInertiaScale;
|
||||
|
||||
//
|
||||
// Cache
|
||||
//
|
||||
float velCacheDamping;
|
||||
float posCacheDamping;
|
||||
bool constraintCachingEnabled;
|
||||
|
||||
//
|
||||
// Integration
|
||||
//
|
||||
float angularDamping;
|
||||
bool updateSimBodies;
|
||||
bool integrateOnlyPositions;
|
||||
|
||||
//
|
||||
// Block PGS
|
||||
//
|
||||
bool blockPGSEnabled;
|
||||
|
||||
//
|
||||
// SOR
|
||||
//
|
||||
float velocityStageSOREnabled;
|
||||
float positionStageSOREnabled;
|
||||
|
||||
//
|
||||
// Virtual masses
|
||||
//
|
||||
bool virtualMassesEnabled;
|
||||
|
||||
//
|
||||
// Use sim islands
|
||||
//
|
||||
bool useSimIslands;
|
||||
|
||||
//
|
||||
// Conflicting constraints detector
|
||||
//
|
||||
bool inconsistentConstraintDetectorEnabled;
|
||||
unsigned inconsistentConstraintMaxIterations;
|
||||
|
||||
float inconsistentConstraintBallInSocketResidualThreshold;
|
||||
float inconsistentConstraintDeltaThreshold;
|
||||
float inconsistentConstraintAlign2AxesThreshold;
|
||||
float inconsistentConstraintCollisionThreshold;
|
||||
float inconsistentConstraintCollisionBaseThreshold;
|
||||
bool printConvergenceDiagnostics;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
|
||||
#include "solver/SolverConfig.h"
|
||||
#include "boost/unordered/unordered_map.hpp"
|
||||
#include "boost/container/vector.hpp"
|
||||
|
||||
#include "rbx/DenseHash.h"
|
||||
#include "util/G3DCore.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
|
||||
class SimBody;
|
||||
|
||||
// If you want to have the map visible in the debugger, enable this
|
||||
// #define SOLVER_DEBUG_MAP
|
||||
|
||||
template< class K, class T >
|
||||
struct SolverUnorderedMap
|
||||
{
|
||||
#ifdef SOLVER_DEBUG_MAP
|
||||
// Use a std map in non-release for easier debugger inspection
|
||||
typedef std::map< K, T > Type;
|
||||
#else
|
||||
// This is faster than a std::map as it uses a hash table
|
||||
typedef boost::unordered::unordered_map< K, T > Type;
|
||||
#endif
|
||||
};
|
||||
|
||||
template< class K, class T >
|
||||
struct SolverOrderedMap
|
||||
{
|
||||
typedef std::map< K, T > Type;
|
||||
};
|
||||
|
||||
//typedef SolverUnorderedMap< const SimBody*, int >::Type BodyIndexation;
|
||||
typedef DenseHashMap< const SimBody*, int > BodyIndexation;
|
||||
|
||||
// It's so that we can use a Vector3 in unions
|
||||
class Vector3Pod
|
||||
{
|
||||
public:
|
||||
void operator=( const Vector3& v )
|
||||
{
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
}
|
||||
|
||||
operator Vector3() const
|
||||
{
|
||||
return Vector3(x, y, z);
|
||||
}
|
||||
|
||||
float dot( const Vector3& v ) const
|
||||
{
|
||||
return x * v.x + y * v.y + z * v.z;
|
||||
}
|
||||
|
||||
Vector3Pod& operator+=( const Vector3& v )
|
||||
{
|
||||
x += v.x;
|
||||
y += v.y;
|
||||
z += v.z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
inline Vector3Pod operator*( float s, const Vector3Pod& v )
|
||||
{
|
||||
Vector3Pod r;
|
||||
r.x = s * v.x;
|
||||
r.y = s * v.y;
|
||||
r.z = s * v.z;
|
||||
return r;
|
||||
}
|
||||
|
||||
inline Vector3Pod operator+( const Vector3Pod& u, const Vector3Pod& v )
|
||||
{
|
||||
Vector3Pod r;
|
||||
r.x = u.x + v.x;
|
||||
r.y = u.y + v.y;
|
||||
r.z = u.z + v.z;
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
#pragma once
|
||||
|
||||
#include "solver/SolverConfig.h"
|
||||
#include "boost/cstdint.hpp"
|
||||
#include "rbx/ArrayDynamic.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
|
||||
class ConstraintJacobianPair;
|
||||
class BodyPairIndices;
|
||||
class SolverBodyStaticProperties;
|
||||
class SolverBodyMassAndInertia;
|
||||
class ConstraintVariables;
|
||||
class VirtualDisplacementArray;
|
||||
class VirtualDisplacementArray;
|
||||
class EffectiveMassPair;
|
||||
|
||||
void PGSComputeEffectiveMasses(
|
||||
EffectiveMassPair* _effectiveMassesVelStage,
|
||||
EffectiveMassPair* _effectiveMassesPosStage,
|
||||
size_t _constraintCount,
|
||||
const boost::uint8_t* _dimensions,
|
||||
const ConstraintJacobianPair* _jacobians,
|
||||
const BodyPairIndices* _pairs,
|
||||
const SolverBodyMassAndInertia* _massAndIntertia,
|
||||
const SolverConfig& _config );
|
||||
|
||||
void PGSApplyEffectiveMassMultipliers(
|
||||
EffectiveMassPair* _effectiveMassesVelStage,
|
||||
EffectiveMassPair* _effectiveMassesPosStage,
|
||||
size_t _constraintCount,
|
||||
const boost::uint8_t* _dimensions,
|
||||
const float* _multipliers,
|
||||
const BodyPairIndices* _pairs,
|
||||
const SolverConfig& _config );
|
||||
|
||||
void PGSPreconditionConstraintEquations(
|
||||
ConstraintJacobianPair* _preconditionedJacobiansVelStage,
|
||||
ConstraintJacobianPair* _preconditionedJacobiansPosStage,
|
||||
ConstraintVariables* _velocityStageVariables,
|
||||
ConstraintVariables* _positionStageVariables,
|
||||
size_t _constraintCount,
|
||||
const boost::uint8_t* _dimensions,
|
||||
const boost::uint8_t* _useBlock,
|
||||
const float* __restrict _sorVel,
|
||||
const float* __restrict _sorPos,
|
||||
const ConstraintJacobianPair* _jacobians,
|
||||
const EffectiveMassPair* _effectiveMassesVelStage,
|
||||
const EffectiveMassPair* _effectiveMassesPosStage );
|
||||
|
||||
void PGSInitVirtualDisplacements(
|
||||
VirtualDisplacementArray& _virDVel,
|
||||
VirtualDisplacementArray& _virDPos,
|
||||
const EffectiveMassPair* _effectiveMassesVelStage,
|
||||
const EffectiveMassPair* _effectiveMassesPosStage,
|
||||
size_t _constraintCount,
|
||||
const boost::uint8_t* _dimensions,
|
||||
const ConstraintVariables* __restrict _velStage,
|
||||
const ConstraintVariables* __restrict _posStage,
|
||||
const BodyPairIndices* _pairs,
|
||||
const SolverConfig& _config );
|
||||
|
||||
void PGSSolveKernel(
|
||||
ConstraintVariables* __restrict _velStage,
|
||||
ConstraintVariables* __restrict _posStage,
|
||||
VirtualDisplacementArray& _virDVel,
|
||||
VirtualDisplacementArray& _virDPos,
|
||||
size_t _constraintCount,
|
||||
size_t _collisionCount,
|
||||
const boost::uint8_t* _dimensions,
|
||||
const BodyPairIndices* _pairs,
|
||||
const ConstraintJacobianPair* _preconditionedJacobiansVelStage,
|
||||
const ConstraintJacobianPair* _preconditionedJacobiansPosStage,
|
||||
const EffectiveMassPair* _effectiveMassesVelStage,
|
||||
const EffectiveMassPair* _effectiveMassesPosStage,
|
||||
const SolverConfig& _config );
|
||||
|
||||
void PGSSolveKernelComputeErrors(
|
||||
ArrayBase< float >& _residuals,
|
||||
ArrayBase< float >& _deltaResiduals,
|
||||
ArrayBase< ConstraintVariables >& _vars,
|
||||
VirtualDisplacementArray& _virD,
|
||||
size_t _constraintCount,
|
||||
size_t _collisionCount,
|
||||
size_t _bodyCount,
|
||||
const boost::uint8_t* _dimensions,
|
||||
const BodyPairIndices* _pairs,
|
||||
const ConstraintJacobianPair* _jacobians,
|
||||
const ConstraintJacobianPair* _preconditionedJacobians,
|
||||
const EffectiveMassPair* _effectiveMasses,
|
||||
const SolverConfig& _config );
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include "rbx/rbxTime.h"
|
||||
#include "RbxAssert.h"
|
||||
#include "util/standardout.h"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
|
||||
//
|
||||
// Prints average timing after the given number of samples were taken
|
||||
//
|
||||
class SolverProfiler
|
||||
{
|
||||
public:
|
||||
SolverProfiler( int _samples, const char* _format ): maxSamples( _samples ), format( _format )
|
||||
{
|
||||
accumulator = Time::Interval::zero();
|
||||
currentSamples = 0;
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
#ifdef ENABLE_SOLVER_PROFILER
|
||||
startTime = Time::now( Time::Precise );
|
||||
#endif
|
||||
}
|
||||
|
||||
void end()
|
||||
{
|
||||
#ifdef ENABLE_SOLVER_PROFILER
|
||||
Time::Interval total = Time::now( Time::Precise ) - startTime;
|
||||
accumulator += total;
|
||||
currentSamples++;
|
||||
#endif
|
||||
}
|
||||
|
||||
void printStats()
|
||||
{
|
||||
#ifdef ENABLE_SOLVER_PROFILER
|
||||
static bool enable = true;
|
||||
if( currentSamples >= maxSamples && enable )
|
||||
{
|
||||
currentSamples = 0;
|
||||
StandardOut::singleton()->printf( MESSAGE_OUTPUT, format, accumulator.msec() / maxSamples );
|
||||
accumulator = Time::Interval::zero();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
RBX::Time startTime;
|
||||
Time::Interval accumulator;
|
||||
const char* format;
|
||||
int maxSamples;
|
||||
int currentSamples;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
#pragma once
|
||||
|
||||
#include "solver/SolverConfig.h"
|
||||
#include "solver/SolverContainers.h"
|
||||
#include "solver/DebugSerializer.h"
|
||||
|
||||
#include "util/standardout.h"
|
||||
|
||||
#include "boost/filesystem.hpp"
|
||||
|
||||
namespace RBX
|
||||
{
|
||||
|
||||
class SolverSerializer
|
||||
{
|
||||
public:
|
||||
SolverSerializer(): enabled( false ), fileOpened( false ) { }
|
||||
|
||||
void update( bool _enabled, int userId, boost::uint64_t debugTime )
|
||||
{
|
||||
#ifdef ENABLE_SOLVER_DEBUG_SERIALIZER
|
||||
bool switchState = ( enabled != _enabled );
|
||||
bool close = false;
|
||||
if( switchState )
|
||||
{
|
||||
if( !enabled )
|
||||
{
|
||||
enabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
enabled = false;
|
||||
close = true;
|
||||
}
|
||||
}
|
||||
else if( !enabled )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static size_t bufferSize = 10 * 1024 * 1024;
|
||||
|
||||
if( !fileOpened )
|
||||
{
|
||||
debugSerializer.data.reserve( bufferSize + 1024 * 1024 );
|
||||
boost::filesystem::path path = boost::filesystem::temp_directory_path();
|
||||
path /= "ROBLOX";
|
||||
path /= "SolverLog_Client";
|
||||
path += boost::lexical_cast<std::string>( userId );
|
||||
path += ".bin";
|
||||
myFile.open (path.c_str(), std::ios::out | std::ios::binary);
|
||||
fileOpened = true;
|
||||
debugSerializer & userId;
|
||||
}
|
||||
|
||||
if( close || debugSerializer.data.size() > bufferSize )
|
||||
{
|
||||
myFile.write( debugSerializer.data.data(), debugSerializer.data.size() );
|
||||
debugSerializer.data.clear();
|
||||
}
|
||||
|
||||
if( close && fileOpened )
|
||||
{
|
||||
close = false;
|
||||
enabled = false;
|
||||
myFile.close();
|
||||
fileOpened = false;
|
||||
}
|
||||
|
||||
static boost::uint64_t frame = 0;
|
||||
if( enabled )
|
||||
{
|
||||
debugSerializer & frame;
|
||||
debugSerializer & debugTime;
|
||||
frame++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void serializeConstraints( const ArrayBase< Constraint* >& connectors )
|
||||
{
|
||||
if( enabled )
|
||||
{
|
||||
debugSerializer.tag("Connectors");
|
||||
debugSerializer & (boost::uint32_t)connectors.size();
|
||||
for( const auto* c : connectors )
|
||||
{
|
||||
debugSerializer & (boost::uint8_t)c->getType() & c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void serializeForces( const ArrayBase< SimBody* >& simBodies, boost::uint32_t total )
|
||||
{
|
||||
if( enabled )
|
||||
{
|
||||
debugSerializer.tag("Forces");
|
||||
debugSerializer & total;
|
||||
size_t i = 0;
|
||||
for( i = 0; i < simBodies.size(); i++ )
|
||||
{
|
||||
debugSerializer & simBodies[ i ]->getForce();
|
||||
debugSerializer & simBodies[ i ]->getTorque();
|
||||
debugSerializer & simBodies[ i ]->getImpulse();
|
||||
debugSerializer & simBodies[ i ]->getRotationallmpulse();
|
||||
}
|
||||
Vector3 zero = Vector3::zero();
|
||||
for( ; i < total; i++ )
|
||||
{
|
||||
debugSerializer & zero & zero & zero & zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void serializeComputedImpulse( const ArrayBase< ConstraintVariables >& velocityStage, const ArrayBase< ConstraintVariables >& positionStage )
|
||||
{
|
||||
if(enabled)
|
||||
{
|
||||
ArrayDynamic< float > impulses;
|
||||
impulses.reserve(velocityStage.size());
|
||||
for( const auto& v : velocityStage )
|
||||
{
|
||||
impulses.push_back(v.impulse);
|
||||
}
|
||||
debugSerializer & impulses;
|
||||
impulses.clear();
|
||||
impulses.reserve(velocityStage.size());
|
||||
for( const auto& v : positionStage )
|
||||
{
|
||||
impulses.push_back(v.impulse);
|
||||
}
|
||||
debugSerializer & impulses;
|
||||
}
|
||||
}
|
||||
|
||||
template< class Cache >
|
||||
void serializeBodyCache( const Cache& bodyCache )
|
||||
{
|
||||
if( enabled )
|
||||
{
|
||||
debugSerializer & boost::uint32_t( bodyCache.size() );
|
||||
for( const auto& it : bodyCache )
|
||||
{
|
||||
debugSerializer & (boost::uint32_t)it.second.simBodyDebug->getBody()->getGuidIndex();
|
||||
debugSerializer & it.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template< class T >
|
||||
SolverSerializer& operator&( const T& t )
|
||||
{
|
||||
#ifdef ENABLE_SOLVER_DEBUG_SERIALIZER
|
||||
if( enabled )
|
||||
{
|
||||
debugSerializer & t;
|
||||
}
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
template< class T >
|
||||
SolverSerializer& operator&( const ArrayDynamic< T >& t )
|
||||
{
|
||||
#ifdef ENABLE_SOLVER_DEBUG_SERIALIZER
|
||||
if( enabled )
|
||||
{
|
||||
debugSerializer & static_cast< const ArrayBase< T >& >( t );
|
||||
}
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
SolverSerializer& tag( const char* name )
|
||||
{
|
||||
if( enabled )
|
||||
{
|
||||
debugSerializer.tag(name);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::ofstream myFile;
|
||||
bool fileOpened;
|
||||
bool enabled;
|
||||
DebugSerializer debugSerializer;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "rbx/boost.hpp"
|
||||
#include "rbx/threadsafe.h"
|
||||
#include "rbx/signal.h"
|
||||
#include "rbx/TaskScheduler.Job.h"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include "util/Name.h"
|
||||
#include "util/Region3.h"
|
||||
#include "reflection/YieldFunction.h"
|
||||
#include "v8tree/Instance.h"
|
||||
#include "V8DataModel/DataModel.h"
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user