This commit is contained in:
watrabi
2025-10-28 14:05:46 -04:00
parent 977f1ff4b8
commit c93494f795
452 changed files with 47860 additions and 152 deletions
Binary file not shown.
+8
View File
@@ -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>
-2
View File
@@ -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 -1
View File
@@ -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.
+199
View File
@@ -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
+59
View File
@@ -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
+27
View File
@@ -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
View File
@@ -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
+76
View File
@@ -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
+62
View File
@@ -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
+29
View File
@@ -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
+35
View File
@@ -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
+14
View File
@@ -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
+47
View File
@@ -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
+39
View File
@@ -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
+53
View File
@@ -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
+32
View File
@@ -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
+51
View File
@@ -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
+30
View File
@@ -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
+621
View File
@@ -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
+346
View File
@@ -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
+43
View File
@@ -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
+51
View File
@@ -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
+30
View File
@@ -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
+66
View File
@@ -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
+51
View File
@@ -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
+24
View File
@@ -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
+48
View File
@@ -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
+24
View File
@@ -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
+24
View File
@@ -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
+43
View File
@@ -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
+2 -2
View File
@@ -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());
+1 -1
View File
@@ -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);
}
};
-10
View File
@@ -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);
+44 -39
View File
@@ -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_DEFAULT = 0,
TOUCH_CAMERA_MOVEMENT_MODE_CLASSIC = 1,
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};
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 };
enum ComputerMovementMode {
COMPUTER_MOVEMENT_MODE_DEFAULT = 0,
COMPUTER_MOVEMENT_MODE_KBD_MOUSE = 1,
COMPUTER_MOVEMENT_MODE_CLICK_TO_MOVE = 2};
COMPUTER_CAMERA_MOVEMENT_MODE_DEFAULT = 0,
COMPUTER_CAMERA_MOVEMENT_MODE_CLASSIC = 1,
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
};
enum ComputerMovementMode {
COMPUTER_MOVEMENT_MODE_DEFAULT = 0,
COMPUTER_MOVEMENT_MODE_KBD_MOUSE = 1,
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 mouseLockedInMouseLockMode() { return inMouseLockMode() && isMouseLocked(); }
bool camLockedInCamLockMode() { return inCamlockMode() && !getFreeLook(); }
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 getTutorialState(std::string tutorialId);
void setTutorialState(std::string tutorialId, bool value);
@@ -118,11 +123,11 @@ namespace RBX
bool getFullScreenConst() const { return fullscreen; }
bool getFullScreen() { return fullscreen; }
void setFullScreen(bool value)
{
if(value != fullscreen)
void setFullScreen(bool value)
{
if (value != fullscreen)
{
fullscreen = value;
fullscreen = value;
fullscreenChangedSignal(value);
}
}
@@ -143,12 +148,12 @@ namespace RBX
void setMouseSensitivity(float value);
bool inStudioMode() { return studio; }
void setStudioMode(bool value)
void setStudioMode(bool value)
{
if(value != studio)
if (value != studio)
{
studioModeChangedSignal(value);
studio = value;
studio = value;
}
}
@@ -157,7 +162,7 @@ namespace RBX
std::string getGoogleAnalyticsClientId() const;
void setGoogleAnalyticsClientId(const std::string& id);
/*override*/ void reset();
/*override*/ void verifySetParent(const Instance* instance) const;
@@ -166,7 +171,7 @@ namespace RBX
rbx::signal<void(bool)> fullscreenChangedSignal;
rbx::signal<void(bool)> studioModeChangedSignal;
private:
private:
ControlMode controlMode;
RenderQualitySetting renderQualitySetting;
YearSettings currentYear;
@@ -205,4 +210,4 @@ namespace RBX
std::string googleAnalyticsClientId;
};
}
}
+264
View File
@@ -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
}
};
} }
+73
View File
@@ -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;
}
};
}
}
+103
View File
@@ -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;
+103
View File
@@ -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;
+103
View File
@@ -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;
+103
View File
@@ -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;
+103
View File
@@ -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;
+103
View File
@@ -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;
+103
View File
@@ -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;
+103
View File
@@ -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;
+103
View File
@@ -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;
+103
View File
@@ -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;
+597
View File
@@ -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());
}
};
}
}
+75
View File
@@ -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() {}
};
}
}
+375
View File
@@ -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
+108
View File
@@ -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);
}
};
}
}
+337
View File
@@ -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;
};
}
}
+491
View File
@@ -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();
}
};
}
}
+323
View File
@@ -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() );
}
}
}
+65
View File
@@ -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);
}
};
}
}
+353
View File
@@ -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
+30
View File
@@ -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);
};
}
+400
View File
@@ -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");
}
};
}
}
+41
View File
@@ -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);
};
}
}
+52
View File
@@ -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);
};
}
+249
View File
@@ -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);
};
}}
+402
View File
@@ -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);
} }
+19
View File
@@ -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[];
}
+56
View File
@@ -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);
} }
+41
View File
@@ -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);
} }
+31
View File
@@ -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);
};
}
}
+36
View File
@@ -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);
};
}
+26
View File
@@ -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
};
}
+1 -1
View File
@@ -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;
+56
View File
@@ -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);
};
}
}
+74
View File
@@ -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;
};
}
+185
View File
@@ -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
+98
View File
@@ -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
+122
View File
@@ -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);
};
}
+466
View File
@@ -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
}
+80
View File
@@ -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);
} }
+66
View File
@@ -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();
};
}
+185
View File
@@ -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);
} }
+192
View File
@@ -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();
}
};
}
+377
View File
@@ -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
}
+86
View File
@@ -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;
}
}
+170
View File
@@ -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
+2
View File
@@ -0,0 +1,2 @@
#pragma once
#define RBX_BUILDSEED 3942749
+117
View File
@@ -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();
};
}
}
+682
View File
@@ -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;
};
}
+274
View File
@@ -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; }
}
+193
View File
@@ -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 );
}
}
+193
View File
@@ -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;
};
}
+288
View File
@@ -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;
};
}
+166
View File
@@ -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;
};
}
+91
View File
@@ -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;
}
}
+94
View File
@@ -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 );
}
+59
View File
@@ -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;
};
}
+189
View File
@@ -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;
};
}
+22
View File
@@ -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