mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
fahhh
This commit is contained in:
Binary file not shown.
@@ -140,6 +140,9 @@
|
|||||||
<OutDir>bin\$(Configuration)\</OutDir>
|
<OutDir>bin\$(Configuration)\</OutDir>
|
||||||
<IntDir>obj\$(Configuration)\</IntDir>
|
<IntDir>obj\$(Configuration)\</IntDir>
|
||||||
</PropertyGroup>
|
</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'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
@@ -302,6 +305,11 @@ cmd /c "exit /b 0"</Command>
|
|||||||
<TreatWarningAsError>false</TreatWarningAsError>
|
<TreatWarningAsError>false</TreatWarningAsError>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemDefinitionGroup>
|
</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>
|
<ItemGroup>
|
||||||
<ClCompile Include="$(CONTRIB_PATH)\w3c-libwww-5.4.0\Library\src\HTList.c">
|
<ClCompile Include="$(CONTRIB_PATH)\w3c-libwww-5.4.0\Library\src\HTList.c">
|
||||||
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='ReleaseStudio|Win32'">Level1</WarningLevel>
|
<WarningLevel Condition="'$(Configuration)|$(Platform)'=='ReleaseStudio|Win32'">Level1</WarningLevel>
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ list(APPEND SOURCES ${libwww_ROOT}/HTParse.c)
|
|||||||
set_source_files_properties(${libwww_ROOT}/HTParse.c PROPERTIES COMPILE_FLAGS "${libwww_cflags}")
|
set_source_files_properties(${libwww_ROOT}/HTParse.c PROPERTIES COMPILE_FLAGS "${libwww_cflags}")
|
||||||
list(APPEND SOURCES ${libwww_ROOT}/HTString.c)
|
list(APPEND SOURCES ${libwww_ROOT}/HTString.c)
|
||||||
set_source_files_properties(${libwww_ROOT}/HTString.c PROPERTIES COMPILE_FLAGS "${libwww_cflags}")
|
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)
|
if(UNIX)
|
||||||
list(APPEND SOURCES util/Unix/ProgramMemoryChecker.cpp)
|
list(APPEND SOURCES util/Unix/ProgramMemoryChecker.cpp)
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
#v4.0:v110:false
|
#v4.0:v110:false
|
||||||
NoOpt|Win32|F:\Trunk2012\BuildWatrbx\|
|
NoOpt|Win32|J:\Trunk2012\Client\|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,199 @@
|
|||||||
|
/* Copyright 2003-2006 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Gui/Gui.h"
|
||||||
|
#include "Util/RunStateOwner.h"
|
||||||
|
#include "V8DataModel/ChatService.h"
|
||||||
|
#include "Util/UDim.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
class SafeChat;
|
||||||
|
class GuiObject;
|
||||||
|
class BillboardGui;
|
||||||
|
class ModelInstance;
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
class Player;
|
||||||
|
class Players;
|
||||||
|
class ChatMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ChatLine {
|
||||||
|
protected:
|
||||||
|
static float ComputeBubbleLifetime(const std::string& msg, bool isSelf);
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const char* ELIPSES;
|
||||||
|
static const int CchMaxChatMessageLength; // max chat message length, including null terminator and elipses.
|
||||||
|
enum BubbleColor
|
||||||
|
{
|
||||||
|
WHITE,
|
||||||
|
BLUE,
|
||||||
|
GREEN,
|
||||||
|
RED,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ChatType
|
||||||
|
{
|
||||||
|
PLAYER_CHAT,
|
||||||
|
PLAYER_TEAM_CHAT,
|
||||||
|
PLAYER_WHISPER_CHAT,
|
||||||
|
|
||||||
|
GAME_MESSAGE,
|
||||||
|
PLAYER_GAME_CHAT,
|
||||||
|
BOT_CHAT,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string message;
|
||||||
|
const BubbleColor bubbleColor;
|
||||||
|
const ChatType chatType;
|
||||||
|
float startTime;
|
||||||
|
float bubbleDieDelay;
|
||||||
|
bool isLocalPlayer;
|
||||||
|
boost::weak_ptr<Instance> origin;
|
||||||
|
|
||||||
|
const Instance* getOrigin() const { return origin.lock().get(); }
|
||||||
|
|
||||||
|
ChatLine(ChatType chatType, const std::string& message, float startTime, BubbleColor bubbleColor, bool isLocalPlayer);
|
||||||
|
virtual ~ChatLine() {}
|
||||||
|
|
||||||
|
bool isPlayerChat() const
|
||||||
|
{
|
||||||
|
switch(chatType)
|
||||||
|
{
|
||||||
|
case PLAYER_CHAT:
|
||||||
|
case PLAYER_TEAM_CHAT:
|
||||||
|
case PLAYER_WHISPER_CHAT:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PlayerChatLine : public ChatLine {
|
||||||
|
public:
|
||||||
|
|
||||||
|
static const char* ROBLOXNAME;
|
||||||
|
Color3 userColor;
|
||||||
|
|
||||||
|
std::string user;
|
||||||
|
float historyDieDelay;
|
||||||
|
|
||||||
|
const ModelInstance* getCharacter() const;
|
||||||
|
|
||||||
|
PlayerChatLine(ChatType chatType, boost::shared_ptr<Network::Player> player, const std::string& message, float startTime, bool isLocalPlayer);
|
||||||
|
};
|
||||||
|
class GameChatLine: public ChatLine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GameChatLine(boost::shared_ptr<Instance> origin, const std::string& message, float startTime, bool isLocalPlayer, BubbleColor bubbleColor);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CharacterChats
|
||||||
|
{
|
||||||
|
CharacterChats()
|
||||||
|
: isVisible(false)
|
||||||
|
, isMoving(false)
|
||||||
|
{}
|
||||||
|
std::deque<boost::shared_ptr<ChatLine> > fifo;
|
||||||
|
bool isVisible;
|
||||||
|
bool isMoving;
|
||||||
|
weak_ptr<BillboardGui> billboardGui;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChatOutput
|
||||||
|
: public GuiItem
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static const int kMaxTextSize = 16;
|
||||||
|
static const int kMaxCharsInLine = 20;
|
||||||
|
|
||||||
|
void createBillboardGuiHelper(Instance* instance, bool character);
|
||||||
|
|
||||||
|
void renderBubbleImposters(Adorn* adorn, weak_ptr<const Instance> owner, weak_ptr<PartInstance> head);
|
||||||
|
void renderBubbles(Adorn* adorn, weak_ptr<const Instance> owner, weak_ptr<PartInstance> head, bool playerAndGameChat,
|
||||||
|
Vector3 extentsOffset, Vector3 studsOffset);
|
||||||
|
typedef GuiItem Super;
|
||||||
|
static const int MaxChatBubblesPerPlayer;
|
||||||
|
static const int MaxChatLinesPerBubble;
|
||||||
|
|
||||||
|
RBX::Network::Players* players;
|
||||||
|
std::map<ChatLine::BubbleColor, shared_ptr<GuiObject> > chatBubble;
|
||||||
|
std::map<ChatLine::BubbleColor, shared_ptr<GuiObject> > chatBubbleWithTail;
|
||||||
|
std::map<ChatLine::BubbleColor, shared_ptr<GuiObject> > scalingChatBubbleWithTail;
|
||||||
|
|
||||||
|
struct ScalingInfo
|
||||||
|
{
|
||||||
|
Vector2 scalingCutoff;
|
||||||
|
UDim2 fixedPosition;
|
||||||
|
UDim2 fixedSize;
|
||||||
|
|
||||||
|
UDim2 scalingPosition;
|
||||||
|
UDim2 scalingSize;
|
||||||
|
|
||||||
|
UDim2 getPosition(Vector2 size)
|
||||||
|
{
|
||||||
|
|
||||||
|
return UDim2(size.x < scalingCutoff.x ? scalingPosition.x : fixedPosition.x,
|
||||||
|
size.y < scalingCutoff.y ? scalingPosition.y : fixedPosition.y);
|
||||||
|
}
|
||||||
|
UDim2 getSize(Vector2 size)
|
||||||
|
{
|
||||||
|
return UDim2(size.x < scalingCutoff.x ? scalingSize.x : fixedSize.x,
|
||||||
|
size.y < scalingCutoff.y ? scalingSize.y : fixedSize.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScalingInfo(Vector2 scalingCutoff, UDim2 fixedPosition, UDim2 fixedSize, UDim2 scalingPosition, UDim2 scalingSize)
|
||||||
|
:scalingCutoff(scalingCutoff)
|
||||||
|
,fixedPosition(fixedPosition)
|
||||||
|
,fixedSize(fixedSize)
|
||||||
|
,scalingPosition(scalingPosition)
|
||||||
|
,scalingSize(scalingSize)
|
||||||
|
{}
|
||||||
|
ScalingInfo()
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
std::map<ChatLine::BubbleColor, ScalingInfo> scalingInfo;
|
||||||
|
|
||||||
|
std::map<ChatLine::BubbleColor, shared_ptr<GuiObject> > chatPlaceholder;
|
||||||
|
|
||||||
|
std::deque<boost::shared_ptr<ChatLine> > fifo;
|
||||||
|
typedef std::map<const Instance*, CharacterChats> CharacterChatMap;
|
||||||
|
CharacterChatMap characterSortedMsg;
|
||||||
|
float time;
|
||||||
|
|
||||||
|
void acceleratedBubbleDecay(ChatLine* line, float wallStep, bool isMoving, bool isVisible);
|
||||||
|
|
||||||
|
void removeOldest();
|
||||||
|
bool removeExpired();
|
||||||
|
|
||||||
|
bool bubbleChatEnabled();
|
||||||
|
|
||||||
|
std::string SanitizeChatLine(const std::string& msg); // truncate and make safe.
|
||||||
|
|
||||||
|
// Instance
|
||||||
|
/*override*/ void onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider);
|
||||||
|
|
||||||
|
// Listener
|
||||||
|
rbx::signals::scoped_connection heartbeatConnection;
|
||||||
|
rbx::signals::scoped_connection playerChatMessageConnection;
|
||||||
|
rbx::signals::scoped_connection gameChatMessageConnection;
|
||||||
|
void onHeartbeat(const Heartbeat& heartbeat);
|
||||||
|
|
||||||
|
void onPlayerChatMessage(const Network::ChatMessage& event);
|
||||||
|
void onGameChatMessage(boost::shared_ptr<Instance> origin, const std::string& message, ChatService::ChatColor color);
|
||||||
|
|
||||||
|
// GuiItem
|
||||||
|
/*override*/ void render2d(Adorn* adorn);
|
||||||
|
/*override*/ void render2d_bubbleStyle(Adorn* adorn, bool playerBubbleChat);
|
||||||
|
|
||||||
|
public:
|
||||||
|
ChatOutput();
|
||||||
|
~ChatOutput();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Gui/GuiDraw.h"
|
||||||
|
|
||||||
|
#include "GfxBase/Adorn.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
class UnifiedImageWidget : public UnifiedWidget
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
GuiDrawImage guiImageDraw;
|
||||||
|
std::string imageName;
|
||||||
|
unsigned imageState;
|
||||||
|
public:
|
||||||
|
UnifiedImageWidget(const std::string& imageName, int imageState)
|
||||||
|
: imageName(imageName)
|
||||||
|
, imageState(imageState)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Gui::WidgetState getWidgetState() const;
|
||||||
|
|
||||||
|
/*override*/ void render2dMe(Adorn* adorn);
|
||||||
|
/*override*/ void setSize(const Vector2& _size) {guiImageDraw.setImageSize(_size);}
|
||||||
|
/*override*/ Vector2 getSize(Canvas canvas) const {return guiImageDraw.getImageSize();}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChatButton : public UnifiedImageWidget
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*override*/ bool isVisible() const;
|
||||||
|
public:
|
||||||
|
ChatButton(const std::string& imageName, unsigned imageState)
|
||||||
|
: UnifiedImageWidget(imageName, imageState)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ChatWidget : public UnifiedWidget
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef UnifiedWidget Super;
|
||||||
|
std::string findMenuString(GuiItem* item);
|
||||||
|
|
||||||
|
std::string code;
|
||||||
|
|
||||||
|
// Unified Widget
|
||||||
|
/*override*/ void onMenuStateChanged();
|
||||||
|
|
||||||
|
/*override*/ GuiResponse process(const shared_ptr<InputObject>& event);
|
||||||
|
|
||||||
|
public:
|
||||||
|
ChatWidget(const std::string& text, std::string code);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Gui/GUI.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
class EquationDisplay : public TextDisplay {
|
||||||
|
private:
|
||||||
|
std::string equation;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// TextDisplay
|
||||||
|
std::string getLabel() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
EquationDisplay(
|
||||||
|
const std::string& title,
|
||||||
|
const std::string& equation);
|
||||||
|
|
||||||
|
EquationDisplay(
|
||||||
|
const std::string& title,
|
||||||
|
const std::string& label,
|
||||||
|
const std::string& equation);
|
||||||
|
|
||||||
|
/*override*/ void render2d(Adorn* adorn);
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
+268
@@ -0,0 +1,268 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "V8DataModel/InputObject.h"
|
||||||
|
#include "Gui/GuiEvent.h"
|
||||||
|
#include "Gui/Layout.h"
|
||||||
|
#include "V8Tree/Instance.h"
|
||||||
|
#include "GfxBase/Type.h"
|
||||||
|
#include "GfxBase/Adorn.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
|
||||||
|
extern const char* const sGuiItem;
|
||||||
|
class GuiItem : public DescribedNonCreatable<GuiItem, Instance, sGuiItem>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef Instance Super;
|
||||||
|
shared_ptr<GuiItem> focus; // TODO: It should be safe to make this a bald pointer, since focus is always a child
|
||||||
|
Vector2 guiSize;
|
||||||
|
|
||||||
|
GuiResponse processNonFocus(const shared_ptr<InputObject>& event);
|
||||||
|
void switchFocus(GuiItem* item);
|
||||||
|
|
||||||
|
// Instance
|
||||||
|
/*override*/ void onDescendantRemoving(const shared_ptr<Instance>& instance);
|
||||||
|
/*override*/ bool askAddChild(const Instance* instance) const {
|
||||||
|
return Instance::fastDynamicCast<GuiItem>(instance)!=0;
|
||||||
|
}
|
||||||
|
/*override*/ const RBX::Name& getClassName() const {return RBX::Name::getNullName(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
GuiItem* getFocus() {return focus.get();}
|
||||||
|
void loseFocus() {
|
||||||
|
if (focus) {
|
||||||
|
focus->onLoseFocus();
|
||||||
|
}
|
||||||
|
focus.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
Rect getMyRect(Canvas canvas) const; // myPosition, myPosition + mySize
|
||||||
|
|
||||||
|
Rect2D getMyRect2D(Canvas canvas) const {
|
||||||
|
return getMyRect(canvas).toRect2D();
|
||||||
|
}
|
||||||
|
|
||||||
|
void label2d(
|
||||||
|
Adorn* adorn,
|
||||||
|
const std::string& label,
|
||||||
|
const Color4& fill,
|
||||||
|
const Color4& border,
|
||||||
|
Text::XAlign align = Text::XALIGN_LEFT) const;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// GUI Item virtuals
|
||||||
|
|
||||||
|
virtual void onLoseFocus() {}
|
||||||
|
virtual bool canLoseFocus() {return false;} // in general, Gui Items don't lose focus while processing
|
||||||
|
|
||||||
|
// standard virtual overrides....
|
||||||
|
virtual Vector2 getPosition(Canvas canvas) const {
|
||||||
|
RBXASSERT(getGuiParent());
|
||||||
|
return getGuiParent()->getChildPosition(this, canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Vector2 getChildPosition(const GuiItem* child, Canvas canvas) const { // This should always be override if ever used
|
||||||
|
RBXASSERT(0);
|
||||||
|
return Vector2::zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
// used internally - could these be protected?
|
||||||
|
virtual int getFontSize() const {return 12;}
|
||||||
|
|
||||||
|
virtual bool isVisible() const {return true;}
|
||||||
|
|
||||||
|
virtual std::string getTitle() {return getName();}
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual Vector2 getSize(Canvas canvas) const {return getGuiSize();}
|
||||||
|
|
||||||
|
virtual GuiResponse process(const shared_ptr<InputObject>& event);
|
||||||
|
|
||||||
|
virtual void render2d(Adorn* adorn) {}
|
||||||
|
|
||||||
|
|
||||||
|
GuiItem();
|
||||||
|
~GuiItem();
|
||||||
|
|
||||||
|
void addGuiItem(shared_ptr<GuiItem> guiItem) {guiItem->setParent(this);}
|
||||||
|
|
||||||
|
void setGuiSize(const Vector2& size) {guiSize = size;}
|
||||||
|
const Vector2& getGuiSize() const {return guiSize;}
|
||||||
|
|
||||||
|
GuiItem* getGuiParent();
|
||||||
|
const GuiItem* getGuiParent() const;
|
||||||
|
GuiItem* getGuiItem(int index);
|
||||||
|
const GuiItem* getGuiItem(int index) const;
|
||||||
|
|
||||||
|
static const Color4& disabledFill();
|
||||||
|
static const Color4& translucentBackdrop();// background of the palette
|
||||||
|
static const Color4& menuSelect();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const char* const sGuiRoot;
|
||||||
|
|
||||||
|
class GuiRoot :
|
||||||
|
public Reflection::Described<GuiRoot, sGuiRoot, GuiItem, Reflection::ClassDescriptor::INTERNAL_LOCAL, RBX::Security::LocalUser>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GuiRoot();
|
||||||
|
|
||||||
|
/*override*/ void render2d(Adorn* adorn);
|
||||||
|
|
||||||
|
void render2dItem(Adorn* adorn, GuiItem* guiItem);
|
||||||
|
|
||||||
|
// GuiItem
|
||||||
|
/*override*/ Vector2 getSize(Canvas canvas) const {
|
||||||
|
// shouldn't be called - implies item doesn't know it's top level
|
||||||
|
RBXASSERT(false);
|
||||||
|
return canvas.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool askSetParent(const Instance* instance) const {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TopMenuBar : public GuiItem {
|
||||||
|
private:
|
||||||
|
void init();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Color4 backdropColor;
|
||||||
|
Layout::Style layoutStyle;
|
||||||
|
bool visible;
|
||||||
|
|
||||||
|
/*override*/ Vector2 getChildPosition(const GuiItem* child, Canvas canvas) const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TopMenuBar() {init();}
|
||||||
|
TopMenuBar(
|
||||||
|
const std::string& _title,
|
||||||
|
Layout::Style layoutStyle,
|
||||||
|
bool translucentBackdrop = false);
|
||||||
|
TopMenuBar(
|
||||||
|
const std::string& _title,
|
||||||
|
Layout::Style _layoutStyle,
|
||||||
|
Color4 _backdropColor);
|
||||||
|
|
||||||
|
/*override*/ GuiResponse process(const shared_ptr<InputObject>& event);
|
||||||
|
/*override*/ void render2d(Adorn* adorn);
|
||||||
|
/*override*/ Vector2 getSize(Canvas canvas) const;
|
||||||
|
/*override*/ bool isVisible() const {return visible;}
|
||||||
|
|
||||||
|
void setVisible(bool _set) {visible = _set;}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class RelativePanel : public TopMenuBar {
|
||||||
|
protected:
|
||||||
|
Rect::Location xLocation;
|
||||||
|
Rect::Location yLocation;
|
||||||
|
Vector2int16 offset;
|
||||||
|
|
||||||
|
void init(const Layout& layout);
|
||||||
|
|
||||||
|
public:
|
||||||
|
RelativePanel() {init(Layout());}
|
||||||
|
RelativePanel(const Layout& layout) {init(layout);}
|
||||||
|
|
||||||
|
virtual Vector2 getPosition(Canvas canvas) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This will become the new unified widget - menu, button, all...
|
||||||
|
//
|
||||||
|
|
||||||
|
class UnifiedWidget : public GuiItem {
|
||||||
|
public:
|
||||||
|
enum MenuState {NOTHING, HOVER, SHOWN_APPEARING, SHOWN}; // + focus if child is shown
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef GuiItem Super;
|
||||||
|
MenuState menuState;
|
||||||
|
|
||||||
|
GuiResponse processShown_InTitle(const shared_ptr<InputObject>& event);
|
||||||
|
GuiResponse processShown_OutOfTitle(const shared_ptr<InputObject>& event);
|
||||||
|
|
||||||
|
GuiResponse processNothing(const shared_ptr<InputObject>& event);
|
||||||
|
GuiResponse processHover(const shared_ptr<InputObject>& event);
|
||||||
|
GuiResponse processShown(const shared_ptr<InputObject>& event);
|
||||||
|
GuiResponse processKey(const shared_ptr<InputObject>& event);
|
||||||
|
|
||||||
|
void render2dChildren(Adorn* adorn);
|
||||||
|
|
||||||
|
/*override*/ Vector2 getChildPosition(const GuiItem* child, Canvas canvas) const;
|
||||||
|
/*override*/ bool canLoseFocus() {return true;}
|
||||||
|
/*override*/ void onLoseFocus();
|
||||||
|
/*override*/ int getFontSize() const {return 8;}
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool showChildren() {return (menuState >= SHOWN_APPEARING);}
|
||||||
|
|
||||||
|
virtual void onMenuStateChanged() {}
|
||||||
|
virtual Vector2 firstChildPosition(Canvas canvas) const;
|
||||||
|
virtual Vector2 childOffset() const;
|
||||||
|
virtual void render2dMe(Adorn* adorn);
|
||||||
|
|
||||||
|
public:
|
||||||
|
UnifiedWidget() {init();}
|
||||||
|
UnifiedWidget(const std::string& title);
|
||||||
|
|
||||||
|
MenuState getMenuState() const {return menuState;}
|
||||||
|
void setMenuState(MenuState value);
|
||||||
|
|
||||||
|
/*override*/ GuiResponse process(const shared_ptr<InputObject>& event);
|
||||||
|
/*override*/ void render2d(Adorn* adorn);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TextDisplay : public GuiItem {
|
||||||
|
private:
|
||||||
|
typedef GuiItem Super;
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string label;
|
||||||
|
int fontSize;
|
||||||
|
Color4 fontColor;
|
||||||
|
Color4 borderColor;
|
||||||
|
Text::XAlign align;
|
||||||
|
bool visible;
|
||||||
|
|
||||||
|
/*override*/ int getFontSize() const {return fontSize;}
|
||||||
|
/*override*/ bool isVisible() const {return visible;}
|
||||||
|
|
||||||
|
const std::string& getLabel() const {return label;}
|
||||||
|
|
||||||
|
public:
|
||||||
|
TextDisplay() {init();}
|
||||||
|
TextDisplay(const std::string& title, const std::string& _label);
|
||||||
|
|
||||||
|
/*override*/ void render2d(Adorn* adorn);
|
||||||
|
/*override*/ Vector2 getSize(Canvas canvas) const;
|
||||||
|
|
||||||
|
void setLabel(const std::string& _label) {label = _label;}
|
||||||
|
void setFontSize(int _fontSize) {
|
||||||
|
fontSize = _fontSize;
|
||||||
|
setGuiSize(Vector2(fontSize*10.0f, fontSize*2.0f));
|
||||||
|
}
|
||||||
|
void setFontColor(const Color4& _color) {fontColor = _color;}
|
||||||
|
void setBorderColor(const Color4& _color) {borderColor = _color;}
|
||||||
|
void setAlign(Text::XAlign _align) {align = _align;}
|
||||||
|
void setVisible(bool _visible) {visible = _visible;}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/* Copyright 2003-2006 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "V8DataModel/GuiCore.h"
|
||||||
|
#include "V8Xml/Reference.h"
|
||||||
|
#include "Util/TextureId.h"
|
||||||
|
#include "GfxBase/TextureProxyBase.h"
|
||||||
|
#include "GfxBase/Adorn.h"
|
||||||
|
#include "rbx/signal.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
class Adorn;
|
||||||
|
|
||||||
|
class GuiDrawImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum ImageState
|
||||||
|
{
|
||||||
|
NORMAL = 0x1,
|
||||||
|
HOVER = 0x2,
|
||||||
|
DOWN = 0x4,
|
||||||
|
DISABLE = 0x8,
|
||||||
|
SELECTED = 0x10,
|
||||||
|
SELECTED_HOVER = 0x20,
|
||||||
|
SELECTED_DOWN = 0x40,
|
||||||
|
ALL = 0x7F
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
TextureId currentTexture;
|
||||||
|
TextureId loadingTexture;
|
||||||
|
RBX::TextureProxyBaseRef disable;
|
||||||
|
RBX::TextureProxyBaseRef normal;
|
||||||
|
RBX::TextureProxyBaseRef hover;
|
||||||
|
RBX::TextureProxyBaseRef down;
|
||||||
|
RBX::TextureProxyBaseRef selected;
|
||||||
|
RBX::TextureProxyBaseRef selectedHover;
|
||||||
|
RBX::TextureProxyBaseRef selectedDown;
|
||||||
|
mutable Vector2 size;
|
||||||
|
rbx::signals::scoped_connection unbindResourceSignalHint;
|
||||||
|
|
||||||
|
void OnUnbindResourceSignalHint();
|
||||||
|
|
||||||
|
void draw(Adorn* adorn, const RBX::TextureProxyBaseRef& texture, const Rect& rect, const Vector2& texul, const Vector2& texbr, const Color4& color,
|
||||||
|
const Rect& clipRect, const Color4& behind, const Color4& inFront);
|
||||||
|
|
||||||
|
void draw(Adorn* adorn, const RBX::TextureProxyBaseRef& texture, const Rect& rect, const Vector2& texul, const Vector2& texbr, const Color4& color,
|
||||||
|
const Rotation2D& rotation, const Color4& behind, const Color4& inFront);
|
||||||
|
|
||||||
|
template <typename Modifier>
|
||||||
|
void render2dImpl(Adorn* adorn, bool enabled, const Rect& rect, const Vector2& texul, const Vector2& texbr, const Color4& color,
|
||||||
|
const Modifier& modifier, Gui::WidgetState state, bool isSelected);
|
||||||
|
|
||||||
|
void tryCreateTextureProxy(Adorn *adorn, const std::string& contentString, const std::string& context, RBX::TextureProxyBaseRef& textureRef, bool& isWaiting);
|
||||||
|
public:
|
||||||
|
GuiDrawImage() : size(Vector2(0,0)) {}
|
||||||
|
GuiDrawImage(Adorn *adorn, const std::string& textureName, unsigned imageState) {setImageFromName(adorn, textureName, imageState);}
|
||||||
|
|
||||||
|
void render2d(Adorn* adorn, bool enabled, const Rect& rect,
|
||||||
|
Gui::WidgetState state, bool isSelected);
|
||||||
|
void render2d(Adorn* adorn, bool enabled, const Rect& rect, const Vector2& texul, const Vector2& texbr, const Color4& color, const Rotation2D& rotation,
|
||||||
|
Gui::WidgetState state, bool isSelected);
|
||||||
|
void render2d(Adorn* adorn, bool enabled, const Rect& rect, const Vector2& texul, const Vector2& texbr, const Color4& color, const Rect& clipRect,
|
||||||
|
Gui::WidgetState state, bool isSelected);
|
||||||
|
|
||||||
|
void setImageSize(const Vector2& _size);
|
||||||
|
Vector2 getImageSize() const;
|
||||||
|
|
||||||
|
bool setImage(Adorn* adorn, const TextureId& textureId, unsigned imageState, Vector2* outSize = NULL, Instance* contextInstance = NULL, const char* context = "");
|
||||||
|
bool setImageFromName(Adorn* adorn, const std::string& textureName, unsigned imageState, Instance* contextInstance = NULL, const char* context = "");
|
||||||
|
|
||||||
|
void computeUV(Vector2& uvtl, Vector2& uvbr, const Vector2& imageRectOffset, const Vector2& imageRectSize, const Vector2& imageSize);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
/* Copyright 2003-2015 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "v8tree/Instance.h"
|
||||||
|
|
||||||
|
LOGGROUP(GuiTargetLifetime)
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
class GuiResponse
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
enum ResponseType {NOT_SUNK, SUNK};
|
||||||
|
enum FinishedType {NOT_FINISHED, FINISHED};
|
||||||
|
enum MouseOverType {NOT_MOUSE_OVER, MOUSE_OVER};
|
||||||
|
|
||||||
|
ResponseType response;
|
||||||
|
FinishedType finished;
|
||||||
|
MouseOverType mouseWasOver;
|
||||||
|
weak_ptr<Instance> target;
|
||||||
|
|
||||||
|
GuiResponse(ResponseType response, FinishedType finished, MouseOverType mouseWasOver, Instance* newTarget)
|
||||||
|
: response(response)
|
||||||
|
, finished(finished)
|
||||||
|
, mouseWasOver(mouseWasOver)
|
||||||
|
, target(weak_from(newTarget))
|
||||||
|
{}
|
||||||
|
|
||||||
|
GuiResponse(ResponseType response)
|
||||||
|
: response(response)
|
||||||
|
, finished(NOT_FINISHED)
|
||||||
|
, mouseWasOver(NOT_MOUSE_OVER)
|
||||||
|
{}
|
||||||
|
|
||||||
|
public:
|
||||||
|
GuiResponse()
|
||||||
|
: response(NOT_SUNK)
|
||||||
|
, finished(NOT_FINISHED)
|
||||||
|
, mouseWasOver(NOT_MOUSE_OVER)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool getMouseWasOver() const {return mouseWasOver == MOUSE_OVER;}
|
||||||
|
void setMouseWasOver() {mouseWasOver = MOUSE_OVER;}
|
||||||
|
|
||||||
|
bool wasSunk() {return (response == SUNK);}
|
||||||
|
bool wasSunkAndFinished()
|
||||||
|
{
|
||||||
|
RBXASSERT(!((finished == FINISHED) && !wasSunk()));
|
||||||
|
return (finished == FINISHED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GuiResponse notSunk() {return GuiResponse(NOT_SUNK);}
|
||||||
|
static GuiResponse notSunkMouseWasOver() {return GuiResponse(NOT_SUNK, NOT_FINISHED, MOUSE_OVER, NULL);}
|
||||||
|
static GuiResponse sunk() {return GuiResponse(SUNK);}
|
||||||
|
static GuiResponse sunkAndFinished() {return GuiResponse(SUNK, FINISHED, NOT_MOUSE_OVER, NULL);}
|
||||||
|
static GuiResponse sunkWithTarget(Instance* target) {return GuiResponse(SUNK, NOT_FINISHED, NOT_MOUSE_OVER, target);}
|
||||||
|
|
||||||
|
shared_ptr<Instance> getTarget() { return target.lock(); }
|
||||||
|
void setTarget(Instance* value) { target = weak_from(value); }
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Util/Rect.h"
|
||||||
|
#include "Util/G3DCore.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
class Layout
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Style {HORIZONTAL = 0, VERTICAL = 1};
|
||||||
|
|
||||||
|
Rect::Location xLocation;
|
||||||
|
Rect::Location yLocation;
|
||||||
|
Vector2int16 offset;
|
||||||
|
Style layoutStyle;
|
||||||
|
Color4 backdropColor;
|
||||||
|
|
||||||
|
Layout()
|
||||||
|
: xLocation(Rect::LEFT)
|
||||||
|
, yLocation(Rect::TOP)
|
||||||
|
, offset(Vector2int16(0,0))
|
||||||
|
, layoutStyle(HORIZONTAL)
|
||||||
|
, backdropColor(Color4::clear())
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/* Copyright 2003-2006 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Util/ScopedSingleton.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
class WordList
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::set<std::string> blacklist;
|
||||||
|
void decrypt(std::string& str);
|
||||||
|
public:
|
||||||
|
WordList();
|
||||||
|
~WordList();
|
||||||
|
|
||||||
|
bool ContainsProfanity(std::string str);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class ProfanityFilter : public ScopedSingleton<ProfanityFilter>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
WordList *wordlist;
|
||||||
|
bool ContainsProfanityWorker(std::string str);
|
||||||
|
public:
|
||||||
|
ProfanityFilter();
|
||||||
|
~ProfanityFilter();
|
||||||
|
|
||||||
|
static bool ContainsProfanity(const std::string& str);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/* Copyright 2003-2008 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Gui/Gui.h"
|
||||||
|
#include "Util/RunStateOwner.h"
|
||||||
|
#include "Network/Player.h"
|
||||||
|
#include "Network/Players.h"
|
||||||
|
#include "V8DataModel/team.h"
|
||||||
|
#include "V8DataModel/teams.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
} // namespace
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Gui/GUI.h"
|
||||||
|
#include "V8Tree/Verb.h"
|
||||||
|
#include "V8DataModel/GuiCore.h"
|
||||||
|
#include "v8datamodel/InputObject.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
class Widget : public GuiItem
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef GuiItem Super;
|
||||||
|
GuiResponse processMouse(const shared_ptr<InputObject>& event);
|
||||||
|
GuiResponse processKey(const shared_ptr<InputObject>& event);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Gui::WidgetState widgetState;
|
||||||
|
|
||||||
|
// This should be standard for all widgets, verb widets, etc.
|
||||||
|
/*override*/ GuiResponse process(const shared_ptr<InputObject>& event);
|
||||||
|
/*override*/ void onLoseFocus() {
|
||||||
|
widgetState = Gui::NOTHING;
|
||||||
|
Super::onLoseFocus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Override these to make new widgets
|
||||||
|
|
||||||
|
// GUI ITEM
|
||||||
|
/*override*/ void render2d(Adorn* adorn);
|
||||||
|
|
||||||
|
// WIDGET
|
||||||
|
virtual void onClick(const shared_ptr<InputObject>& event) {}
|
||||||
|
virtual int getFontSize() const {return 10;}
|
||||||
|
virtual G3D::Color4 getFontColor() {return G3D::Color3::white();}
|
||||||
|
virtual bool isEnabled() {return isVisible();}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Widget();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Humanoid/HumanoidState.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
namespace HUMAN {
|
||||||
|
|
||||||
|
|
||||||
|
class Balancing : public HumanoidState
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
float kP; // units: 1/sec^2 torque = kP * momentOfInertia * rotation
|
||||||
|
float kD; // units: 1/sec torque = kD * momentOfInertia * rotVelocity
|
||||||
|
|
||||||
|
Vector3 lastBalanceTorque;
|
||||||
|
int tick;
|
||||||
|
|
||||||
|
static int balanceRate(double torqueMag);
|
||||||
|
static int balanceRateForPGS();
|
||||||
|
protected:
|
||||||
|
static const float maxTorqueComponent() {return 4000.0f;} // units: 1/sec^2 torque <= maxTorqueComponent * momentOfInertia
|
||||||
|
|
||||||
|
void setBalanceP(float P) { kP = P; };
|
||||||
|
void setBalanceD(float D) { kD = D; };
|
||||||
|
|
||||||
|
// Humanoid::State
|
||||||
|
/*override*/ void onComputeForceImpl();
|
||||||
|
|
||||||
|
public:
|
||||||
|
Balancing(Humanoid* humanoid, StateType priorState);
|
||||||
|
Balancing(Humanoid* humanoid, StateType priorState, const float kP, const float kD);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace HUMAN
|
||||||
|
} // namespace RBX
|
||||||
|
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Humanoid/HumanoidState.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
namespace HUMAN {
|
||||||
|
|
||||||
|
// pure simulation!
|
||||||
|
|
||||||
|
extern const char* const sDead;
|
||||||
|
class Dead : public Named<HumanoidState, sDead>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*override*/ StateType getStateType() const {return DEAD;}
|
||||||
|
/*override*/ void onStepImpl();
|
||||||
|
/*override*/ void onSimulatorStepImpl(float stepDt);
|
||||||
|
/*override*/ void onComputeForceImpl() {}
|
||||||
|
/*override*/ bool enableAutoJump() const { return false; }
|
||||||
|
public:
|
||||||
|
Dead(Humanoid* humanoid, StateType priorState);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern const char* const sFallingDown;
|
||||||
|
class FallingDown : public Named<HumanoidState, sFallingDown>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*override*/ StateType getStateType() const {return FALLING_DWN;}
|
||||||
|
/*override*/ void onComputeForceImpl() {}
|
||||||
|
/*override*/ bool enableAutoJump() const { return false; }
|
||||||
|
public:
|
||||||
|
FallingDown(Humanoid* humanoid, StateType priorState);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const char* const sPhysics;
|
||||||
|
class Physics : public Named<HumanoidState, sPhysics>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*override*/ StateType getStateType() const {return PHYSICS;}
|
||||||
|
/*override*/ void onComputeForceImpl() {}
|
||||||
|
/*override*/ bool enableAutoJump() const { return false; }
|
||||||
|
public:
|
||||||
|
Physics(Humanoid* humanoid, StateType priorState);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace HUMAN
|
||||||
|
} // namespace RBX
|
||||||
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Humanoid/Balancing.h"
|
||||||
|
#include "Util/Name.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
namespace HUMAN {
|
||||||
|
|
||||||
|
// Flying occurs when there's no ground below you. You have the ability
|
||||||
|
// to turn around the y-axis, but not much else.
|
||||||
|
extern const char* const sFlying;
|
||||||
|
|
||||||
|
class Flying : public Named<Balancing, sFlying>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*override*/ StateType getStateType() const {return FLYING;}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Humanoid::State
|
||||||
|
/*override*/ void onSimulatorStepImpl(float stepDt);
|
||||||
|
/*override*/ void onComputeForceImpl();
|
||||||
|
/*override*/ bool enableAutoJump() const { return false; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
Flying(Humanoid* humanoid, StateType priorState);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace HUMAN
|
||||||
|
} // namespace
|
||||||
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Humanoid/Balancing.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
namespace HUMAN {
|
||||||
|
|
||||||
|
extern const char* const sFreefall;
|
||||||
|
|
||||||
|
class Freefall : public Named<Balancing, sFreefall>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef Named<Balancing, sFreefall> Super;
|
||||||
|
bool initialized; // hack- some data is bad in the constructor - do first time through;
|
||||||
|
Vector3 initialLinearVelocity;
|
||||||
|
Velocity desiredVelocity; // Y is world-up
|
||||||
|
float torsoFriction; // I set both of these to zero!
|
||||||
|
float headFriction;
|
||||||
|
|
||||||
|
/*override*/ StateType getStateType() const {return FREE_FALL;}
|
||||||
|
|
||||||
|
/*override*/ void onSimulatorStepImpl(float stepDt);
|
||||||
|
|
||||||
|
/*override*/ void onComputeForceImpl();
|
||||||
|
|
||||||
|
/*override*/ int ladderCheckRate() { return 0; }
|
||||||
|
|
||||||
|
/*override*/ bool armsShouldCollide() const {return false;}
|
||||||
|
/*override*/ bool legsShouldCollide() const {return false;}
|
||||||
|
/*override*/ bool enableAutoJump() const { return false; }
|
||||||
|
|
||||||
|
static float characterVelocityInfluence();
|
||||||
|
static float floorVelocityInfluence();
|
||||||
|
static float velocityDecay();
|
||||||
|
|
||||||
|
public:
|
||||||
|
Freefall(Humanoid* humanoid, StateType priorState);
|
||||||
|
|
||||||
|
~Freefall();
|
||||||
|
|
||||||
|
static float kTurnSpeed();
|
||||||
|
static float kTurnSpeedForPGS();
|
||||||
|
static const float kTurnAccelMax() {return 20000.0f * kTurnSpeed();} // units: 1/sec^2
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace HUMAN
|
||||||
|
} // namespace
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Humanoid/Humanoid.h"
|
||||||
|
#include "Humanoid/Balancing.h"
|
||||||
|
#include "Util/Name.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
namespace HUMAN {
|
||||||
|
|
||||||
|
extern const char* const sGettingUp;
|
||||||
|
|
||||||
|
class GettingUp : public Named<Balancing, sGettingUp>
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
/*override*/ StateType getStateType() const {return GETTING_UP;}
|
||||||
|
|
||||||
|
/*override*/ bool armsShouldCollide() const {return false;}
|
||||||
|
/*override*/ bool legsShouldCollide() const {return false;}
|
||||||
|
/*override*/ bool enableAutoJump() const { return false; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
GettingUp(Humanoid* humanoid, StateType priorState);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // HUMAN
|
||||||
|
} // namespace
|
||||||
|
|
||||||
@@ -0,0 +1,621 @@
|
|||||||
|
/* Copyright 2003-2007 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "V8DataModel/ICharacterSubject.h"
|
||||||
|
#include "V8DataModel/IModelModifier.h"
|
||||||
|
#include "V8DataModel/PartInstance.h"
|
||||||
|
#include "V8DataModel/Tool.h"
|
||||||
|
#include "V8World/KernelJoint.h"
|
||||||
|
#include "V8World/Primitive.h"
|
||||||
|
#include "Util/SteppedInstance.h"
|
||||||
|
#include "GfxBase/IAdornable.h"
|
||||||
|
#include "Util/RunStateOwner.h"
|
||||||
|
#include "Util/ContentFilter.h"
|
||||||
|
#include "Util/HeapValue.h"
|
||||||
|
#include "Humanoid/StatusInstance.h"
|
||||||
|
#include "Humanoid/HumanoidState.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
class World;
|
||||||
|
class RunService;
|
||||||
|
class Controller;
|
||||||
|
class Primitive;
|
||||||
|
class PartInstance;
|
||||||
|
class ModelInstance;
|
||||||
|
class JointInstance;
|
||||||
|
class DataModelMesh;
|
||||||
|
class Decal;
|
||||||
|
class Weld;
|
||||||
|
class Animator;
|
||||||
|
|
||||||
|
namespace HUMAN {
|
||||||
|
class HumanoidState;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Soundscape {
|
||||||
|
class SoundChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern const char* const sHumanoid;
|
||||||
|
class Humanoid
|
||||||
|
: public DescribedCreatable<Humanoid, Instance, sHumanoid>
|
||||||
|
, public KernelJoint // Implements "computeForce"
|
||||||
|
, public IAdornable
|
||||||
|
, public ICharacterSubject
|
||||||
|
, public IModelModifier
|
||||||
|
, public IStepped
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum NameOcclusion
|
||||||
|
{
|
||||||
|
NAME_OCCLUSION_NONE = 0,
|
||||||
|
NAME_OCCLUSION_ENEMY = 1,
|
||||||
|
NAME_OCCLUSION_ALL = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HumanoidDisplayDistanceType
|
||||||
|
{
|
||||||
|
HUMANOID_DISPLAY_DISTANCE_TYPE_VIEWER = 0,
|
||||||
|
HUMANOID_DISPLAY_DISTANCE_TYPE_SUBJECT = 1,
|
||||||
|
HUMANOID_DISPLAY_DISTANCE_TYPE_NONE = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HumanoidRigType
|
||||||
|
{
|
||||||
|
HUMANOID_RIG_TYPE_R6 = 0,
|
||||||
|
HUMANOID_RIG_TYPE_R15 = 1,
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
friend unsigned int HUMAN::HumanoidState::checkComputeEvent(); // only used to check for exploits.
|
||||||
|
|
||||||
|
typedef DescribedCreatable<Humanoid, Instance, sHumanoid> Super;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
// REFLECTED DATA
|
||||||
|
shared_ptr<PartInstance> seatPart; // seat the humanoid is sitting in
|
||||||
|
shared_ptr<PartInstance> walkToPart; // if null, then use the walk speed control
|
||||||
|
Vector3 walkToPoint; // in part coordinate Frame
|
||||||
|
Vector3 walkDirection; // x == xvalue, y == 0, z== zvalue
|
||||||
|
Vector3 luaMoveDirection; // unit vector, used to move humanoid continously in that direction
|
||||||
|
Vector3 rawMovementVector; // unit vector, stores the raw input (never world adjusted)
|
||||||
|
Vector3 targetPoint;
|
||||||
|
Vector3 replicatedTargetPoint;
|
||||||
|
float walkAngleError;
|
||||||
|
HeapValue<float> walkSpeed;
|
||||||
|
HeapValue<float> walkSpeedShadow; // due to exploits.
|
||||||
|
HeapValue<float> percentWalkSpeed; // used to make walk speed variable (for joysticks and the like)
|
||||||
|
HeapValue<float> health;
|
||||||
|
HeapValue<float> maxHealth;
|
||||||
|
mutable ObscureValue<size_t> walkSpeedErrors; // only used in const member functions...
|
||||||
|
HeapValue<float> jumpPower;
|
||||||
|
HeapValue<float> maxSlopeAngle;
|
||||||
|
HeapValue<float> hipHeight;
|
||||||
|
bool torsoArrived;
|
||||||
|
bool jump;
|
||||||
|
bool autoJump;
|
||||||
|
bool sit;
|
||||||
|
bool touchedHard;
|
||||||
|
bool strafe;
|
||||||
|
bool localSimulating; // am I simulating this humanoid?
|
||||||
|
bool ownedByLocalPlayer; // is this my own humanoid?
|
||||||
|
bool typing;
|
||||||
|
bool autorotate;
|
||||||
|
HumanoidRigType rigType;
|
||||||
|
HeapValue<bool> platformStanding;
|
||||||
|
|
||||||
|
bool autoJumpEnabled;
|
||||||
|
|
||||||
|
bool activatePhysics;
|
||||||
|
Vector3 activatePhysicsImpulse; //
|
||||||
|
|
||||||
|
int ragdollCriteria;
|
||||||
|
int numContacts; // Used to signal nearlyTouched event
|
||||||
|
NameOcclusion nameOcclusion;
|
||||||
|
HumanoidDisplayDistanceType displayDistanceType;
|
||||||
|
float nameDisplayDistance;
|
||||||
|
float healthDisplayDistance;
|
||||||
|
Vector3 cameraOffset; // When this humanoid is used as a camera target, offset the camera target by this vector
|
||||||
|
|
||||||
|
bool isWalkingFromStudioTouchEmulation;
|
||||||
|
|
||||||
|
std::string displayText;
|
||||||
|
ContentFilter::FilterResult filterState;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// INTERNAL DATA
|
||||||
|
// Controller interface - server side
|
||||||
|
bool isWalking;
|
||||||
|
double walkTimer;
|
||||||
|
Vector3 getDeltaToGoal() const;
|
||||||
|
void setWalkMode(bool walking);
|
||||||
|
void stepWalkMode(double gameDt);
|
||||||
|
|
||||||
|
bool clickToWalkEnabled;
|
||||||
|
|
||||||
|
bool stateTransitionEnabled[HUMAN::NUM_STATE_TYPES];
|
||||||
|
|
||||||
|
Vector3 lastFloorNormal;
|
||||||
|
// Humanoid Network Floor Platforms
|
||||||
|
boost::shared_ptr<PartInstance> lastFloorPart;
|
||||||
|
boost::shared_ptr<PartInstance> rootFloorMechPart;
|
||||||
|
int lastFilterPhase;
|
||||||
|
|
||||||
|
// hack - easiest place to update is on query of had neck
|
||||||
|
bool hadNeck; // has this humanoid ever had a neck? Only break joints on death if so
|
||||||
|
bool hadHealth; // has this humanoid ever had health > 0? Only break joints on death if so
|
||||||
|
|
||||||
|
Vector3 pos0; // for looking for movement spikes
|
||||||
|
Vector3 pos1;
|
||||||
|
Vector3 pos2;
|
||||||
|
|
||||||
|
void updateHadHealth() {
|
||||||
|
hadHealth = hadHealth || (health > 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef enum {TORSO, HEAD, RIGHT_ARM, LEFT_ARM, RIGHT_LEG, LEFT_LEG, VISIBLE_TORSO, APPENDAGE_COUNT} AppendageType;
|
||||||
|
|
||||||
|
shared_ptr<PartInstance> appendageCache[APPENDAGE_COUNT];
|
||||||
|
shared_ptr<PartInstance> baseInstance;
|
||||||
|
|
||||||
|
rbx::signals::scoped_connection characterChildAdded;
|
||||||
|
rbx::signals::scoped_connection characterChildRemoved;
|
||||||
|
void onEvent_ChildModified(shared_ptr<Instance> child);
|
||||||
|
|
||||||
|
boost::unordered_map<shared_ptr<PartInstance>, rbx::signals::scoped_connection> siblingMap;
|
||||||
|
void updateSiblingPropertyListener(shared_ptr<PartInstance> sibling);
|
||||||
|
void onEvent_SiblingPropertyChanged(const RBX::Reflection::PropertyDescriptor* desc);
|
||||||
|
|
||||||
|
shared_ptr<StatusInstance> status;
|
||||||
|
|
||||||
|
rbx::signals::scoped_connection onCFrameChangedConnection;
|
||||||
|
rbx::signals::scoped_connection humanoidEquipConnection;
|
||||||
|
|
||||||
|
void setCachePointerByType(AppendageType appendage, PartInstance *part);
|
||||||
|
void updateBaseInstance();
|
||||||
|
|
||||||
|
const PartInstance* getConstAppendageSlow(AppendageType appendage) const;
|
||||||
|
PartInstance* getAppendageFast(AppendageType appendage, shared_ptr<PartInstance>& appendagePart);
|
||||||
|
PartInstance* getAppendageSlow(AppendageType appendage);
|
||||||
|
|
||||||
|
World* world;
|
||||||
|
shared_ptr<HUMAN::HumanoidState> currentState;
|
||||||
|
HUMAN::StateType previousState;
|
||||||
|
|
||||||
|
shared_ptr<Animator> animator;
|
||||||
|
Animator* getAnimator();
|
||||||
|
|
||||||
|
void updateLocalSimulating(); // Do I need to simulate this humanoid?
|
||||||
|
|
||||||
|
void onLocalHumanoidEnteringWorkspace();
|
||||||
|
|
||||||
|
void onCFrameChangedFromReflection();
|
||||||
|
|
||||||
|
bool hasWalkToPoint(Vector3& worldPosition) const;
|
||||||
|
|
||||||
|
bool canClickToWalk() const;
|
||||||
|
|
||||||
|
void setLocalTransparencyModifier(float transparencyModifier) const;
|
||||||
|
|
||||||
|
void setWalkDirectionInternal(const Vector3& value, bool raiseSignal);
|
||||||
|
void setJumpInternal(bool value, bool replicate);
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Instance
|
||||||
|
/*override*/ bool askSetParent(const Instance* instance) const;
|
||||||
|
/*override*/ void onAncestorChanged(const AncestorChanged& event);
|
||||||
|
/*override*/ void setName(const std::string& value);
|
||||||
|
/*override*/ void onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider);
|
||||||
|
/*override*/ void onDescendantAdded(Instance* instance);
|
||||||
|
/*override*/ void onDescendantRemoving(const shared_ptr<Instance>& instance);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// IAdornable
|
||||||
|
/*override*/ bool shouldRender3dAdorn() const {return true;}
|
||||||
|
/*override*/ bool shouldRender3dSortedAdorn() const {return true;}
|
||||||
|
/*override*/ Vector3 render3dSortedPosition() const;
|
||||||
|
/*override*/ void render3dAdorn(Adorn* adorn);
|
||||||
|
/*override*/ void render3dSortedAdorn(Adorn* adorn);
|
||||||
|
|
||||||
|
void renderMultiplayer(Adorn* adorn, const RBX::Camera& camera);
|
||||||
|
|
||||||
|
void renderBillboard(Adorn* adorn, const RBX::Camera& camera);
|
||||||
|
void renderBillboardImpl(Adorn* adorn, const Vector2& screenLoc, float fontSize, const Color3& nameTagColor, float nameAlpha, float healthAlpha);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// SteppedInstance
|
||||||
|
/*override*/ void onStepped(const Stepped& event);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// KernelJoint / Connector
|
||||||
|
/*override*/ void computeForce(bool throttling);
|
||||||
|
/*override*/ Body* getEngineBody() {return getRootBodyFast();}
|
||||||
|
/*override*/ virtual KernelType getConnectorKernelType() const { return Connector::HUMANOID; }
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// ILocation
|
||||||
|
/*override*/ const CoordinateFrame getLocation();
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// CameraSubject
|
||||||
|
/*override*/ const CoordinateFrame getRenderLocation();
|
||||||
|
/*override*/ const Vector3 getRenderSize();
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// ICharacterSubject
|
||||||
|
/*override*/ float getYAxisRotationalVelocity() const; // used for camera control
|
||||||
|
/*override*/ void setFirstPersonRotationalVelocity(const Vector3& desiredLook, bool firstPersonOn);
|
||||||
|
/*override*/ void getSelectionIgnorePrimitives(std::vector<const Primitive*>& primitives);
|
||||||
|
/*override*/ virtual bool hasFocusCoord() const {return getHeadSlow() != NULL;}
|
||||||
|
|
||||||
|
// Humanoid Platform Networking
|
||||||
|
bool validateNetworkUpdateDistance(PartInstance* floorPart, CoordinateFrame& previousFloorPosition, float& netDt);
|
||||||
|
void truncateDisplacementIfObstacle(PartInstance* floorPart, Vector3& newCharPosition, const Vector3& previousCharPosition);
|
||||||
|
Vector3 getSimulatedFrictionVelocityOffset(PartInstance* floorPart, Vector3& newCharPosition, const Vector3& previousCharPosition, const Vector3& charPosInFloorSpace, const RBX::Velocity& previousFloorVelocity, float& netDt);
|
||||||
|
const Velocity getHumanoidRelativeVelocityToPart(Primitive* floorPrim);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void updateNetworkFloorPosition(PartInstance* floorPart, CoordinateFrame& previousFloorPosition, RBX::Velocity& lastFloorVelocity, float& netDt);
|
||||||
|
bool shouldNotApplyFloorVelocity(Primitive* floorPrim);
|
||||||
|
bool primitiveIsLastFloor(Primitive* prim);
|
||||||
|
void updateFloorSimPhaseCharVelocity(Primitive* floorPrim);
|
||||||
|
// End Humanoid Platform Networking
|
||||||
|
|
||||||
|
|
||||||
|
/*override*/ void tellCameraNear(float distance) const;
|
||||||
|
/*override*/ void tellCameraSubjectDidChange(shared_ptr<Instance> oldSubject, shared_ptr<Instance> newSubject) const;
|
||||||
|
/*override*/ void tellCursorOver(float cursorOffset) const;
|
||||||
|
/*override*/ void getCameraIgnorePrimitives(std::vector<const Primitive*>& primitives);
|
||||||
|
/*override*/ Velocity calcDesiredWalkVelocity() const; // used for camera control
|
||||||
|
|
||||||
|
static float autoTurnSpeed() {return 8.0f;}
|
||||||
|
|
||||||
|
Humanoid();
|
||||||
|
~Humanoid();
|
||||||
|
|
||||||
|
bool waitingForTorso() { return !torsoArrived; }
|
||||||
|
bool isLegalForClientToChange(const Reflection::PropertyDescriptor& desc) const;
|
||||||
|
int getPlayerId();
|
||||||
|
|
||||||
|
enum Status
|
||||||
|
{
|
||||||
|
POISON_STATUS = 0,
|
||||||
|
CONFUSION_STATUS = 1,
|
||||||
|
};
|
||||||
|
bool hasStatus(Status status);
|
||||||
|
bool addStatus(Status status);
|
||||||
|
bool removeStatus(Status status);
|
||||||
|
bool hasCustomStatus(std::string status);
|
||||||
|
bool addCustomStatus(std::string status);
|
||||||
|
bool removeCustomStatus(std::string status);
|
||||||
|
bool isLocalSimulating() const {return localSimulating;}
|
||||||
|
bool computeNearlyTouched();
|
||||||
|
|
||||||
|
bool getStateTransitionEnabled(HUMAN::StateType state);
|
||||||
|
void setStateTransitionEnabled(HUMAN::StateType state, bool enabled);
|
||||||
|
|
||||||
|
shared_ptr<const Reflection::ValueArray> getStatuses();
|
||||||
|
rbx::signal<void(Status)> statusAddedSignal;
|
||||||
|
rbx::signal<void(Status)> statusRemovedSignal;
|
||||||
|
rbx::signal<void(std::string)> customStatusAddedSignal;
|
||||||
|
rbx::signal<void(std::string)> customStatusRemovedSignal;
|
||||||
|
|
||||||
|
rbx::remote_signal<void(shared_ptr<Instance>)> serverEquipToolSignal;
|
||||||
|
|
||||||
|
// Humanoid Network Update Connection
|
||||||
|
rbx::signals::scoped_connection onPositionUpdatedByNetworkConnection;
|
||||||
|
|
||||||
|
NameOcclusion getNameOcclusion() const { return nameOcclusion; }
|
||||||
|
void setNameOcclusion(NameOcclusion value);
|
||||||
|
|
||||||
|
HumanoidDisplayDistanceType getDisplayDistanceType() const { return displayDistanceType; }
|
||||||
|
void setDisplayDistanceType(HumanoidDisplayDistanceType value);
|
||||||
|
|
||||||
|
static Humanoid* humanoidFromBodyPart(Instance* bodyPart);
|
||||||
|
static const Humanoid* constHumanoidFromBodyPart(const Instance* bodyPart);
|
||||||
|
static const Humanoid* constHumanoidFromDescendant(const Instance* bodyPart);
|
||||||
|
|
||||||
|
static Humanoid* modelIsCharacter(Instance* testModel);
|
||||||
|
static const Humanoid* modelIsConstCharacter(const Instance* testModel);
|
||||||
|
|
||||||
|
static Humanoid* getLocalHumanoidFromContext(Instance* context);
|
||||||
|
static const Humanoid* getConstLocalHumanoidFromContext(const Instance* context);
|
||||||
|
|
||||||
|
static PartInstance* getLocalHeadFromContext(Instance* context);
|
||||||
|
static const PartInstance* getConstLocalHeadFromContext(const Instance* context);
|
||||||
|
|
||||||
|
static ModelInstance* getCharacterFromHumanoid(Humanoid* humanoid);
|
||||||
|
static const ModelInstance* getConstCharacterFromHumanoid(const Humanoid* humanoid);
|
||||||
|
|
||||||
|
static PartInstance* getHeadFromCharacter(ModelInstance* character);
|
||||||
|
static const PartInstance* getConstHeadFromCharacter(const ModelInstance* character);
|
||||||
|
|
||||||
|
static Weld* getGrip(Instance* character);
|
||||||
|
|
||||||
|
static const Vector3 &defaultCharacterCorner() { static Vector3 corner(2.5f,2.5f,2.5f); return corner; }
|
||||||
|
|
||||||
|
// By Definition, these are all called by HumanoidState - these are reflected
|
||||||
|
rbx::signal<void()> diedSignal;
|
||||||
|
rbx::signal<void(float)> swimmingSignal;
|
||||||
|
rbx::signal<void(float)> runningSignal; // state change scripts
|
||||||
|
rbx::signal<void(float)> climbingSignal; // state change scripts
|
||||||
|
rbx::signal<void(bool)> jumpingSignal; // state change scripts
|
||||||
|
rbx::signal<void(bool)> freeFallingSignal;
|
||||||
|
rbx::signal<void(bool)> strafingSignal;
|
||||||
|
rbx::signal<void(bool)> gettingUpSignal;
|
||||||
|
rbx::signal<void(bool)> fallingDownSignal;
|
||||||
|
rbx::signal<void(bool)> ragdollSignal;
|
||||||
|
rbx::signal<void(bool, shared_ptr<Instance>)> seatedSignal;
|
||||||
|
rbx::signal<void(bool)> platformStandingSignal;
|
||||||
|
rbx::signal<void(RBX::HUMAN::StateType, RBX::HUMAN::StateType)> stateChangedSignal;
|
||||||
|
rbx::signal<void(RBX::HUMAN::StateType, bool)> stateEnabledChangedSignal;
|
||||||
|
RBX::HUMAN::StateType getCurrentStateType();
|
||||||
|
RBX::HUMAN::StateType getPreviousStateType() { return previousState; };
|
||||||
|
void setPreviousStateType(RBX::HUMAN::StateType newState);
|
||||||
|
void changeState(RBX::HUMAN::StateType state);
|
||||||
|
static bool isStateInString(const std::string& text, const RBX::HUMAN::StateType &compare, RBX::HUMAN::StateType& value);
|
||||||
|
|
||||||
|
rbx::signal<void(float)> healthChangedSignal;
|
||||||
|
|
||||||
|
// Internal use only - no reflection - happens both client, server
|
||||||
|
rbx::signal<void()> doneSittingSignal;
|
||||||
|
rbx::signal<void()> donePlatformStandingSignal;
|
||||||
|
|
||||||
|
void equipToolInstance(shared_ptr<Instance> instance);
|
||||||
|
void equipTool(RBX::Tool* tool);
|
||||||
|
void unequipTools();
|
||||||
|
|
||||||
|
void setWalkSpeed(float value);
|
||||||
|
float getWalkSpeed() const {return walkSpeed;}
|
||||||
|
void testWalkSpeed(float walkSpeed, float percentWalkSpeed) const
|
||||||
|
{
|
||||||
|
walkSpeedErrors = (walkSpeed > walkSpeedShadow) ? walkSpeedErrors + 1 : 0;
|
||||||
|
if (walkSpeedErrors > 8)
|
||||||
|
{
|
||||||
|
RBX::Security::setHackFlagVs<LINE_RAND4>(RBX::Security::hackFlag11, HATE_SPEEDHACK);
|
||||||
|
}
|
||||||
|
if (fabs(percentWalkSpeed) > 1.01)
|
||||||
|
{
|
||||||
|
RBX::Security::setHackFlagVs<LINE_RAND4>(RBX::Security::hackFlag11, HATE_SPEEDHACK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPercentWalkSpeed(float value);
|
||||||
|
float getPercentWalkSpeed() const { return percentWalkSpeed; }
|
||||||
|
|
||||||
|
void setJumpPower(float value);
|
||||||
|
float getJumpPower() const { return jumpPower; }
|
||||||
|
|
||||||
|
void setMaxSlopeAngle(float value);
|
||||||
|
float getMaxSlopeAngle() const { return maxSlopeAngle; }
|
||||||
|
|
||||||
|
const Vector3 &getLastFloorNormal() const { return lastFloorNormal; }
|
||||||
|
void setLastFloorNormal(const Vector3 &norm) { lastFloorNormal = norm; }
|
||||||
|
|
||||||
|
void setHipHeight(float value);
|
||||||
|
float getHipHeight() const { return hipHeight; }
|
||||||
|
|
||||||
|
// Health / damage interface
|
||||||
|
void setHealth(float value);
|
||||||
|
void setHealthUi(float value);
|
||||||
|
void zeroHealthLocal() {health = 0.0f;} // for a non-simulating client -zero out health without bouncing back to the server
|
||||||
|
float getHealth() const {return health;}
|
||||||
|
|
||||||
|
void setMaxHealth(float value);
|
||||||
|
float getMaxHealth() const {return maxHealth;}
|
||||||
|
|
||||||
|
void setTyping(bool value) { typing = value; }
|
||||||
|
bool getTyping() const { return typing; }
|
||||||
|
|
||||||
|
void takeDamage(float value); // honors explosions, etc.
|
||||||
|
|
||||||
|
void setClickToWalkEnabled(bool value) { clickToWalkEnabled = value; }
|
||||||
|
|
||||||
|
// Controller interface - don't set the walk direction directly
|
||||||
|
void setWalkDirection(const Vector3& value); // compacted - z is in the y place
|
||||||
|
Vector3 getWalkDirection() const {return walkDirection;} // compacted - z is in the y place
|
||||||
|
bool allow3dWalkDirection() const;
|
||||||
|
|
||||||
|
void move(Vector3 walkVector, bool relativeToCamera);
|
||||||
|
|
||||||
|
Vector3 getLuaMoveDirection() const { return luaMoveDirection;}
|
||||||
|
void setLuaMoveDirection(const Vector3& value);
|
||||||
|
Vector3 getRawMovementVector() const { return rawMovementVector; }
|
||||||
|
|
||||||
|
bool getAutoJumpEnabled() const { return autoJumpEnabled; };
|
||||||
|
void setAutoJumpEnabled(bool value);
|
||||||
|
|
||||||
|
void setWalkAngleError(const float &value);
|
||||||
|
float getWalkAngleError() const {return walkAngleError;}
|
||||||
|
|
||||||
|
void setWalkToPoint(const Vector3& value);
|
||||||
|
const Vector3& getWalkToPoint() const {return walkToPoint;}
|
||||||
|
|
||||||
|
void setWalkToPart(PartInstance* value);
|
||||||
|
PartInstance* getWalkToPart() const {return walkToPart.get();}
|
||||||
|
|
||||||
|
void setSeatPart(PartInstance* value);
|
||||||
|
PartInstance* getSeatPart() const {return seatPart.get();}
|
||||||
|
|
||||||
|
void setJump(bool value);
|
||||||
|
bool getJump() const { return jump; }
|
||||||
|
|
||||||
|
void setAutoJump(bool value);
|
||||||
|
bool getAutoJump() const { return autoJump;}
|
||||||
|
|
||||||
|
void setSit(bool value);
|
||||||
|
bool getSit() const { return sit; }
|
||||||
|
|
||||||
|
void setAutoRotate(bool value);
|
||||||
|
bool getAutoRotate() const { return autorotate; }
|
||||||
|
|
||||||
|
void setTouchedHard(bool hit) { touchedHard = hit; }
|
||||||
|
|
||||||
|
void setActivatePhysics(bool flag, const Vector3& impulse)
|
||||||
|
{
|
||||||
|
activatePhysics = flag;
|
||||||
|
if (flag)
|
||||||
|
activatePhysicsImpulse += impulse;
|
||||||
|
else
|
||||||
|
activatePhysicsImpulse = impulse;
|
||||||
|
}
|
||||||
|
bool getActivatePhysics() { return activatePhysics; }
|
||||||
|
const Vector3 getActivatePhysicsImpulse() { return activatePhysicsImpulse; }
|
||||||
|
bool getTouchedHard() { return touchedHard; }
|
||||||
|
|
||||||
|
void setRagdollCriteria(int value);
|
||||||
|
int getRagdollCriteria() const { return ragdollCriteria; }
|
||||||
|
|
||||||
|
void setPlatformStanding(bool value);
|
||||||
|
bool getPlatformStanding() const { return platformStanding; }
|
||||||
|
|
||||||
|
void setStrafe(bool value);
|
||||||
|
bool getStrafe() const { return strafe; }
|
||||||
|
|
||||||
|
bool getDead() const;
|
||||||
|
|
||||||
|
void setHadNeck() {hadNeck = true;}
|
||||||
|
bool breakJointsOnDeath() const {return hadNeck && hadHealth;}
|
||||||
|
|
||||||
|
void setTargetPoint(const Vector3& value);
|
||||||
|
void setTargetPointLocal(const Vector3& value); // does not replicate
|
||||||
|
const Vector3& getTargetPoint() const {return targetPoint;}
|
||||||
|
|
||||||
|
void setNameDisplayDistance(float d);
|
||||||
|
float getNameDisplayDistance() const { return nameDisplayDistance; }
|
||||||
|
|
||||||
|
void setHealthDisplayDistance(float d);
|
||||||
|
float getHealthDisplayDistance() const { return healthDisplayDistance; }
|
||||||
|
|
||||||
|
void setCameraOffset(const Vector3 &value);
|
||||||
|
const Vector3 &getCamearaOffset() const { return cameraOffset; }
|
||||||
|
|
||||||
|
// Humanoid Platform Update Getters and Setters;
|
||||||
|
void setLastFloor(PartInstance* part)
|
||||||
|
{
|
||||||
|
if(lastFloorPart)
|
||||||
|
{
|
||||||
|
lastFloorPart.reset();
|
||||||
|
}
|
||||||
|
lastFloorPart = shared_from(part);
|
||||||
|
}
|
||||||
|
const shared_ptr<PartInstance>& getLastFloor() const { return lastFloorPart; }
|
||||||
|
|
||||||
|
void setRootFloorPart(PartInstance* part)
|
||||||
|
{
|
||||||
|
if (rootFloorMechPart)
|
||||||
|
{
|
||||||
|
rootFloorMechPart.reset();
|
||||||
|
}
|
||||||
|
rootFloorMechPart = shared_from(part);
|
||||||
|
}
|
||||||
|
shared_ptr<PartInstance> getRootFloorPart() const { return rootFloorMechPart; }
|
||||||
|
|
||||||
|
int getCurrentFloorFilterPhase();
|
||||||
|
int getCurrentFloorFilterPhase(Assembly* floorAssembly);
|
||||||
|
|
||||||
|
void setLastFloorPhase(int phase) { lastFilterPhase = phase; }
|
||||||
|
int getLastFloorPhase() const { return lastFilterPhase; }
|
||||||
|
|
||||||
|
// Walk Utilities
|
||||||
|
void moveTo(const Vector3& worldPosition, PartInstance* part);
|
||||||
|
void moveTo2(Vector3 worldPosition, shared_ptr<Instance> part);
|
||||||
|
rbx::signal<void(bool)> moveToFinishedSignal;
|
||||||
|
|
||||||
|
bool getUseR15() const { return (rigType != HUMANOID_RIG_TYPE_R6); }
|
||||||
|
Humanoid::HumanoidRigType getRigType() const { return rigType; }
|
||||||
|
void setRigType(Humanoid::HumanoidRigType type);
|
||||||
|
|
||||||
|
// Build Joints
|
||||||
|
void buildJoints(RBX::DataModel* dm = NULL);
|
||||||
|
void buildJointsFromAttachments(PartInstance* part, std::vector<PartInstance*>& characterParts);
|
||||||
|
|
||||||
|
JointInstance* getRightShoulder();
|
||||||
|
Joint* getNeck();
|
||||||
|
|
||||||
|
// Primitive
|
||||||
|
void getPrimitives(std::vector<Primitive*>& primitives) const;
|
||||||
|
|
||||||
|
void getParts(std::vector<PartInstance*>& primitives) const;
|
||||||
|
|
||||||
|
PartInstance* getTorsoDangerous() const; // reflection only
|
||||||
|
PartInstance* getLeftLegDangerous() const; // reflection only
|
||||||
|
PartInstance* getRightLegDangerous() const; // reflection only
|
||||||
|
|
||||||
|
// TODO: No internal buffering - after refactor, rename without the word slow
|
||||||
|
PartInstance* getTorsoSlow(); // no internal buffering
|
||||||
|
PartInstance* getVisibleTorsoSlow();
|
||||||
|
PartInstance* getHeadSlow();
|
||||||
|
PartInstance* getLeftLegSlow();
|
||||||
|
PartInstance* getRightLegSlow();
|
||||||
|
PartInstance* getLeftArmSlow();
|
||||||
|
PartInstance* getRightArmSlow();
|
||||||
|
StatusInstance* getStatusSlow();
|
||||||
|
|
||||||
|
const PartInstance* getTorsoSlow() const; // no internal buffering
|
||||||
|
const PartInstance* getVisibleTorsoSlow() const;
|
||||||
|
const PartInstance* getHeadSlow() const;
|
||||||
|
const PartInstance* getLeftLegSlow() const;
|
||||||
|
const PartInstance* getRightLegSlow() const;
|
||||||
|
const PartInstance* getLeftArmSlow() const;
|
||||||
|
const PartInstance* getRightArmSlow() const;
|
||||||
|
const StatusInstance* getStatusSlow() const;
|
||||||
|
|
||||||
|
Primitive* getTorsoPrimitiveSlow();
|
||||||
|
Primitive* getHeadPrimitiveSlow();
|
||||||
|
|
||||||
|
// Internal buffering
|
||||||
|
PartInstance* getTorsoFast();
|
||||||
|
PartInstance* getVisibleTorsoFast();
|
||||||
|
PartInstance* getHeadFast();
|
||||||
|
PartInstance* getLeftLegFast();
|
||||||
|
PartInstance* getRightLegFast();
|
||||||
|
PartInstance* getLeftArmFast();
|
||||||
|
PartInstance* getRightArmFast();
|
||||||
|
StatusInstance* getStatusFast();
|
||||||
|
|
||||||
|
Primitive* getTorsoPrimitiveFast();
|
||||||
|
|
||||||
|
// Body
|
||||||
|
inline Body* getTorsoBodyFast()
|
||||||
|
{
|
||||||
|
Primitive* prim = getTorsoPrimitiveFast();
|
||||||
|
return prim ? prim->getBody() : NULL;
|
||||||
|
}
|
||||||
|
Body* getRootBodyFast();
|
||||||
|
|
||||||
|
// Attachment Points
|
||||||
|
CoordinateFrame getTopOfHead() const;
|
||||||
|
CoordinateFrame getRightArmGrip() const;
|
||||||
|
|
||||||
|
float getTorsoHeading() const; // 0 == North == -Z. Pi/2 = WEST == -x
|
||||||
|
float getTorsoElevation() const;
|
||||||
|
|
||||||
|
void setTorso(PartInstance* value);
|
||||||
|
void setLeftLeg(PartInstance* value);
|
||||||
|
void setRightLeg(PartInstance* value);
|
||||||
|
|
||||||
|
void setHeadMesh(DataModelMesh* value);
|
||||||
|
void setHeadDecal(Decal* value);
|
||||||
|
|
||||||
|
World* getWorld() {return world;};
|
||||||
|
const World* getConstWorld() const {return world;};
|
||||||
|
|
||||||
|
static void renderWaypoint(Adorn* adorn, const Vector3& waypoint);
|
||||||
|
|
||||||
|
// proxy interface to Animator object.
|
||||||
|
shared_ptr<Instance> loadAnimation(shared_ptr<Instance> animation);
|
||||||
|
bool CheckTorso();
|
||||||
|
void setupAnimator();
|
||||||
|
shared_ptr<const Reflection::ValueArray> getPlayingAnimationTracks();
|
||||||
|
|
||||||
|
rbx::signal<void(shared_ptr<Instance>)> animationPlayedSignal;
|
||||||
|
|
||||||
|
bool getOwnedByLocalPlayer() const { return ownedByLocalPlayer; }
|
||||||
|
|
||||||
|
bool getWalkingFromStudioTouchEmulation() const { return isWalkingFromStudioTouchEmulation; }
|
||||||
|
void setWalkingFromStudioTouchEmulation(bool value) { isWalkingFromStudioTouchEmulation = value; }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace RBX
|
||||||
@@ -0,0 +1,346 @@
|
|||||||
|
/* Copyright 2003-2007 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include "Util/HitTestFilter.h"
|
||||||
|
#include "GfxBase/IAdornable.h"
|
||||||
|
#include "Util/Name.h"
|
||||||
|
#include "rbx/Debug.h"
|
||||||
|
#include "Util/Velocity.h"
|
||||||
|
#include "rbx/boost.hpp"
|
||||||
|
#include "Reflection/Event.h"
|
||||||
|
#include "G3D/Array.h"
|
||||||
|
#include "util/PartMaterial.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#define CHARACTER_FORCE_DEBUG 0
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
class Humanoid;
|
||||||
|
class PartInstance;
|
||||||
|
class Controller;
|
||||||
|
class Assembly;
|
||||||
|
class GeometryService;
|
||||||
|
|
||||||
|
namespace HUMAN
|
||||||
|
{
|
||||||
|
typedef enum { FALLING_DWN = 0,
|
||||||
|
RAGDOLL, // 1
|
||||||
|
GETTING_UP,
|
||||||
|
JUMPING,
|
||||||
|
SWIMMING,
|
||||||
|
FREE_FALL, // 4: balancing, no thrust
|
||||||
|
FLYING,
|
||||||
|
LANDED, // 6: can't jump
|
||||||
|
RUNNING, // 7
|
||||||
|
RUNNING_SLAVE, // 8: slave side - lock to running mode to do accurate physics when touched slave side
|
||||||
|
RUNNING_NO_PHYS, // 9
|
||||||
|
STRAFING_NO_PHYS,
|
||||||
|
CLIMBING,
|
||||||
|
SEATED,
|
||||||
|
PLATFORM_STANDING,
|
||||||
|
DEAD,
|
||||||
|
PHYSICS,
|
||||||
|
NUM_STATE_TYPES,
|
||||||
|
xx } StateType; // XX == NO change
|
||||||
|
|
||||||
|
typedef enum { NO_HEALTH = 0, // Humanoid Commands
|
||||||
|
NO_NECK,
|
||||||
|
JUMP_CMD,
|
||||||
|
STRAFE_CMD,
|
||||||
|
NO_STRAFE_CMD,
|
||||||
|
SIT_CMD,
|
||||||
|
NO_SIT_CMD,
|
||||||
|
PLATFORM_STAND_CMD,
|
||||||
|
NO_PLATFORM_STAND_CMD,
|
||||||
|
TIPPED, // Tilting
|
||||||
|
UPRIGHT,
|
||||||
|
FACE_LDR, // Ladder
|
||||||
|
AWAY_LDR,
|
||||||
|
OFF_FLOOR, // Floor
|
||||||
|
OFF_FLOOR_GRACE, // Floor w/ Grace Period
|
||||||
|
ON_FLOOR,
|
||||||
|
TOUCHED, // Other Objects
|
||||||
|
NEARLY_TOUCHED, // Other Objects
|
||||||
|
TOUCHED_HARD,
|
||||||
|
ACTIVATE_PHYSICS,
|
||||||
|
FINISHED,
|
||||||
|
TIMER_UP, // FINISHED_FALLING, READY_TO_JUMP,
|
||||||
|
NO_TOUCH_ONE_SECOND,
|
||||||
|
HAS_GYRO,
|
||||||
|
HAS_BUOYANCY,
|
||||||
|
NO_BUOYANCY,
|
||||||
|
NUM_EVENT_TYPES } EventType;
|
||||||
|
|
||||||
|
#if CHARACTER_FORCE_DEBUG
|
||||||
|
class DebugRay
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RbxRay ray;
|
||||||
|
Color3 color;
|
||||||
|
|
||||||
|
DebugRay(const RbxRay& _ray, const Color3& _color)
|
||||||
|
{
|
||||||
|
ray = _ray;
|
||||||
|
color = _color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Draw(Adorn* adorn);
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class HumanoidState : public INamed,
|
||||||
|
public HitTestFilter
|
||||||
|
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const unsigned int kCorrectCheckValue = 2;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const Vector3& unitializedFloorTouch() const {
|
||||||
|
static Vector3 v(1e15f, 1e15f, 1e15f);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
Humanoid* humanoid;
|
||||||
|
float timer;
|
||||||
|
float noTouchTimer;
|
||||||
|
bool nearlyTouched;
|
||||||
|
bool shouldRender;
|
||||||
|
bool finished;
|
||||||
|
bool outOfWater;
|
||||||
|
bool headClear;
|
||||||
|
StateType priorState;
|
||||||
|
StateType luaState;
|
||||||
|
|
||||||
|
G3D::Array<PartInstance*> foundParts; // temp buffer
|
||||||
|
bool facingLadder;
|
||||||
|
shared_ptr<PartInstance> floorPart;
|
||||||
|
PartMaterial floorMaterial;
|
||||||
|
Vector3 floorTouchInWorld;
|
||||||
|
Vector3 floorTouchNormal;
|
||||||
|
Vector3 floorHumanoidLocationInWorld;
|
||||||
|
float noFloorTimer;
|
||||||
|
|
||||||
|
// Cut down firing of the running event to when there are major difference in velocity
|
||||||
|
float lastMovementVelocity;
|
||||||
|
|
||||||
|
// signals that the state needs these updated
|
||||||
|
bool usesEvent(EventType e) const;
|
||||||
|
bool usesLadder() const {return (usesEvent(FACE_LDR) || usesEvent(AWAY_LDR));}
|
||||||
|
bool usesFloor() const {return (usesEvent(OFF_FLOOR) || usesEvent(ON_FLOOR) || usesEvent(OFF_FLOOR_GRACE));}
|
||||||
|
|
||||||
|
float computeTilt() const;
|
||||||
|
bool computeTipped() const;
|
||||||
|
bool computeUpright() const;
|
||||||
|
bool computeHasGyro() const;
|
||||||
|
bool computeJumped() const;
|
||||||
|
float computeFloorTilt() const;
|
||||||
|
|
||||||
|
void setLegsCanCollide(bool canCollide);
|
||||||
|
void setArmsCanCollide(bool canCollide);
|
||||||
|
void setHeadCanCollide(bool canCollide);
|
||||||
|
void setTorsoCanCollide(bool canCollide);
|
||||||
|
|
||||||
|
int ladderCheck;
|
||||||
|
virtual int ladderCheckRate() { return 2; }
|
||||||
|
bool findPrimitiveInLadderZone(Adorn* adorn);
|
||||||
|
bool findLadder(Adorn* adorn);
|
||||||
|
void doLadderRaycast(GeometryService *geom, const RbxRay& caster,Humanoid* humanoid, Primitive** hitPrimOut,
|
||||||
|
Vector3* hitLocationOut);
|
||||||
|
void doAutoJump();
|
||||||
|
void findFloor(shared_ptr<PartInstance>& oldFloor);
|
||||||
|
shared_ptr<PartInstance> tryFloor(const RbxRay& ray, Vector3& hitLocation, Vector3& hitNormal, float maxDistance, Assembly* humanoidAssembly, PartMaterial& recentFloorMaterial);
|
||||||
|
void AverageFloorRayCast(shared_ptr<PartInstance> &floorPart, Vector3& floorPartHitLocation, Vector3& floorPartHitNormal,
|
||||||
|
PartMaterial& floorPartHitMaterial, Vector3& hitLocationAccumulator, int& hitLocationCount, const bool UpdateFloorPart,
|
||||||
|
const Vector3& offset, const float maxDistance, Assembly* humanoidAssembly, const CoordinateFrame& torsoC);
|
||||||
|
void preStepFloor();
|
||||||
|
void preStepCollide();
|
||||||
|
void preStepSimulatorSide(float dt);
|
||||||
|
void preStepSlaveSide() {preStepCollide();}
|
||||||
|
|
||||||
|
static void doSimulatorStateTable(shared_ptr<HumanoidState>& state, float dt);
|
||||||
|
static void doSlaveStateTable(shared_ptr<HumanoidState>& state, StateType newType);
|
||||||
|
static HumanoidState* create(StateType newType, StateType oldType, Humanoid* humanoid);
|
||||||
|
static HumanoidState* createNew(StateType newType, StateType oldType, Humanoid* humanoid);
|
||||||
|
static void changeState(shared_ptr<HumanoidState>& state, StateType newType);
|
||||||
|
|
||||||
|
void fireEvent(StateType stateType, bool entering);
|
||||||
|
|
||||||
|
// Override hitTestFiler
|
||||||
|
/*override*/ Result filterResult(const Primitive* testMe) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// For debugging
|
||||||
|
Vector3 maxTorque;
|
||||||
|
Vector3 maxForce;
|
||||||
|
float maxContactVel;
|
||||||
|
Vector3 lastTorque;
|
||||||
|
Vector3 lastForce;
|
||||||
|
float lastContactVel;
|
||||||
|
|
||||||
|
static float minMoveVelocity() {return 0.5f;}
|
||||||
|
static float maxClimbDistance() {return 2.45f;} // studs
|
||||||
|
static const Vector3 maxMoveForce() {static Vector3 m(1000.0f, 10000.0f, 1000.0f); return m;} //const Vector3 maxMoveAccelerationGrid(5e4f*0.02f, 5e5f*0.02f, 1e4f*0.02f);
|
||||||
|
static const Vector3 minMoveForce() {static Vector3 m(-1000.0f, 0.0f, -1000.0f); return m;}
|
||||||
|
static const Vector3 maxSwimmingMoveForce() {static Vector3 m(10000.0f, 1000.0f, 10000.0f); return m;}
|
||||||
|
static const Vector3 minSwimmingMoveForce() {static Vector3 m(-10000.0f, -10000.0f, -10000.0f); return m;}
|
||||||
|
static float fallDelay() { return 0.125f; }
|
||||||
|
static float maxLinearMoveForce() { return 143.0; }
|
||||||
|
|
||||||
|
// Need public for some Physics calculations outside of Humanoid State
|
||||||
|
public:
|
||||||
|
float steepSlopeAngle() const;
|
||||||
|
static float runningKMoveP();
|
||||||
|
static float runningKMovePForPGS();
|
||||||
|
static float maxLinearGroundMoveForce() { return 500.0; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Assembly* filteringAssembly;
|
||||||
|
|
||||||
|
bool computeEvent(EventType eventType);
|
||||||
|
|
||||||
|
bool computeTouched();
|
||||||
|
bool computeNearlyTouched();
|
||||||
|
bool computeTouchedByMySimulation();
|
||||||
|
bool computeTouchedHard();
|
||||||
|
bool computeActivatePhysics();
|
||||||
|
|
||||||
|
void setOutOfWater() { outOfWater = true; }
|
||||||
|
bool getOutOfWater() const { return outOfWater; }
|
||||||
|
|
||||||
|
void setTimer(float time) {timer = time;}
|
||||||
|
float getTimer() const {return timer;}
|
||||||
|
|
||||||
|
bool getFinished() const {return finished;}
|
||||||
|
void setFinished(bool value) {finished = value;}
|
||||||
|
|
||||||
|
bool getFacingLadder() const {return facingLadder;}
|
||||||
|
bool getHeadClear() const { return headClear; }
|
||||||
|
|
||||||
|
PartMaterial getFloorMaterial() const { return floorMaterial; }
|
||||||
|
float getFloorFrictionProperty(Primitive* floorPrim) const;
|
||||||
|
|
||||||
|
Primitive* getFloorPrimitive();
|
||||||
|
const Primitive* getFloorPrimitiveConst() const;
|
||||||
|
const Vector3& getFloorTouchInWorld() const {
|
||||||
|
RBXASSERT(floorTouchInWorld != unitializedFloorTouch());
|
||||||
|
return floorTouchInWorld;
|
||||||
|
}
|
||||||
|
const Vector3& getFloorTouchNormal() const {
|
||||||
|
RBXASSERT(floorTouchInWorld != unitializedFloorTouch());
|
||||||
|
return floorTouchNormal;
|
||||||
|
}
|
||||||
|
const Vector3& getFloorHumanoidLocationInWorld() const {
|
||||||
|
RBXASSERT(floorHumanoidLocationInWorld != unitializedFloorTouch());
|
||||||
|
return floorHumanoidLocationInWorld;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Velocity getFloorPointVelocity();
|
||||||
|
Vector3 getRelativeMovementVelocity();
|
||||||
|
float getDesiredAltitude() const;
|
||||||
|
|
||||||
|
#if CHARACTER_FORCE_DEBUG
|
||||||
|
std::vector<DebugRay> debugRayList;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void fireMovementSignal(rbx::signal<void(float)>& movementSignal, float movementVelocity);
|
||||||
|
|
||||||
|
// Tick Count - 30 FPS, state table occurs here
|
||||||
|
virtual void onComputeForceImpl() = 0;
|
||||||
|
virtual void onStepImpl() {}
|
||||||
|
virtual void onSimulatorStepImpl(float stepDt) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setCanThrottleState(bool canThrottle); // only the Seated state can throttle - its joined to parts so it must
|
||||||
|
|
||||||
|
// Attributes moved in assemblies
|
||||||
|
Assembly* getAssembly();
|
||||||
|
const Assembly* getAssemblyConst() const;
|
||||||
|
void stateToAssembly();
|
||||||
|
StateType stateFromAssembly();
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual bool armsShouldCollide() const {return true;}
|
||||||
|
virtual bool legsShouldCollide() const {return true;}
|
||||||
|
virtual bool headShouldCollide() const {return true;}
|
||||||
|
virtual bool torsoShouldCollide() const {return true;}
|
||||||
|
|
||||||
|
virtual bool enableAutoJump() const { return true; }
|
||||||
|
|
||||||
|
virtual void onCFrameChangedFromReflection() { preStepFloor();} // recalculate floor part
|
||||||
|
|
||||||
|
|
||||||
|
HumanoidState(Humanoid* humanoid, StateType priorState);
|
||||||
|
|
||||||
|
virtual ~HumanoidState();
|
||||||
|
|
||||||
|
const Humanoid* getHumanoidConst() const;
|
||||||
|
|
||||||
|
Humanoid* getHumanoid() {
|
||||||
|
return const_cast<Humanoid*>(getHumanoidConst());
|
||||||
|
}
|
||||||
|
|
||||||
|
static HumanoidState* defaultState(Humanoid* humanoid); // new Running(this));
|
||||||
|
|
||||||
|
static void simulate(shared_ptr<HumanoidState>& state, float dt);
|
||||||
|
|
||||||
|
static void updateHumanoidFloorStatus(shared_ptr<HumanoidState>& state);
|
||||||
|
|
||||||
|
static bool hasFloorChanged(shared_ptr<HumanoidState>& state, Primitive* lastFloorPrim);
|
||||||
|
|
||||||
|
static void noSimulate(shared_ptr<HumanoidState>& state); // for non-simulating humanoids, match states
|
||||||
|
|
||||||
|
virtual void fireEvents();
|
||||||
|
|
||||||
|
virtual float getYAxisRotationalVelocity() const {return 0.0f;}
|
||||||
|
|
||||||
|
float getCharacterHipHeight() const;
|
||||||
|
|
||||||
|
void onComputeForce();
|
||||||
|
|
||||||
|
bool torsoHasBuoyancy, leftLegHasBuoyancy, rightLegHasBuoyancy;
|
||||||
|
std::vector<rbx::signals::connection> buoyancyConnections;
|
||||||
|
void setTorsoHasBuoyancy( bool value ) { torsoHasBuoyancy = value; }
|
||||||
|
void setLeftLegHasBuoyancy( bool value ) { leftLegHasBuoyancy = value; }
|
||||||
|
void setRightLegHasBuoyancy( bool value ) { rightLegHasBuoyancy = value; }
|
||||||
|
bool computeHasBuoyancy();
|
||||||
|
|
||||||
|
virtual StateType getStateType() const = 0;
|
||||||
|
|
||||||
|
void setLuaState(StateType state);
|
||||||
|
StateType getLuaState() { return luaState; }
|
||||||
|
|
||||||
|
static const char *getStateNameByType(StateType state);
|
||||||
|
|
||||||
|
bool computeHitByHighImpactObject();
|
||||||
|
|
||||||
|
// only in debug
|
||||||
|
void render3dAdorn(Adorn* adorn);
|
||||||
|
|
||||||
|
void setNearlyTouched();
|
||||||
|
|
||||||
|
// for security purposes, get the address of this code.
|
||||||
|
// A member function pointer is a compiler defined data structure.
|
||||||
|
static inline const void* getComputeEventBaseAddress()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
bool (RBX::HUMAN::HumanoidState::* hsce)(EventType) = &computeEvent;
|
||||||
|
if(sizeof(hsce) == 8 || sizeof(hsce) == 4)
|
||||||
|
{
|
||||||
|
return (const void*&)(hsce); // odd, but required syntax for this horrible conversion.
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int checkComputeEvent(); // this was added due to exploits.
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace HUMAN
|
||||||
|
} // namespace RBX
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Humanoid/Flying.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
namespace HUMAN {
|
||||||
|
|
||||||
|
extern const char* const sJumping;
|
||||||
|
|
||||||
|
class Jumping : public Named<Flying, sJumping>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef Named<Flying, sJumping> Super;
|
||||||
|
/*override*/ StateType getStateType() const {return JUMPING;}
|
||||||
|
|
||||||
|
// Humanoid::State
|
||||||
|
/*override*/ void onComputeForceImpl();
|
||||||
|
|
||||||
|
/*override*/ bool armsShouldCollide() const {return false;}
|
||||||
|
/*override*/ bool legsShouldCollide() const {return false;}
|
||||||
|
/*override*/ bool torsoShouldCollide() const {return false;}
|
||||||
|
|
||||||
|
// Override hitTestFiler
|
||||||
|
/*override*/ Result filterResult(const Primitive* testMe) const;
|
||||||
|
|
||||||
|
bool findCeiling();
|
||||||
|
shared_ptr<PartInstance> tryCeiling(const RbxRay& ray, float maxDistance, Assembly* humanoidAssembly);
|
||||||
|
|
||||||
|
Vector3 jumpDir;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Jumping(Humanoid* humanoid, StateType priorState);
|
||||||
|
|
||||||
|
static float kJumpP() {return 500.0f;}
|
||||||
|
static float kJumpVelocityGrid() {return 50.0f;}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace HUMAN
|
||||||
|
} // namespace
|
||||||
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Humanoid/HumanoidState.h"
|
||||||
|
#include "V8World/Mechanism.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
class Assembly;
|
||||||
|
class PhysicsService;
|
||||||
|
|
||||||
|
namespace HUMAN {
|
||||||
|
|
||||||
|
extern const char* const sMovingNoPhysicsBase;
|
||||||
|
|
||||||
|
class MovingNoPhysicsBase
|
||||||
|
: public Named<HumanoidState, sMovingNoPhysicsBase>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef Named<HumanoidState, sMovingNoPhysicsBase> Super;
|
||||||
|
/*override*/ StateType getStateType() const {return RUNNING_NO_PHYS;}
|
||||||
|
/*override*/ void fireEvents();
|
||||||
|
|
||||||
|
shared_ptr<PartInstance> torsoPart;
|
||||||
|
weak_ptr<PhysicsService> physicsService;
|
||||||
|
|
||||||
|
rbx::signals::scoped_connection torsoAncestryChanged;
|
||||||
|
void onEvent_TorsoAncestryChanged();
|
||||||
|
void disconnectTorso();
|
||||||
|
|
||||||
|
const Assembly* getAssemblyConst() const;
|
||||||
|
|
||||||
|
void applyImpulseToFloor(float dt);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// Humanoid::State
|
||||||
|
/*override*/ void onSimulatorStepImpl(float stepDt);
|
||||||
|
/*override*/ void onComputeForceImpl();
|
||||||
|
|
||||||
|
/*override*/ bool armsShouldCollide() const {return false;}
|
||||||
|
/*override*/ bool legsShouldCollide() const {return false;}
|
||||||
|
/*override*/ bool headTorsoShouldCollide() const {return false;}
|
||||||
|
|
||||||
|
public:
|
||||||
|
MovingNoPhysicsBase(Humanoid* humanoid, StateType priorState);
|
||||||
|
~MovingNoPhysicsBase();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace HUMAN
|
||||||
|
} // namespace
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Humanoid/Balancing.h"
|
||||||
|
#include "Util/Name.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
namespace HUMAN {
|
||||||
|
|
||||||
|
// Flying occurs when there's no ground below you. You have the ability
|
||||||
|
// to turn around the y-axis, but not much else.
|
||||||
|
extern const char* const sRagdoll;
|
||||||
|
|
||||||
|
class Ragdoll : public Named<HumanoidState, sRagdoll>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef Named<HumanoidState, sRagdoll> Super;
|
||||||
|
/*override*/ StateType getStateType() const {return RAGDOLL;}
|
||||||
|
/*override*/ void onStepImpl();
|
||||||
|
/*override*/ void onComputeForceImpl() {}
|
||||||
|
/*override*/ bool enableAutoJump() const { return false; }
|
||||||
|
public:
|
||||||
|
Ragdoll(Humanoid* humanoid, StateType priorState);
|
||||||
|
~Ragdoll();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace HUMAN
|
||||||
|
} // namespace
|
||||||
|
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Humanoid/RunningBase.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
class Body;
|
||||||
|
|
||||||
|
namespace HUMAN {
|
||||||
|
|
||||||
|
extern const char* const sRunning;
|
||||||
|
extern const char* const sRunningSlave;
|
||||||
|
extern const char* const sLanded;
|
||||||
|
extern const char* const sClimbing;
|
||||||
|
|
||||||
|
|
||||||
|
class Running : public Named<RunningBase, sRunning>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef Named<RunningBase, sRunning> Super;
|
||||||
|
/*override*/ StateType getStateType() const {return RUNNING;}
|
||||||
|
/*override*/ void fireEvents();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*override*/ void onComputeForceImpl();
|
||||||
|
|
||||||
|
public:
|
||||||
|
Running(Humanoid* humanoid, StateType priorState);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Slave side only - stays running until some other change to respond to touch events correctly
|
||||||
|
class RunningSlave : public Named<Running, sRunningSlave>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RunningSlave(Humanoid* humanoid, StateType priorState);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Landed : public Named<RunningBase, sLanded>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*override*/ StateType getStateType() const {return LANDED;}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Landed(Humanoid* humanoid, StateType priorState);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Climbing : public Named<RunningBase, sClimbing>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef Named<RunningBase, sClimbing> Super;
|
||||||
|
/*override*/ StateType getStateType() const {return CLIMBING;}
|
||||||
|
/*override*/ void fireEvents();
|
||||||
|
/*override*/ int ladderCheckRate() { return 0; }
|
||||||
|
/*override*/ bool enableAutoJump() const { return false; }
|
||||||
|
public:
|
||||||
|
Climbing(Humanoid* humanoid, StateType priorState) : Named<RunningBase, sClimbing>(humanoid, priorState)
|
||||||
|
{}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace HUMAN
|
||||||
|
} // namespace RBX
|
||||||
|
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Humanoid/Balancing.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
class Body;
|
||||||
|
|
||||||
|
namespace HUMAN {
|
||||||
|
|
||||||
|
class RunningBase : public Balancing
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef Balancing Super;
|
||||||
|
protected:
|
||||||
|
Velocity floorVelocity;
|
||||||
|
|
||||||
|
// The following velocities are w.r.t the ground that the figure is walking on. The ground may be moving
|
||||||
|
Velocity desiredVelocity; // desired velocity in world coordinates relative to the floor's velocity
|
||||||
|
float desiredAltitude; // ignored if 0.0
|
||||||
|
|
||||||
|
void rotateWithGround(Body* body);
|
||||||
|
void hoverOnFloor(Body* body);
|
||||||
|
void move(Body* body);
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Humanoid::State
|
||||||
|
/*override*/ void onComputeForceImpl();
|
||||||
|
/*override*/ void onSimulatorStepImpl(float stepDt);
|
||||||
|
|
||||||
|
/*override*/ float getYAxisRotationalVelocity() const {return desiredVelocity.rotational.y;}
|
||||||
|
|
||||||
|
/*override*/ bool armsShouldCollide() const {return false;}
|
||||||
|
/*override*/ bool legsShouldCollide() const {return false;}
|
||||||
|
|
||||||
|
public:
|
||||||
|
RunningBase(Humanoid* humanoid, StateType priorState);
|
||||||
|
RunningBase(Humanoid* humanoid, StateType priorState, const float kP, const float kD);
|
||||||
|
|
||||||
|
/*override*/ void onCFrameChangedFromReflection();
|
||||||
|
|
||||||
|
static const float kTurnP() {return 7500.0f;}
|
||||||
|
static const float kTurnPForRotatePGS() {return 450.0f;}
|
||||||
|
static const float kTurnPForFreeFallPGS() {return 375.0f;}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace HUMAN
|
||||||
|
} // namespace RBX
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Humanoid/MovingNoPhysicsBase.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
class Clump;
|
||||||
|
|
||||||
|
namespace HUMAN {
|
||||||
|
|
||||||
|
extern const char* const sRunningNoPhysics;
|
||||||
|
|
||||||
|
class RunningNoPhysics
|
||||||
|
: public Named<MovingNoPhysicsBase, sRunningNoPhysics>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*override*/ StateType getStateType() const {return RUNNING_NO_PHYS;}
|
||||||
|
public:
|
||||||
|
RunningNoPhysics(Humanoid* humanoid, StateType priorState);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace HUMAN
|
||||||
|
} // namespace
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Humanoid/HumanoidState.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
namespace HUMAN {
|
||||||
|
|
||||||
|
extern const char *const sSeated;
|
||||||
|
|
||||||
|
class Seated : public Named<HumanoidState, sSeated>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*override*/ StateType getStateType() const {return SEATED;}
|
||||||
|
|
||||||
|
/*override*/ bool armsShouldCollide() const {return false;}
|
||||||
|
/*override*/ bool legsShouldCollide() const {return false;}
|
||||||
|
/*override*/ void onComputeForceImpl() {}
|
||||||
|
/*override*/ bool enableAutoJump() const { return false; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
Seated(Humanoid* humanoid, StateType priorState);
|
||||||
|
~Seated();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern const char* const sPlatformStanding;
|
||||||
|
|
||||||
|
class PlatformStanding : public Named<HumanoidState, sPlatformStanding>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*override*/ StateType getStateType() const {return PLATFORM_STANDING;}
|
||||||
|
|
||||||
|
/*override*/ bool armsShouldCollide() const {return false;}
|
||||||
|
/*override*/ bool legsShouldCollide() const {return false;}
|
||||||
|
/*override*/ void onComputeForceImpl() {}
|
||||||
|
/*override*/ bool enableAutoJump() const { return false; }
|
||||||
|
|
||||||
|
public:
|
||||||
|
PlatformStanding(Humanoid* humanoid, StateType priorState);
|
||||||
|
~PlatformStanding();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "V8DataModel/ModelInstance.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
extern const char* const sStatusInstance;
|
||||||
|
class StatusInstance
|
||||||
|
: public DescribedCreatable<StatusInstance, ModelInstance, sStatusInstance, Reflection::ClassDescriptor::INTERNAL>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef DescribedCreatable<StatusInstance, ModelInstance, sStatusInstance, Reflection::ClassDescriptor::INTERNAL> Super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
StatusInstance();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*override*/ bool askSetParent(const Instance* instance) const;
|
||||||
|
/*override*/ bool askForbidParent(const Instance* instance) const { return !askSetParent(instance); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Humanoid/MovingNoPhysicsBase.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
class Clump;
|
||||||
|
|
||||||
|
namespace HUMAN {
|
||||||
|
|
||||||
|
extern const char* const sStrafingNoPhysics;
|
||||||
|
|
||||||
|
class StrafingNoPhysics
|
||||||
|
: public Named<MovingNoPhysicsBase, sStrafingNoPhysics>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/*override*/ StateType getStateType() const {return STRAFING_NO_PHYS;}
|
||||||
|
public:
|
||||||
|
StrafingNoPhysics(Humanoid* humanoid, StateType priorState);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace HUMAN
|
||||||
|
} // namespace
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Humanoid/Balancing.h"
|
||||||
|
#include "Util/Name.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
namespace HUMAN {
|
||||||
|
|
||||||
|
extern const char* const sSwimming;
|
||||||
|
|
||||||
|
class Swimming : public Named<HumanoidState, sSwimming>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef Named<HumanoidState, sSwimming> Super;
|
||||||
|
Vector3 initialLinearVelocity;
|
||||||
|
static float velocityDecay();
|
||||||
|
|
||||||
|
/*override*/ StateType getStateType() const {return SWIMMING;}
|
||||||
|
/*override*/ void fireEvents();
|
||||||
|
/*override*/ bool enableAutoJump() const { return false; }
|
||||||
|
|
||||||
|
Velocity desiredVelocity;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Humanoid::State
|
||||||
|
/*override*/ void onComputeForceImpl();
|
||||||
|
/*override*/ void onSimulatorStepImpl(float stepDt);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Swimming(Humanoid* humanoid, StateType priorState);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static const float kTurnSpeed() {return 6.0f;} // note Humanoid autoTurnSpeed is 8.0f;
|
||||||
|
static const float kTurnAccelMax() {return 20000.0f * kTurnSpeed();}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace HUMAN
|
||||||
|
} // namespace
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ namespace RBX
|
|||||||
:Descriptor(name, Descriptor::Attributes())
|
:Descriptor(name, Descriptor::Attributes())
|
||||||
,tag(Name::lookup(name))
|
,tag(Name::lookup(name))
|
||||||
,isNumber(boost::is_arithmetic<T>::value)
|
,isNumber(boost::is_arithmetic<T>::value)
|
||||||
,isFloat(boost::is_floating_point<T>::value)
|
,isFloat(boost::is_float<T>::value)
|
||||||
,isEnum(false)
|
,isEnum(false)
|
||||||
{
|
{
|
||||||
*isOutdated = false;
|
*isOutdated = false;
|
||||||
@@ -71,7 +71,7 @@ namespace RBX
|
|||||||
:Descriptor(name, Descriptor::Attributes())
|
:Descriptor(name, Descriptor::Attributes())
|
||||||
,tag(Name::declare(tag))
|
,tag(Name::declare(tag))
|
||||||
,isNumber(boost::is_arithmetic<T>::value)
|
,isNumber(boost::is_arithmetic<T>::value)
|
||||||
,isFloat(boost::is_floating_point<T>::value)
|
,isFloat(boost::is_float<T>::value)
|
||||||
,isEnum(false)
|
,isEnum(false)
|
||||||
{
|
{
|
||||||
RBXASSERT(!this->tag.empty());
|
RBXASSERT(!this->tag.empty());
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ namespace RBX
|
|||||||
/*implement*/ void setValue(DescribedBase* object, const V& value) const
|
/*implement*/ void setValue(DescribedBase* object, const V& value) const
|
||||||
{
|
{
|
||||||
Class* c = boost::polymorphic_downcast<Class*>(object);
|
Class* c = boost::polymorphic_downcast<Class*>(object);
|
||||||
set(c, value);
|
(c->*set)(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,6 @@ public:
|
|||||||
rbx::signal<void(const std::string &)> screenshotReadySignal;
|
rbx::signal<void(const std::string &)> screenshotReadySignal;
|
||||||
rbx::signal<void(bool)> screenshotUploadSignal;
|
rbx::signal<void(bool)> screenshotUploadSignal;
|
||||||
|
|
||||||
|
|
||||||
rbx::signal<void(bool)> graphicsQualityShortcutSignal;
|
rbx::signal<void(bool)> graphicsQualityShortcutSignal;
|
||||||
|
|
||||||
rbx::signal<void()> allowedGearTypeChanged;
|
rbx::signal<void()> allowedGearTypeChanged;
|
||||||
@@ -227,8 +226,6 @@ private:
|
|||||||
|
|
||||||
bool networkStatsWindowsOn;
|
bool networkStatsWindowsOn;
|
||||||
|
|
||||||
bool isRobloxApp;
|
|
||||||
|
|
||||||
bool renderGuisActive;
|
bool renderGuisActive;
|
||||||
|
|
||||||
RBX::Game* game;
|
RBX::Game* game;
|
||||||
@@ -251,8 +248,6 @@ private:
|
|||||||
public:
|
public:
|
||||||
static bool BlockingDataModelShutdown;
|
static bool BlockingDataModelShutdown;
|
||||||
|
|
||||||
static bool isXboxApp;
|
|
||||||
|
|
||||||
static unsigned int perfStats; // another bitmask used to record detected hacks
|
static unsigned int perfStats; // another bitmask used to record detected hacks
|
||||||
|
|
||||||
std::string jobId;
|
std::string jobId;
|
||||||
@@ -384,9 +379,6 @@ public:
|
|||||||
bool isStudio() const { return runningInStudio; }
|
bool isStudio() const { return runningInStudio; }
|
||||||
void setIsStudio(bool runningInStudio);
|
void setIsStudio(bool runningInStudio);
|
||||||
|
|
||||||
bool getIsXboxApp() const { return isXboxApp; }
|
|
||||||
void setIsXboxApp(bool value);
|
|
||||||
|
|
||||||
bool isRunMode() const { return isStudioRunMode; }
|
bool isRunMode() const { return isStudioRunMode; }
|
||||||
void setIsRunMode(bool value);
|
void setIsRunMode(bool value);
|
||||||
|
|
||||||
@@ -499,8 +491,6 @@ public:
|
|||||||
void save(ContentId contentId);
|
void save(ContentId contentId);
|
||||||
static bool canSave(const RBX::Instance* instance);
|
static bool canSave(const RBX::Instance* instance);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool getRemoteBuildMode();
|
bool getRemoteBuildMode();
|
||||||
void setRemoteBuildMode(bool remoteBuildMode);
|
void setRemoteBuildMode(bool remoteBuildMode);
|
||||||
|
|
||||||
|
|||||||
@@ -5,33 +5,37 @@
|
|||||||
|
|
||||||
namespace RBX
|
namespace RBX
|
||||||
{
|
{
|
||||||
extern const char *const sGameBasicSettings;
|
extern const char* const sGameBasicSettings;
|
||||||
class GameBasicSettings
|
class GameBasicSettings
|
||||||
: public GlobalBasicSettingsItem<GameBasicSettings, sGameBasicSettings>
|
: public GlobalBasicSettingsItem<GameBasicSettings, sGameBasicSettings>
|
||||||
{
|
{
|
||||||
typedef GlobalBasicSettingsItem<GameBasicSettings, sGameBasicSettings> Super;
|
typedef GlobalBasicSettingsItem<GameBasicSettings, sGameBasicSettings> Super;
|
||||||
public:
|
public:
|
||||||
enum ControlMode {CONTROL_CLASSIC = 0, CONTROL_MOUSELOCK = 1, CONTROL_HYBRID = 2, CONTROL_CAMLOCK = 3, CONTROL_MOUSEPAN = 4};
|
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 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 CameraMode { CAMERA_MODE_DEFAULT = 0, CAMERA_MODE_CLASSIC = 1, CAMERA_MODE_FOLLOW = 2 };
|
||||||
enum TouchCameraMovementMode {
|
enum TouchCameraMovementMode {
|
||||||
TOUCH_CAMERA_MOVEMENT_MODE_DEFAULT = 0,
|
TOUCH_CAMERA_MOVEMENT_MODE_DEFAULT = 0,
|
||||||
TOUCH_CAMERA_MOVEMENT_MODE_CLASSIC = 1,
|
TOUCH_CAMERA_MOVEMENT_MODE_CLASSIC = 1,
|
||||||
TOUCH_CAMERA_MOVEMENT_MODE_FOLLOW = 2 };
|
TOUCH_CAMERA_MOVEMENT_MODE_FOLLOW = 2
|
||||||
|
};
|
||||||
enum ComputerCameraMovementMode {
|
enum ComputerCameraMovementMode {
|
||||||
COMPUTER_CAMERA_MOVEMENT_MODE_DEFAULT = 0,
|
COMPUTER_CAMERA_MOVEMENT_MODE_DEFAULT = 0,
|
||||||
COMPUTER_CAMERA_MOVEMENT_MODE_CLASSIC = 1,
|
COMPUTER_CAMERA_MOVEMENT_MODE_CLASSIC = 1,
|
||||||
COMPUTER_CAMERA_MOVEMENT_MODE_FOLLOW = 2};
|
COMPUTER_CAMERA_MOVEMENT_MODE_FOLLOW = 2
|
||||||
|
};
|
||||||
enum TouchMovementMode {
|
enum TouchMovementMode {
|
||||||
TOUCH_MOVEMENT_MODE_DEFAULT = 0,
|
TOUCH_MOVEMENT_MODE_DEFAULT = 0,
|
||||||
TOUCH_MOVEMENT_MODE_THUMBSTICK = 1,
|
TOUCH_MOVEMENT_MODE_THUMBSTICK = 1,
|
||||||
TOUCH_MOVEMENT_MODE_DPAD = 2,
|
TOUCH_MOVEMENT_MODE_DPAD = 2,
|
||||||
TOUCH_MOVEMENT_MODE_THUMBPAD = 3,
|
TOUCH_MOVEMENT_MODE_THUMBPAD = 3,
|
||||||
TOUCH_MOVEMENT_MODE_CLICK_TO_MOVE = 4 };
|
TOUCH_MOVEMENT_MODE_CLICK_TO_MOVE = 4
|
||||||
|
};
|
||||||
enum ComputerMovementMode {
|
enum ComputerMovementMode {
|
||||||
COMPUTER_MOVEMENT_MODE_DEFAULT = 0,
|
COMPUTER_MOVEMENT_MODE_DEFAULT = 0,
|
||||||
COMPUTER_MOVEMENT_MODE_KBD_MOUSE = 1,
|
COMPUTER_MOVEMENT_MODE_KBD_MOUSE = 1,
|
||||||
COMPUTER_MOVEMENT_MODE_CLICK_TO_MOVE = 2};
|
COMPUTER_MOVEMENT_MODE_CLICK_TO_MOVE = 2
|
||||||
|
};
|
||||||
enum YearSettings {
|
enum YearSettings {
|
||||||
Year2016 = 0,
|
Year2016 = 0,
|
||||||
Year2015 = 1,
|
Year2015 = 1,
|
||||||
@@ -40,7 +44,8 @@ namespace RBX
|
|||||||
};
|
};
|
||||||
enum RotationType {
|
enum RotationType {
|
||||||
ROTATION_TYPE_MOVEMENT_RELATIVE = 0,
|
ROTATION_TYPE_MOVEMENT_RELATIVE = 0,
|
||||||
ROTATION_TYPE_CAMERA_RELATIVE = 1};
|
ROTATION_TYPE_CAMERA_RELATIVE = 1
|
||||||
|
};
|
||||||
|
|
||||||
static Reflection::PropDescriptor<GameBasicSettings, float> prop_masterVolume;
|
static Reflection::PropDescriptor<GameBasicSettings, float> prop_masterVolume;
|
||||||
|
|
||||||
@@ -120,7 +125,7 @@ namespace RBX
|
|||||||
bool getFullScreen() { return fullscreen; }
|
bool getFullScreen() { return fullscreen; }
|
||||||
void setFullScreen(bool value)
|
void setFullScreen(bool value)
|
||||||
{
|
{
|
||||||
if(value != fullscreen)
|
if (value != fullscreen)
|
||||||
{
|
{
|
||||||
fullscreen = value;
|
fullscreen = value;
|
||||||
fullscreenChangedSignal(value);
|
fullscreenChangedSignal(value);
|
||||||
@@ -145,7 +150,7 @@ namespace RBX
|
|||||||
bool inStudioMode() { return studio; }
|
bool inStudioMode() { return studio; }
|
||||||
void setStudioMode(bool value)
|
void setStudioMode(bool value)
|
||||||
{
|
{
|
||||||
if(value != studio)
|
if (value != studio)
|
||||||
{
|
{
|
||||||
studioModeChangedSignal(value);
|
studioModeChangedSignal(value);
|
||||||
studio = value;
|
studio = value;
|
||||||
|
|||||||
@@ -0,0 +1,264 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Lua.hpp"
|
||||||
|
|
||||||
|
#include "util/exception.h"
|
||||||
|
#include "util/utilities.h"
|
||||||
|
#include "rbx/Debug.h"
|
||||||
|
#include "rbx/atomic.h"
|
||||||
|
|
||||||
|
namespace RBX { namespace Lua {
|
||||||
|
|
||||||
|
void newweaktable(lua_State *L, const char *mode);
|
||||||
|
|
||||||
|
template<class C, int (C::*Func)(lua_State*)>
|
||||||
|
int memberFunctionProxy(lua_State* thread)
|
||||||
|
{
|
||||||
|
C* c = reinterpret_cast<C*>(lua_touserdata(thread, lua_upvalueindex(1)));
|
||||||
|
return (c->*Func)(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class C, int (C::*Func)(lua_State*)>
|
||||||
|
void pushMemberFunction(lua_State* L, C* c)
|
||||||
|
{
|
||||||
|
lua_pushlightuserdata(L, (void*)c);
|
||||||
|
lua_pushcclosure(L, &memberFunctionProxy<C, Func>, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Use traits pattern rather than bool __eq
|
||||||
|
template<class Class, bool __eq = true>
|
||||||
|
class Bridge
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// 0 arg constructor
|
||||||
|
static Class* pushNewObject(lua_State *L)
|
||||||
|
{
|
||||||
|
Class* data = (Class*)lua_newuserdata(L, sizeof(Class));
|
||||||
|
new(data) Class;
|
||||||
|
luaL_getmetatable(L, className);
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
// 1 arg constructor
|
||||||
|
template<typename Param1>
|
||||||
|
static Class* pushNewObject(lua_State *L, Param1 param1)
|
||||||
|
{
|
||||||
|
Class* data = (Class*)lua_newuserdata(L, sizeof(Class));
|
||||||
|
new(data) Class(param1);
|
||||||
|
luaL_getmetatable(L, className);
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
// 2 arg constructor
|
||||||
|
template<typename Param1, typename Param2>
|
||||||
|
static Class* pushNewObject(lua_State *L, Param1 param1, Param2 param2)
|
||||||
|
{
|
||||||
|
Class* data = (Class*)lua_newuserdata(L, sizeof(Class));
|
||||||
|
new(data) Class(param1, param2);
|
||||||
|
luaL_getmetatable(L, className);
|
||||||
|
lua_setmetatable(L, -2);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throws an exception if index doesn't hold the right type
|
||||||
|
static Class& getObject(lua_State *L, unsigned int index) {
|
||||||
|
void *ud = luaL_checkudata(L, index, className);
|
||||||
|
return *reinterpret_cast<Class*>(ud);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns false if index doesn't hold the right type (leaving value unchanged)
|
||||||
|
template<typename V>
|
||||||
|
static bool getValue(lua_State *L, unsigned int index, V& value) {
|
||||||
|
|
||||||
|
// A re-implementation of luaL_checkudata that doesn't throw an exception
|
||||||
|
void *p = lua_touserdata(L, index);
|
||||||
|
if (p != NULL) { /* value is a userdata? */
|
||||||
|
if (lua_getmetatable(L, index)) { /* does it have a metatable? */
|
||||||
|
lua_getfield(L, LUA_REGISTRYINDEX, className); /* get correct metatable */
|
||||||
|
if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */
|
||||||
|
lua_pop(L, 2); /* remove both metatables */
|
||||||
|
value = *reinterpret_cast<Class*>(p);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
lua_pop(L, 2); /* remove both metatables */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void registerClass (lua_State *L);
|
||||||
|
|
||||||
|
/// gcc craps out with the error while it is called from ScriptContext.cpp for registerClass fns for the Bridge e.g EventBridge::registerClass(globalState);
|
||||||
|
// error: 'static int RBX::Lua::Bridge<Class, __eq>::on_index(lua_State*) [with Class = RBX::Lua::EventInstance, bool __eq = true]' is protected
|
||||||
|
#ifdef _WIN32
|
||||||
|
protected:
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The following members must be implemented by client:
|
||||||
|
static int on_index(const Class& object, const char* name, lua_State *L);
|
||||||
|
static void on_newindex(Class& object, const char* name, lua_State *L);
|
||||||
|
|
||||||
|
// This member may be specialized when StringConverter has no implementation for Class:
|
||||||
|
static int on_tostring(const Class& object, lua_State *L);
|
||||||
|
|
||||||
|
static const char* className;
|
||||||
|
|
||||||
|
static int on_gc(lua_State *L) {
|
||||||
|
getObject(L, 1).~Class();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int on_tostring(lua_State *L) {
|
||||||
|
return on_tostring(getObject(L, 1), L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int on_newindex(lua_State *L) {
|
||||||
|
const char* name = lua_checkstring_secure(L, 2);
|
||||||
|
on_newindex(getObject(L, 1), name, L);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int on_index(lua_State *L) {
|
||||||
|
const char* name = lua_checkstring_secure(L, 2);
|
||||||
|
return on_index(getObject(L, 1), name, L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int on_eq(lua_State *L) {
|
||||||
|
lua_pushboolean(L, getObject(L, 1) == getObject(L, 2));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This class hides parent on purpose
|
||||||
|
template<class Class>
|
||||||
|
class SharedPtrBridge : protected Bridge<boost::shared_ptr<Class>, false>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void registerClass (lua_State *L)
|
||||||
|
{
|
||||||
|
Bridge<boost::shared_ptr<Class>, false>::registerClass(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void registerClassLibrary (lua_State *L) {
|
||||||
|
// Declare the UserData re-use table
|
||||||
|
lua_pushlightuserdata(L, (void*)&push);
|
||||||
|
newweaktable(L, "v");
|
||||||
|
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void push(lua_State *L, boost::shared_ptr<Class> instance)
|
||||||
|
{
|
||||||
|
if (instance==NULL)
|
||||||
|
lua_pushnil(L);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
int i = lua_gettop(L);
|
||||||
|
#endif
|
||||||
|
// Matt Campbell at Serotek Corporation had a great idea. Create only
|
||||||
|
// a single instance of the userdata and re-use it. This way the userdata
|
||||||
|
// can be used in table keys, and we don't need an __eq operator
|
||||||
|
// Also see http://lua-users.org/lists/lua-l/2004-07/msg00391.html
|
||||||
|
|
||||||
|
lua_pushlightuserdata(L, (void*)&push ); /* Registry mapping for weak table. Key is arbitrary. */
|
||||||
|
lua_rawget(L, LUA_REGISTRYINDEX); // Stack: t
|
||||||
|
RBXASSERT(!lua_isnil( L, -1 )); // Did you forget to call registerClassLibrary??
|
||||||
|
|
||||||
|
// Now the top of the stack is our lookup table
|
||||||
|
// See if we already have a UserData for this instance
|
||||||
|
lua_pushlightuserdata (L, (void*)instance.get()); // Stack: t, i
|
||||||
|
lua_rawget (L, -2); // Stack: t, t[i]
|
||||||
|
|
||||||
|
if( lua_isnil( L, -1 ) ) { // Stack: t, nil or I
|
||||||
|
lua_pop (L, 1); // Stack: t
|
||||||
|
Bridge<boost::shared_ptr<Class>, false>::pushNewObject(L, instance); // Stack: t, I
|
||||||
|
/* store the value for later use */
|
||||||
|
lua_pushlightuserdata (L, (void*)instance.get()); // Stack: t, I, i
|
||||||
|
lua_pushvalue (L, -2); // Stack: t, I, i, I
|
||||||
|
lua_rawset (L, -4); // Stack: t, I
|
||||||
|
}
|
||||||
|
lua_remove (L, -2); // Stack: I
|
||||||
|
#ifdef _DEBUG
|
||||||
|
RBXASSERT(lua_gettop(L) == i + 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static boost::shared_ptr<Class> getPtr(lua_State *L, unsigned int index)
|
||||||
|
{
|
||||||
|
if (lua_isnil(L, index))
|
||||||
|
return boost::shared_ptr<Class>();
|
||||||
|
else
|
||||||
|
return RBX::Lua::Bridge<boost::shared_ptr<Class>, false>::getObject(L, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename V>
|
||||||
|
static bool getPtr(lua_State *L, unsigned int index, V& value) {
|
||||||
|
if (lua_isnil(L, index))
|
||||||
|
{
|
||||||
|
value = boost::shared_ptr<Class>();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return Bridge<boost::shared_ptr<Class>, false>::getValue(L, index, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// This class hides Bridge on purpose
|
||||||
|
template<class T>
|
||||||
|
class SingletonBridge : protected Bridge<T, false>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void registerClass (lua_State *L) {
|
||||||
|
Bridge<T, false>::registerClass(L);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void registerClassLibrary (lua_State *L) {
|
||||||
|
// Declare the UserData re-use table
|
||||||
|
lua_pushlightuserdata(L, (void*)&push);
|
||||||
|
lua_newtable(L); // Not a weak table, unlike SharedPtrBridge
|
||||||
|
lua_rawset(L, LUA_REGISTRYINDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void push(lua_State *L, T item)
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
int i = lua_gettop(L);
|
||||||
|
#endif
|
||||||
|
// Matt Campbell at Serotek Corporation had a great idea. Create only
|
||||||
|
// a single instance of the userdata and re-use it. This way the userdata
|
||||||
|
// can be used in table keys
|
||||||
|
// Also see http://lua-users.org/lists/lua-l/2004-07/msg00391.html
|
||||||
|
|
||||||
|
lua_pushlightuserdata(L, (void*)&push); /* Registry mapping for table. Key is arbitrary. */
|
||||||
|
lua_rawget(L, LUA_REGISTRYINDEX); // Stack: t
|
||||||
|
RBXASSERT(!lua_isnil( L, -1 )); // Did you forget to call registerClassLibrary??
|
||||||
|
|
||||||
|
// Now the top of the stack is our lookup table
|
||||||
|
// See if we already have a UserData for this instance
|
||||||
|
lua_pushlightuserdata (L, (void*)item); // Stack: t, i
|
||||||
|
lua_rawget (L, -2); // Stack: t, t[i]
|
||||||
|
|
||||||
|
// TODO: only allow explicit, one-time declaration
|
||||||
|
if( lua_isnil( L, -1 ) ) { // Stack: t, nil or I
|
||||||
|
lua_pop (L, 1); // Stack: t
|
||||||
|
Bridge<T, false>::pushNewObject(L, item); // Stack: t, I
|
||||||
|
/* store the value for later use */
|
||||||
|
lua_pushlightuserdata (L, (void*)item); // Stack: t, I, i
|
||||||
|
lua_pushvalue (L, -2); // Stack: t, I, i, I
|
||||||
|
lua_rawset (L, -4); // Stack: t, I
|
||||||
|
}
|
||||||
|
lua_remove (L, -2); // Stack: I
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
RBXASSERT(lua_gettop(L) == i + 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "lua.h"
|
||||||
|
#include "lauxlib.h"
|
||||||
|
#include "lualib.h"
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
namespace Lua
|
||||||
|
{
|
||||||
|
extern const char* safe_lua_tostring(lua_State *L, int idx);
|
||||||
|
extern const char* throwable_lua_tostring(lua_State *L, int idx);
|
||||||
|
extern float lua_tofloat(lua_State *L, int idx);
|
||||||
|
extern void protect_metatable(lua_State* thread, int index);
|
||||||
|
inline void lua_pushstring(lua_State* thread, const std::string& s)
|
||||||
|
{
|
||||||
|
lua_pushlstring(thread, s.c_str(), s.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* lua_checkstring_secure(lua_State* L, int idx);
|
||||||
|
|
||||||
|
void lua_resetstack(lua_State* L, int idx);
|
||||||
|
|
||||||
|
// Pops items from the stack when it goes out of scope
|
||||||
|
class ScopedPopper
|
||||||
|
{
|
||||||
|
int popCount;
|
||||||
|
lua_State* const thread;
|
||||||
|
public:
|
||||||
|
ScopedPopper(lua_State* thread, int popCount)
|
||||||
|
:thread(thread),popCount(popCount)
|
||||||
|
{}
|
||||||
|
|
||||||
|
ScopedPopper& operator +=(int popCount)
|
||||||
|
{
|
||||||
|
this->popCount += popCount;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
ScopedPopper& operator -=(int popCount)
|
||||||
|
{
|
||||||
|
this->popCount -= popCount;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ScopedPopper()
|
||||||
|
{
|
||||||
|
lua_pop(thread, popCount);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScopedState
|
||||||
|
{
|
||||||
|
lua_State* const thread;
|
||||||
|
public:
|
||||||
|
ScopedState()
|
||||||
|
:thread(luaL_newstate())
|
||||||
|
{}
|
||||||
|
|
||||||
|
~ScopedState()
|
||||||
|
{
|
||||||
|
lua_close(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
operator lua_State*()
|
||||||
|
{
|
||||||
|
return thread;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
|
||||||
|
RBX::Lua::LuaStubGen<609> stub609;
|
||||||
|
RBX::Lua::LuaStubGen<288> stub288;
|
||||||
|
RBX::Lua::LuaStubGen<646> stub646;
|
||||||
|
RBX::Lua::LuaStubGen<387> stub387;
|
||||||
|
RBX::Lua::LuaStubGen<649> stub649;
|
||||||
|
RBX::Lua::LuaStubGen<687> stub687;
|
||||||
|
RBX::Lua::LuaStubGen<836> stub836;
|
||||||
|
RBX::Lua::LuaStubGen<959> stub959;
|
||||||
|
RBX::Lua::LuaStubGen<803> stub803;
|
||||||
|
RBX::Lua::LuaStubGen<107> stub107;
|
||||||
|
RBX::Lua::LuaStubGen<361> stub361;
|
||||||
|
RBX::Lua::LuaStubGen<172> stub172;
|
||||||
|
RBX::Lua::LuaStubGen<666> stub666;
|
||||||
|
RBX::Lua::LuaStubGen<901> stub901;
|
||||||
|
RBX::Lua::LuaStubGen<287> stub287;
|
||||||
|
RBX::Lua::LuaStubGen<523> stub523;
|
||||||
|
RBX::Lua::LuaStubGen<701> stub701;
|
||||||
|
RBX::Lua::LuaStubGen<316> stub316;
|
||||||
|
RBX::Lua::LuaStubGen<671> stub671;
|
||||||
|
RBX::Lua::LuaStubGen<423> stub423;
|
||||||
|
RBX::Lua::LuaStubGen<718> stub718;
|
||||||
|
RBX::Lua::LuaStubGen<711> stub711;
|
||||||
|
RBX::Lua::LuaStubGen<211> stub211;
|
||||||
|
RBX::Lua::LuaStubGen<158> stub158;
|
||||||
|
RBX::Lua::LuaStubGen<219> stub219;
|
||||||
|
RBX::Lua::LuaStubGen<68> stub68;
|
||||||
|
RBX::Lua::LuaStubGen<790> stub790;
|
||||||
|
RBX::Lua::LuaStubGen<58> stub58;
|
||||||
|
RBX::Lua::LuaStubGen<919> stub919;
|
||||||
|
RBX::Lua::LuaStubGen<747> stub747;
|
||||||
|
RBX::Lua::LuaStubGen<161> stub161;
|
||||||
|
RBX::Lua::LuaStubGen<119> stub119;
|
||||||
|
RBX::Lua::LuaStubGen<622> stub622;
|
||||||
|
RBX::Lua::LuaStubGen<183> stub183;
|
||||||
|
RBX::Lua::LuaStubGen<93> stub93;
|
||||||
|
RBX::Lua::LuaStubGen<560> stub560;
|
||||||
|
RBX::Lua::LuaStubGen<382> stub382;
|
||||||
|
RBX::Lua::LuaStubGen<455> stub455;
|
||||||
|
RBX::Lua::LuaStubGen<562> stub562;
|
||||||
|
RBX::Lua::LuaStubGen<554> stub554;
|
||||||
|
RBX::Lua::LuaStubGen<652> stub652;
|
||||||
|
RBX::Lua::LuaStubGen<997> stub997;
|
||||||
|
RBX::Lua::LuaStubGen<237> stub237;
|
||||||
|
RBX::Lua::LuaStubGen<655> stub655;
|
||||||
|
RBX::Lua::LuaStubGen<892> stub892;
|
||||||
|
RBX::Lua::LuaStubGen<840> stub840;
|
||||||
|
RBX::Lua::LuaStubGen<872> stub872;
|
||||||
|
RBX::Lua::LuaStubGen<821> stub821;
|
||||||
|
RBX::Lua::LuaStubGen<314> stub314;
|
||||||
|
RBX::Lua::LuaStubGen<249> stub249;
|
||||||
|
RBX::Lua::LuaStubGen<82> stub82;
|
||||||
|
RBX::Lua::LuaStubGen<470> stub470;
|
||||||
|
RBX::Lua::LuaStubGen<203> stub203;
|
||||||
|
RBX::Lua::LuaStubGen<722> stub722;
|
||||||
|
RBX::Lua::LuaStubGen<492> stub492;
|
||||||
|
RBX::Lua::LuaStubGen<29> stub29;
|
||||||
|
RBX::Lua::LuaStubGen<429> stub429;
|
||||||
|
RBX::Lua::LuaStubGen<933> stub933;
|
||||||
|
RBX::Lua::LuaStubGen<983> stub983;
|
||||||
|
RBX::Lua::LuaStubGen<700> stub700;
|
||||||
|
RBX::Lua::LuaStubGen<471> stub471;
|
||||||
|
RBX::Lua::LuaStubGen<453> stub453;
|
||||||
|
RBX::Lua::LuaStubGen<396> stub396;
|
||||||
|
RBX::Lua::LuaStubGen<330> stub330;
|
||||||
|
RBX::Lua::LuaStubGen<206> stub206;
|
||||||
|
RBX::Lua::LuaStubGen<362> stub362;
|
||||||
|
RBX::Lua::LuaStubGen<737> stub737;
|
||||||
|
RBX::Lua::LuaStubGen<390> stub390;
|
||||||
|
RBX::Lua::LuaStubGen<914> stub914;
|
||||||
|
RBX::Lua::LuaStubGen<985> stub985;
|
||||||
|
RBX::Lua::LuaStubGen<490> stub490;
|
||||||
|
RBX::Lua::LuaStubGen<786> stub786;
|
||||||
|
RBX::Lua::LuaStubGen<173> stub173;
|
||||||
|
RBX::Lua::LuaStubGen<346> stub346;
|
||||||
|
RBX::Lua::LuaStubGen<643> stub643;
|
||||||
|
RBX::Lua::LuaStubGen<331> stub331;
|
||||||
|
RBX::Lua::LuaStubGen<539> stub539;
|
||||||
|
RBX::Lua::LuaStubGen<134> stub134;
|
||||||
|
RBX::Lua::LuaStubGen<325> stub325;
|
||||||
|
RBX::Lua::LuaStubGen<34> stub34;
|
||||||
|
RBX::Lua::LuaStubGen<88> stub88;
|
||||||
|
RBX::Lua::LuaStubGen<536> stub536;
|
||||||
|
RBX::Lua::LuaStubGen<79> stub79;
|
||||||
|
RBX::Lua::LuaStubGen<459> stub459;
|
||||||
|
RBX::Lua::LuaStubGen<842> stub842;
|
||||||
|
RBX::Lua::LuaStubGen<370> stub370;
|
||||||
|
RBX::Lua::LuaStubGen<553> stub553;
|
||||||
|
RBX::Lua::LuaStubGen<486> stub486;
|
||||||
|
RBX::Lua::LuaStubGen<591> stub591;
|
||||||
|
RBX::Lua::LuaStubGen<797> stub797;
|
||||||
|
RBX::Lua::LuaStubGen<571> stub571;
|
||||||
|
RBX::Lua::LuaStubGen<907> stub907;
|
||||||
|
RBX::Lua::LuaStubGen<43> stub43;
|
||||||
|
RBX::Lua::LuaStubGen<918> stub918;
|
||||||
|
RBX::Lua::LuaStubGen<866> stub866;
|
||||||
|
RBX::Lua::LuaStubGen<856> stub856;
|
||||||
|
RBX::Lua::LuaStubGen<751> stub751;
|
||||||
|
RBX::Lua::LuaStubGen<124> stub124;
|
||||||
|
RBX::Lua::LuaStubGen<559> stub559;
|
||||||
|
RBX::Lua::LuaStubGen<620> stub620;
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
|
||||||
|
RBX::Lua::LuaStubGen<339> stub339;
|
||||||
|
RBX::Lua::LuaStubGen<510> stub510;
|
||||||
|
RBX::Lua::LuaStubGen<634> stub634;
|
||||||
|
RBX::Lua::LuaStubGen<17> stub17;
|
||||||
|
RBX::Lua::LuaStubGen<302> stub302;
|
||||||
|
RBX::Lua::LuaStubGen<454> stub454;
|
||||||
|
RBX::Lua::LuaStubGen<814> stub814;
|
||||||
|
RBX::Lua::LuaStubGen<887> stub887;
|
||||||
|
RBX::Lua::LuaStubGen<824> stub824;
|
||||||
|
RBX::Lua::LuaStubGen<703> stub703;
|
||||||
|
RBX::Lua::LuaStubGen<932> stub932;
|
||||||
|
RBX::Lua::LuaStubGen<220> stub220;
|
||||||
|
RBX::Lua::LuaStubGen<972> stub972;
|
||||||
|
RBX::Lua::LuaStubGen<99> stub99;
|
||||||
|
RBX::Lua::LuaStubGen<627> stub627;
|
||||||
|
RBX::Lua::LuaStubGen<13> stub13;
|
||||||
|
RBX::Lua::LuaStubGen<633> stub633;
|
||||||
|
RBX::Lua::LuaStubGen<800> stub800;
|
||||||
|
RBX::Lua::LuaStubGen<875> stub875;
|
||||||
|
RBX::Lua::LuaStubGen<458> stub458;
|
||||||
|
RBX::Lua::LuaStubGen<181> stub181;
|
||||||
|
RBX::Lua::LuaStubGen<352> stub352;
|
||||||
|
RBX::Lua::LuaStubGen<920> stub920;
|
||||||
|
RBX::Lua::LuaStubGen<951> stub951;
|
||||||
|
RBX::Lua::LuaStubGen<319> stub319;
|
||||||
|
RBX::Lua::LuaStubGen<716> stub716;
|
||||||
|
RBX::Lua::LuaStubGen<529> stub529;
|
||||||
|
RBX::Lua::LuaStubGen<507> stub507;
|
||||||
|
RBX::Lua::LuaStubGen<85> stub85;
|
||||||
|
RBX::Lua::LuaStubGen<105> stub105;
|
||||||
|
RBX::Lua::LuaStubGen<727> stub727;
|
||||||
|
RBX::Lua::LuaStubGen<568> stub568;
|
||||||
|
RBX::Lua::LuaStubGen<749> stub749;
|
||||||
|
RBX::Lua::LuaStubGen<530> stub530;
|
||||||
|
RBX::Lua::LuaStubGen<207> stub207;
|
||||||
|
RBX::Lua::LuaStubGen<5> stub5;
|
||||||
|
RBX::Lua::LuaStubGen<413> stub413;
|
||||||
|
RBX::Lua::LuaStubGen<675> stub675;
|
||||||
|
RBX::Lua::LuaStubGen<462> stub462;
|
||||||
|
RBX::Lua::LuaStubGen<762> stub762;
|
||||||
|
RBX::Lua::LuaStubGen<397> stub397;
|
||||||
|
RBX::Lua::LuaStubGen<431> stub431;
|
||||||
|
RBX::Lua::LuaStubGen<47> stub47;
|
||||||
|
RBX::Lua::LuaStubGen<307> stub307;
|
||||||
|
RBX::Lua::LuaStubGen<692> stub692;
|
||||||
|
RBX::Lua::LuaStubGen<320> stub320;
|
||||||
|
RBX::Lua::LuaStubGen<947> stub947;
|
||||||
|
RBX::Lua::LuaStubGen<775> stub775;
|
||||||
|
RBX::Lua::LuaStubGen<647> stub647;
|
||||||
|
RBX::Lua::LuaStubGen<766> stub766;
|
||||||
|
RBX::Lua::LuaStubGen<661> stub661;
|
||||||
|
RBX::Lua::LuaStubGen<384> stub384;
|
||||||
|
RBX::Lua::LuaStubGen<235> stub235;
|
||||||
|
RBX::Lua::LuaStubGen<177> stub177;
|
||||||
|
RBX::Lua::LuaStubGen<535> stub535;
|
||||||
|
RBX::Lua::LuaStubGen<580> stub580;
|
||||||
|
RBX::Lua::LuaStubGen<854> stub854;
|
||||||
|
RBX::Lua::LuaStubGen<987> stub987;
|
||||||
|
RBX::Lua::LuaStubGen<891> stub891;
|
||||||
|
RBX::Lua::LuaStubGen<846> stub846;
|
||||||
|
RBX::Lua::LuaStubGen<630> stub630;
|
||||||
|
RBX::Lua::LuaStubGen<491> stub491;
|
||||||
|
RBX::Lua::LuaStubGen<573> stub573;
|
||||||
|
RBX::Lua::LuaStubGen<488> stub488;
|
||||||
|
RBX::Lua::LuaStubGen<695> stub695;
|
||||||
|
RBX::Lua::LuaStubGen<995> stub995;
|
||||||
|
RBX::Lua::LuaStubGen<321> stub321;
|
||||||
|
RBX::Lua::LuaStubGen<322> stub322;
|
||||||
|
RBX::Lua::LuaStubGen<504> stub504;
|
||||||
|
RBX::Lua::LuaStubGen<403> stub403;
|
||||||
|
RBX::Lua::LuaStubGen<197> stub197;
|
||||||
|
RBX::Lua::LuaStubGen<487> stub487;
|
||||||
|
RBX::Lua::LuaStubGen<231> stub231;
|
||||||
|
RBX::Lua::LuaStubGen<236> stub236;
|
||||||
|
RBX::Lua::LuaStubGen<128> stub128;
|
||||||
|
RBX::Lua::LuaStubGen<381> stub381;
|
||||||
|
RBX::Lua::LuaStubGen<705> stub705;
|
||||||
|
RBX::Lua::LuaStubGen<61> stub61;
|
||||||
|
RBX::Lua::LuaStubGen<214> stub214;
|
||||||
|
RBX::Lua::LuaStubGen<497> stub497;
|
||||||
|
RBX::Lua::LuaStubGen<232> stub232;
|
||||||
|
RBX::Lua::LuaStubGen<725> stub725;
|
||||||
|
RBX::Lua::LuaStubGen<371> stub371;
|
||||||
|
RBX::Lua::LuaStubGen<401> stub401;
|
||||||
|
RBX::Lua::LuaStubGen<526> stub526;
|
||||||
|
RBX::Lua::LuaStubGen<448> stub448;
|
||||||
|
RBX::Lua::LuaStubGen<961> stub961;
|
||||||
|
RBX::Lua::LuaStubGen<97> stub97;
|
||||||
|
RBX::Lua::LuaStubGen<375> stub375;
|
||||||
|
RBX::Lua::LuaStubGen<979> stub979;
|
||||||
|
RBX::Lua::LuaStubGen<908> stub908;
|
||||||
|
RBX::Lua::LuaStubGen<227> stub227;
|
||||||
|
RBX::Lua::LuaStubGen<112> stub112;
|
||||||
|
RBX::Lua::LuaStubGen<819> stub819;
|
||||||
|
RBX::Lua::LuaStubGen<208> stub208;
|
||||||
|
RBX::Lua::LuaStubGen<78> stub78;
|
||||||
|
RBX::Lua::LuaStubGen<992> stub992;
|
||||||
|
RBX::Lua::LuaStubGen<209> stub209;
|
||||||
|
RBX::Lua::LuaStubGen<881> stub881;
|
||||||
|
RBX::Lua::LuaStubGen<463> stub463;
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
|
||||||
|
RBX::Lua::LuaStubGen<925> stub925;
|
||||||
|
RBX::Lua::LuaStubGen<311> stub311;
|
||||||
|
RBX::Lua::LuaStubGen<801> stub801;
|
||||||
|
RBX::Lua::LuaStubGen<450> stub450;
|
||||||
|
RBX::Lua::LuaStubGen<469> stub469;
|
||||||
|
RBX::Lua::LuaStubGen<522> stub522;
|
||||||
|
RBX::Lua::LuaStubGen<412> stub412;
|
||||||
|
RBX::Lua::LuaStubGen<418> stub418;
|
||||||
|
RBX::Lua::LuaStubGen<879> stub879;
|
||||||
|
RBX::Lua::LuaStubGen<745> stub745;
|
||||||
|
RBX::Lua::LuaStubGen<818> stub818;
|
||||||
|
RBX::Lua::LuaStubGen<69> stub69;
|
||||||
|
RBX::Lua::LuaStubGen<122> stub122;
|
||||||
|
RBX::Lua::LuaStubGen<654> stub654;
|
||||||
|
RBX::Lua::LuaStubGen<385> stub385;
|
||||||
|
RBX::Lua::LuaStubGen<160> stub160;
|
||||||
|
RBX::Lua::LuaStubGen<550> stub550;
|
||||||
|
RBX::Lua::LuaStubGen<199> stub199;
|
||||||
|
RBX::Lua::LuaStubGen<897> stub897;
|
||||||
|
RBX::Lua::LuaStubGen<60> stub60;
|
||||||
|
RBX::Lua::LuaStubGen<420> stub420;
|
||||||
|
RBX::Lua::LuaStubGen<712> stub712;
|
||||||
|
RBX::Lua::LuaStubGen<581> stub581;
|
||||||
|
RBX::Lua::LuaStubGen<613> stub613;
|
||||||
|
RBX::Lua::LuaStubGen<928> stub928;
|
||||||
|
RBX::Lua::LuaStubGen<391> stub391;
|
||||||
|
RBX::Lua::LuaStubGen<868> stub868;
|
||||||
|
RBX::Lua::LuaStubGen<517> stub517;
|
||||||
|
RBX::Lua::LuaStubGen<393> stub393;
|
||||||
|
RBX::Lua::LuaStubGen<593> stub593;
|
||||||
|
RBX::Lua::LuaStubGen<865> stub865;
|
||||||
|
RBX::Lua::LuaStubGen<610> stub610;
|
||||||
|
RBX::Lua::LuaStubGen<289> stub289;
|
||||||
|
RBX::Lua::LuaStubGen<508> stub508;
|
||||||
|
RBX::Lua::LuaStubGen<779> stub779;
|
||||||
|
RBX::Lua::LuaStubGen<224> stub224;
|
||||||
|
RBX::Lua::LuaStubGen<527> stub527;
|
||||||
|
RBX::Lua::LuaStubGen<733> stub733;
|
||||||
|
RBX::Lua::LuaStubGen<419> stub419;
|
||||||
|
RBX::Lua::LuaStubGen<106> stub106;
|
||||||
|
RBX::Lua::LuaStubGen<501> stub501;
|
||||||
|
RBX::Lua::LuaStubGen<677> stub677;
|
||||||
|
RBX::Lua::LuaStubGen<212> stub212;
|
||||||
|
RBX::Lua::LuaStubGen<859> stub859;
|
||||||
|
RBX::Lua::LuaStubGen<697> stub697;
|
||||||
|
RBX::Lua::LuaStubGen<357> stub357;
|
||||||
|
RBX::Lua::LuaStubGen<233> stub233;
|
||||||
|
RBX::Lua::LuaStubGen<248> stub248;
|
||||||
|
RBX::Lua::LuaStubGen<698> stub698;
|
||||||
|
RBX::Lua::LuaStubGen<552> stub552;
|
||||||
|
RBX::Lua::LuaStubGen<19> stub19;
|
||||||
|
RBX::Lua::LuaStubGen<873> stub873;
|
||||||
|
RBX::Lua::LuaStubGen<169> stub169;
|
||||||
|
RBX::Lua::LuaStubGen<367> stub367;
|
||||||
|
RBX::Lua::LuaStubGen<763> stub763;
|
||||||
|
RBX::Lua::LuaStubGen<115> stub115;
|
||||||
|
RBX::Lua::LuaStubGen<477> stub477;
|
||||||
|
RBX::Lua::LuaStubGen<475> stub475;
|
||||||
|
RBX::Lua::LuaStubGen<341> stub341;
|
||||||
|
RBX::Lua::LuaStubGen<686> stub686;
|
||||||
|
RBX::Lua::LuaStubGen<939> stub939;
|
||||||
|
RBX::Lua::LuaStubGen<648> stub648;
|
||||||
|
RBX::Lua::LuaStubGen<277> stub277;
|
||||||
|
RBX::Lua::LuaStubGen<584> stub584;
|
||||||
|
RBX::Lua::LuaStubGen<776> stub776;
|
||||||
|
RBX::Lua::LuaStubGen<684> stub684;
|
||||||
|
RBX::Lua::LuaStubGen<155> stub155;
|
||||||
|
RBX::Lua::LuaStubGen<51> stub51;
|
||||||
|
RBX::Lua::LuaStubGen<994> stub994;
|
||||||
|
RBX::Lua::LuaStubGen<702> stub702;
|
||||||
|
RBX::Lua::LuaStubGen<3> stub3;
|
||||||
|
RBX::Lua::LuaStubGen<73> stub73;
|
||||||
|
RBX::Lua::LuaStubGen<579> stub579;
|
||||||
|
RBX::Lua::LuaStubGen<83> stub83;
|
||||||
|
RBX::Lua::LuaStubGen<768> stub768;
|
||||||
|
RBX::Lua::LuaStubGen<813> stub813;
|
||||||
|
RBX::Lua::LuaStubGen<604> stub604;
|
||||||
|
RBX::Lua::LuaStubGen<312> stub312;
|
||||||
|
RBX::Lua::LuaStubGen<588> stub588;
|
||||||
|
RBX::Lua::LuaStubGen<834> stub834;
|
||||||
|
RBX::Lua::LuaStubGen<313> stub313;
|
||||||
|
RBX::Lua::LuaStubGen<967> stub967;
|
||||||
|
RBX::Lua::LuaStubGen<784> stub784;
|
||||||
|
RBX::Lua::LuaStubGen<139> stub139;
|
||||||
|
RBX::Lua::LuaStubGen<555> stub555;
|
||||||
|
RBX::Lua::LuaStubGen<157> stub157;
|
||||||
|
RBX::Lua::LuaStubGen<226> stub226;
|
||||||
|
RBX::Lua::LuaStubGen<263> stub263;
|
||||||
|
RBX::Lua::LuaStubGen<863> stub863;
|
||||||
|
RBX::Lua::LuaStubGen<882> stub882;
|
||||||
|
RBX::Lua::LuaStubGen<110> stub110;
|
||||||
|
RBX::Lua::LuaStubGen<274> stub274;
|
||||||
|
RBX::Lua::LuaStubGen<736> stub736;
|
||||||
|
RBX::Lua::LuaStubGen<113> stub113;
|
||||||
|
RBX::Lua::LuaStubGen<484> stub484;
|
||||||
|
RBX::Lua::LuaStubGen<638> stub638;
|
||||||
|
RBX::Lua::LuaStubGen<49> stub49;
|
||||||
|
RBX::Lua::LuaStubGen<774> stub774;
|
||||||
|
RBX::Lua::LuaStubGen<742> stub742;
|
||||||
|
RBX::Lua::LuaStubGen<485> stub485;
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
|
||||||
|
RBX::Lua::LuaStubGen<290> stub290;
|
||||||
|
RBX::Lua::LuaStubGen<734> stub734;
|
||||||
|
RBX::Lua::LuaStubGen<543> stub543;
|
||||||
|
RBX::Lua::LuaStubGen<433> stub433;
|
||||||
|
RBX::Lua::LuaStubGen<871> stub871;
|
||||||
|
RBX::Lua::LuaStubGen<308> stub308;
|
||||||
|
RBX::Lua::LuaStubGen<685> stub685;
|
||||||
|
RBX::Lua::LuaStubGen<839> stub839;
|
||||||
|
RBX::Lua::LuaStubGen<870> stub870;
|
||||||
|
RBX::Lua::LuaStubGen<910> stub910;
|
||||||
|
RBX::Lua::LuaStubGen<150> stub150;
|
||||||
|
RBX::Lua::LuaStubGen<439> stub439;
|
||||||
|
RBX::Lua::LuaStubGen<799> stub799;
|
||||||
|
RBX::Lua::LuaStubGen<760> stub760;
|
||||||
|
RBX::Lua::LuaStubGen<878> stub878;
|
||||||
|
RBX::Lua::LuaStubGen<912> stub912;
|
||||||
|
RBX::Lua::LuaStubGen<168> stub168;
|
||||||
|
RBX::Lua::LuaStubGen<743> stub743;
|
||||||
|
RBX::Lua::LuaStubGen<624> stub624;
|
||||||
|
RBX::Lua::LuaStubGen<516> stub516;
|
||||||
|
RBX::Lua::LuaStubGen<545> stub545;
|
||||||
|
RBX::Lua::LuaStubGen<148> stub148;
|
||||||
|
RBX::Lua::LuaStubGen<121> stub121;
|
||||||
|
RBX::Lua::LuaStubGen<977> stub977;
|
||||||
|
RBX::Lua::LuaStubGen<998> stub998;
|
||||||
|
RBX::Lua::LuaStubGen<156> stub156;
|
||||||
|
RBX::Lua::LuaStubGen<999> stub999;
|
||||||
|
RBX::Lua::LuaStubGen<860> stub860;
|
||||||
|
RBX::Lua::LuaStubGen<41> stub41;
|
||||||
|
RBX::Lua::LuaStubGen<479> stub479;
|
||||||
|
RBX::Lua::LuaStubGen<366> stub366;
|
||||||
|
RBX::Lua::LuaStubGen<938> stub938;
|
||||||
|
RBX::Lua::LuaStubGen<577> stub577;
|
||||||
|
RBX::Lua::LuaStubGen<640> stub640;
|
||||||
|
RBX::Lua::LuaStubGen<956> stub956;
|
||||||
|
RBX::Lua::LuaStubGen<929> stub929;
|
||||||
|
RBX::Lua::LuaStubGen<574> stub574;
|
||||||
|
RBX::Lua::LuaStubGen<619> stub619;
|
||||||
|
RBX::Lua::LuaStubGen<166> stub166;
|
||||||
|
RBX::Lua::LuaStubGen<198> stub198;
|
||||||
|
RBX::Lua::LuaStubGen<11> stub11;
|
||||||
|
RBX::Lua::LuaStubGen<64> stub64;
|
||||||
|
RBX::Lua::LuaStubGen<221> stub221;
|
||||||
|
RBX::Lua::LuaStubGen<564> stub564;
|
||||||
|
RBX::Lua::LuaStubGen<56> stub56;
|
||||||
|
RBX::Lua::LuaStubGen<787> stub787;
|
||||||
|
RBX::Lua::LuaStubGen<713> stub713;
|
||||||
|
RBX::Lua::LuaStubGen<777> stub777;
|
||||||
|
RBX::Lua::LuaStubGen<541> stub541;
|
||||||
|
RBX::Lua::LuaStubGen<187> stub187;
|
||||||
|
RBX::Lua::LuaStubGen<600> stub600;
|
||||||
|
RBX::Lua::LuaStubGen<472> stub472;
|
||||||
|
RBX::Lua::LuaStubGen<196> stub196;
|
||||||
|
RBX::Lua::LuaStubGen<323> stub323;
|
||||||
|
RBX::Lua::LuaStubGen<616> stub616;
|
||||||
|
RBX::Lua::LuaStubGen<242> stub242;
|
||||||
|
RBX::Lua::LuaStubGen<699> stub699;
|
||||||
|
RBX::Lua::LuaStubGen<678> stub678;
|
||||||
|
RBX::Lua::LuaStubGen<532> stub532;
|
||||||
|
RBX::Lua::LuaStubGen<949> stub949;
|
||||||
|
RBX::Lua::LuaStubGen<973> stub973;
|
||||||
|
RBX::Lua::LuaStubGen<270> stub270;
|
||||||
|
RBX::Lua::LuaStubGen<14> stub14;
|
||||||
|
RBX::Lua::LuaStubGen<451> stub451;
|
||||||
|
RBX::Lua::LuaStubGen<12> stub12;
|
||||||
|
RBX::Lua::LuaStubGen<809> stub809;
|
||||||
|
RBX::Lua::LuaStubGen<642> stub642;
|
||||||
|
RBX::Lua::LuaStubGen<324> stub324;
|
||||||
|
RBX::Lua::LuaStubGen<7> stub7;
|
||||||
|
RBX::Lua::LuaStubGen<569> stub569;
|
||||||
|
RBX::Lua::LuaStubGen<880> stub880;
|
||||||
|
RBX::Lua::LuaStubGen<828> stub828;
|
||||||
|
RBX::Lua::LuaStubGen<35> stub35;
|
||||||
|
RBX::Lua::LuaStubGen<547> stub547;
|
||||||
|
RBX::Lua::LuaStubGen<447> stub447;
|
||||||
|
RBX::Lua::LuaStubGen<228> stub228;
|
||||||
|
RBX::Lua::LuaStubGen<739> stub739;
|
||||||
|
RBX::Lua::LuaStubGen<796> stub796;
|
||||||
|
RBX::Lua::LuaStubGen<889> stub889;
|
||||||
|
RBX::Lua::LuaStubGen<317> stub317;
|
||||||
|
RBX::Lua::LuaStubGen<668> stub668;
|
||||||
|
RBX::Lua::LuaStubGen<598> stub598;
|
||||||
|
RBX::Lua::LuaStubGen<781> stub781;
|
||||||
|
RBX::Lua::LuaStubGen<466> stub466;
|
||||||
|
RBX::Lua::LuaStubGen<823> stub823;
|
||||||
|
RBX::Lua::LuaStubGen<753> stub753;
|
||||||
|
RBX::Lua::LuaStubGen<101> stub101;
|
||||||
|
RBX::Lua::LuaStubGen<170> stub170;
|
||||||
|
RBX::Lua::LuaStubGen<612> stub612;
|
||||||
|
RBX::Lua::LuaStubGen<40> stub40;
|
||||||
|
RBX::Lua::LuaStubGen<502> stub502;
|
||||||
|
RBX::Lua::LuaStubGen<621> stub621;
|
||||||
|
RBX::Lua::LuaStubGen<893> stub893;
|
||||||
|
RBX::Lua::LuaStubGen<452> stub452;
|
||||||
|
RBX::Lua::LuaStubGen<345> stub345;
|
||||||
|
RBX::Lua::LuaStubGen<546> stub546;
|
||||||
|
RBX::Lua::LuaStubGen<623> stub623;
|
||||||
|
RBX::Lua::LuaStubGen<513> stub513;
|
||||||
|
RBX::Lua::LuaStubGen<15> stub15;
|
||||||
|
RBX::Lua::LuaStubGen<758> stub758;
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
|
||||||
|
RBX::Lua::LuaStubGen<614> stub614;
|
||||||
|
RBX::Lua::LuaStubGen<481> stub481;
|
||||||
|
RBX::Lua::LuaStubGen<217> stub217;
|
||||||
|
RBX::Lua::LuaStubGen<883> stub883;
|
||||||
|
RBX::Lua::LuaStubGen<261> stub261;
|
||||||
|
RBX::Lua::LuaStubGen<432> stub432;
|
||||||
|
RBX::Lua::LuaStubGen<383> stub383;
|
||||||
|
RBX::Lua::LuaStubGen<791> stub791;
|
||||||
|
RBX::Lua::LuaStubGen<395> stub395;
|
||||||
|
RBX::Lua::LuaStubGen<20> stub20;
|
||||||
|
RBX::Lua::LuaStubGen<916> stub916;
|
||||||
|
RBX::Lua::LuaStubGen<229> stub229;
|
||||||
|
RBX::Lua::LuaStubGen<215> stub215;
|
||||||
|
RBX::Lua::LuaStubGen<589> stub589;
|
||||||
|
RBX::Lua::LuaStubGen<23> stub23;
|
||||||
|
RBX::Lua::LuaStubGen<750> stub750;
|
||||||
|
RBX::Lua::LuaStubGen<483> stub483;
|
||||||
|
RBX::Lua::LuaStubGen<724> stub724;
|
||||||
|
RBX::Lua::LuaStubGen<505> stub505;
|
||||||
|
RBX::Lua::LuaStubGen<254> stub254;
|
||||||
|
RBX::Lua::LuaStubGen<752> stub752;
|
||||||
|
RBX::Lua::LuaStubGen<926> stub926;
|
||||||
|
RBX::Lua::LuaStubGen<524> stub524;
|
||||||
|
RBX::Lua::LuaStubGen<672> stub672;
|
||||||
|
RBX::Lua::LuaStubGen<406> stub406;
|
||||||
|
RBX::Lua::LuaStubGen<924> stub924;
|
||||||
|
RBX::Lua::LuaStubGen<394> stub394;
|
||||||
|
RBX::Lua::LuaStubGen<506> stub506;
|
||||||
|
RBX::Lua::LuaStubGen<772> stub772;
|
||||||
|
RBX::Lua::LuaStubGen<603> stub603;
|
||||||
|
RBX::Lua::LuaStubGen<175> stub175;
|
||||||
|
RBX::Lua::LuaStubGen<256> stub256;
|
||||||
|
RBX::Lua::LuaStubGen<392> stub392;
|
||||||
|
RBX::Lua::LuaStubGen<605> stub605;
|
||||||
|
RBX::Lua::LuaStubGen<534> stub534;
|
||||||
|
RBX::Lua::LuaStubGen<443> stub443;
|
||||||
|
RBX::Lua::LuaStubGen<365> stub365;
|
||||||
|
RBX::Lua::LuaStubGen<126> stub126;
|
||||||
|
RBX::Lua::LuaStubGen<709> stub709;
|
||||||
|
RBX::Lua::LuaStubGen<42> stub42;
|
||||||
|
RBX::Lua::LuaStubGen<10> stub10;
|
||||||
|
RBX::Lua::LuaStubGen<292> stub292;
|
||||||
|
RBX::Lua::LuaStubGen<669> stub669;
|
||||||
|
RBX::Lua::LuaStubGen<282> stub282;
|
||||||
|
RBX::Lua::LuaStubGen<201> stub201;
|
||||||
|
RBX::Lua::LuaStubGen<585> stub585;
|
||||||
|
RBX::Lua::LuaStubGen<693> stub693;
|
||||||
|
RBX::Lua::LuaStubGen<241> stub241;
|
||||||
|
RBX::Lua::LuaStubGen<131> stub131;
|
||||||
|
RBX::Lua::LuaStubGen<70> stub70;
|
||||||
|
RBX::Lua::LuaStubGen<360> stub360;
|
||||||
|
RBX::Lua::LuaStubGen<537> stub537;
|
||||||
|
RBX::Lua::LuaStubGen<408> stub408;
|
||||||
|
RBX::Lua::LuaStubGen<515> stub515;
|
||||||
|
RBX::Lua::LuaStubGen<9> stub9;
|
||||||
|
RBX::Lua::LuaStubGen<111> stub111;
|
||||||
|
RBX::Lua::LuaStubGen<388> stub388;
|
||||||
|
RBX::Lua::LuaStubGen<937> stub937;
|
||||||
|
RBX::Lua::LuaStubGen<276> stub276;
|
||||||
|
RBX::Lua::LuaStubGen<426> stub426;
|
||||||
|
RBX::Lua::LuaStubGen<832> stub832;
|
||||||
|
RBX::Lua::LuaStubGen<90> stub90;
|
||||||
|
RBX::Lua::LuaStubGen<414> stub414;
|
||||||
|
RBX::Lua::LuaStubGen<151> stub151;
|
||||||
|
RBX::Lua::LuaStubGen<178> stub178;
|
||||||
|
RBX::Lua::LuaStubGen<625> stub625;
|
||||||
|
RBX::Lua::LuaStubGen<478> stub478;
|
||||||
|
RBX::Lua::LuaStubGen<941> stub941;
|
||||||
|
RBX::Lua::LuaStubGen<71> stub71;
|
||||||
|
RBX::Lua::LuaStubGen<556> stub556;
|
||||||
|
RBX::Lua::LuaStubGen<421> stub421;
|
||||||
|
RBX::Lua::LuaStubGen<683> stub683;
|
||||||
|
RBX::Lua::LuaStubGen<422> stub422;
|
||||||
|
RBX::Lua::LuaStubGen<193> stub193;
|
||||||
|
RBX::Lua::LuaStubGen<626> stub626;
|
||||||
|
RBX::Lua::LuaStubGen<738> stub738;
|
||||||
|
RBX::Lua::LuaStubGen<728> stub728;
|
||||||
|
RBX::Lua::LuaStubGen<438> stub438;
|
||||||
|
RBX::Lua::LuaStubGen<606> stub606;
|
||||||
|
RBX::Lua::LuaStubGen<969> stub969;
|
||||||
|
RBX::Lua::LuaStubGen<602> stub602;
|
||||||
|
RBX::Lua::LuaStubGen<857> stub857;
|
||||||
|
RBX::Lua::LuaStubGen<572> stub572;
|
||||||
|
RBX::Lua::LuaStubGen<129> stub129;
|
||||||
|
RBX::Lua::LuaStubGen<578> stub578;
|
||||||
|
RBX::Lua::LuaStubGen<544> stub544;
|
||||||
|
RBX::Lua::LuaStubGen<358> stub358;
|
||||||
|
RBX::Lua::LuaStubGen<651> stub651;
|
||||||
|
RBX::Lua::LuaStubGen<482> stub482;
|
||||||
|
RBX::Lua::LuaStubGen<729> stub729;
|
||||||
|
RBX::Lua::LuaStubGen<582> stub582;
|
||||||
|
RBX::Lua::LuaStubGen<975> stub975;
|
||||||
|
RBX::Lua::LuaStubGen<238> stub238;
|
||||||
|
RBX::Lua::LuaStubGen<167> stub167;
|
||||||
|
RBX::Lua::LuaStubGen<632> stub632;
|
||||||
|
RBX::Lua::LuaStubGen<770> stub770;
|
||||||
|
RBX::Lua::LuaStubGen<176> stub176;
|
||||||
|
RBX::Lua::LuaStubGen<805> stub805;
|
||||||
|
RBX::Lua::LuaStubGen<473> stub473;
|
||||||
|
RBX::Lua::LuaStubGen<145> stub145;
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
|
||||||
|
RBX::Lua::LuaStubGen<641> stub641;
|
||||||
|
RBX::Lua::LuaStubGen<200> stub200;
|
||||||
|
RBX::Lua::LuaStubGen<428> stub428;
|
||||||
|
RBX::Lua::LuaStubGen<596> stub596;
|
||||||
|
RBX::Lua::LuaStubGen<909> stub909;
|
||||||
|
RBX::Lua::LuaStubGen<540> stub540;
|
||||||
|
RBX::Lua::LuaStubGen<108> stub108;
|
||||||
|
RBX::Lua::LuaStubGen<328> stub328;
|
||||||
|
RBX::Lua::LuaStubGen<852> stub852;
|
||||||
|
RBX::Lua::LuaStubGen<81> stub81;
|
||||||
|
RBX::Lua::LuaStubGen<761> stub761;
|
||||||
|
RBX::Lua::LuaStubGen<159> stub159;
|
||||||
|
RBX::Lua::LuaStubGen<46> stub46;
|
||||||
|
RBX::Lua::LuaStubGen<272> stub272;
|
||||||
|
RBX::Lua::LuaStubGen<404> stub404;
|
||||||
|
RBX::Lua::LuaStubGen<386> stub386;
|
||||||
|
RBX::Lua::LuaStubGen<719> stub719;
|
||||||
|
RBX::Lua::LuaStubGen<191> stub191;
|
||||||
|
RBX::Lua::LuaStubGen<33> stub33;
|
||||||
|
RBX::Lua::LuaStubGen<851> stub851;
|
||||||
|
RBX::Lua::LuaStubGen<561> stub561;
|
||||||
|
RBX::Lua::LuaStubGen<681> stub681;
|
||||||
|
RBX::Lua::LuaStubGen<721> stub721;
|
||||||
|
RBX::Lua::LuaStubGen<87> stub87;
|
||||||
|
RBX::Lua::LuaStubGen<996> stub996;
|
||||||
|
RBX::Lua::LuaStubGen<576> stub576;
|
||||||
|
RBX::Lua::LuaStubGen<835> stub835;
|
||||||
|
RBX::Lua::LuaStubGen<305> stub305;
|
||||||
|
RBX::Lua::LuaStubGen<182> stub182;
|
||||||
|
RBX::Lua::LuaStubGen<974> stub974;
|
||||||
|
RBX::Lua::LuaStubGen<294> stub294;
|
||||||
|
RBX::Lua::LuaStubGen<922> stub922;
|
||||||
|
RBX::Lua::LuaStubGen<890> stub890;
|
||||||
|
RBX::Lua::LuaStubGen<185> stub185;
|
||||||
|
RBX::Lua::LuaStubGen<253> stub253;
|
||||||
|
RBX::Lua::LuaStubGen<298> stub298;
|
||||||
|
RBX::Lua::LuaStubGen<744> stub744;
|
||||||
|
RBX::Lua::LuaStubGen<861> stub861;
|
||||||
|
RBX::Lua::LuaStubGen<885> stub885;
|
||||||
|
RBX::Lua::LuaStubGen<351> stub351;
|
||||||
|
RBX::Lua::LuaStubGen<63> stub63;
|
||||||
|
RBX::Lua::LuaStubGen<327> stub327;
|
||||||
|
RBX::Lua::LuaStubGen<599> stub599;
|
||||||
|
RBX::Lua::LuaStubGen<720> stub720;
|
||||||
|
RBX::Lua::LuaStubGen<911> stub911;
|
||||||
|
RBX::Lua::LuaStubGen<676> stub676;
|
||||||
|
RBX::Lua::LuaStubGen<993> stub993;
|
||||||
|
RBX::Lua::LuaStubGen<326> stub326;
|
||||||
|
RBX::Lua::LuaStubGen<489> stub489;
|
||||||
|
RBX::Lua::LuaStubGen<4> stub4;
|
||||||
|
RBX::Lua::LuaStubGen<830> stub830;
|
||||||
|
RBX::Lua::LuaStubGen<398> stub398;
|
||||||
|
RBX::Lua::LuaStubGen<509> stub509;
|
||||||
|
RBX::Lua::LuaStubGen<372> stub372;
|
||||||
|
RBX::Lua::LuaStubGen<102> stub102;
|
||||||
|
RBX::Lua::LuaStubGen<296> stub296;
|
||||||
|
RBX::Lua::LuaStubGen<86> stub86;
|
||||||
|
RBX::Lua::LuaStubGen<258> stub258;
|
||||||
|
RBX::Lua::LuaStubGen<981> stub981;
|
||||||
|
RBX::Lua::LuaStubGen<971> stub971;
|
||||||
|
RBX::Lua::LuaStubGen<65> stub65;
|
||||||
|
RBX::Lua::LuaStubGen<467> stub467;
|
||||||
|
RBX::Lua::LuaStubGen<566> stub566;
|
||||||
|
RBX::Lua::LuaStubGen<118> stub118;
|
||||||
|
RBX::Lua::LuaStubGen<565> stub565;
|
||||||
|
RBX::Lua::LuaStubGen<717> stub717;
|
||||||
|
RBX::Lua::LuaStubGen<741> stub741;
|
||||||
|
RBX::Lua::LuaStubGen<66> stub66;
|
||||||
|
RBX::Lua::LuaStubGen<348> stub348;
|
||||||
|
RBX::Lua::LuaStubGen<557> stub557;
|
||||||
|
RBX::Lua::LuaStubGen<202> stub202;
|
||||||
|
RBX::Lua::LuaStubGen<674> stub674;
|
||||||
|
RBX::Lua::LuaStubGen<480> stub480;
|
||||||
|
RBX::Lua::LuaStubGen<794> stub794;
|
||||||
|
RBX::Lua::LuaStubGen<234> stub234;
|
||||||
|
RBX::Lua::LuaStubGen<353> stub353;
|
||||||
|
RBX::Lua::LuaStubGen<757> stub757;
|
||||||
|
RBX::Lua::LuaStubGen<844> stub844;
|
||||||
|
RBX::Lua::LuaStubGen<900> stub900;
|
||||||
|
RBX::Lua::LuaStubGen<587> stub587;
|
||||||
|
RBX::Lua::LuaStubGen<773> stub773;
|
||||||
|
RBX::Lua::LuaStubGen<84> stub84;
|
||||||
|
RBX::Lua::LuaStubGen<284> stub284;
|
||||||
|
RBX::Lua::LuaStubGen<300> stub300;
|
||||||
|
RBX::Lua::LuaStubGen<456> stub456;
|
||||||
|
RBX::Lua::LuaStubGen<461> stub461;
|
||||||
|
RBX::Lua::LuaStubGen<109> stub109;
|
||||||
|
RBX::Lua::LuaStubGen<349> stub349;
|
||||||
|
RBX::Lua::LuaStubGen<337> stub337;
|
||||||
|
RBX::Lua::LuaStubGen<154> stub154;
|
||||||
|
RBX::Lua::LuaStubGen<293> stub293;
|
||||||
|
RBX::Lua::LuaStubGen<706> stub706;
|
||||||
|
RBX::Lua::LuaStubGen<764> stub764;
|
||||||
|
RBX::Lua::LuaStubGen<930> stub930;
|
||||||
|
RBX::Lua::LuaStubGen<465> stub465;
|
||||||
|
RBX::Lua::LuaStubGen<245> stub245;
|
||||||
|
RBX::Lua::LuaStubGen<55> stub55;
|
||||||
|
RBX::Lua::LuaStubGen<960> stub960;
|
||||||
|
RBX::Lua::LuaStubGen<756> stub756;
|
||||||
|
RBX::Lua::LuaStubGen<521> stub521;
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
|
||||||
|
RBX::Lua::LuaStubGen<144> stub144;
|
||||||
|
RBX::Lua::LuaStubGen<44> stub44;
|
||||||
|
RBX::Lua::LuaStubGen<667> stub667;
|
||||||
|
RBX::Lua::LuaStubGen<896> stub896;
|
||||||
|
RBX::Lua::LuaStubGen<318> stub318;
|
||||||
|
RBX::Lua::LuaStubGen<731> stub731;
|
||||||
|
RBX::Lua::LuaStubGen<98> stub98;
|
||||||
|
RBX::Lua::LuaStubGen<306> stub306;
|
||||||
|
RBX::Lua::LuaStubGen<434> stub434;
|
||||||
|
RBX::Lua::LuaStubGen<374> stub374;
|
||||||
|
RBX::Lua::LuaStubGen<92> stub92;
|
||||||
|
RBX::Lua::LuaStubGen<309> stub309;
|
||||||
|
RBX::Lua::LuaStubGen<94> stub94;
|
||||||
|
RBX::Lua::LuaStubGen<239> stub239;
|
||||||
|
RBX::Lua::LuaStubGen<464> stub464;
|
||||||
|
RBX::Lua::LuaStubGen<243> stub243;
|
||||||
|
RBX::Lua::LuaStubGen<963> stub963;
|
||||||
|
RBX::Lua::LuaStubGen<514> stub514;
|
||||||
|
RBX::Lua::LuaStubGen<639> stub639;
|
||||||
|
RBX::Lua::LuaStubGen<816> stub816;
|
||||||
|
RBX::Lua::LuaStubGen<164> stub164;
|
||||||
|
RBX::Lua::LuaStubGen<653> stub653;
|
||||||
|
RBX::Lua::LuaStubGen<812> stub812;
|
||||||
|
RBX::Lua::LuaStubGen<269> stub269;
|
||||||
|
RBX::Lua::LuaStubGen<822> stub822;
|
||||||
|
RBX::Lua::LuaStubGen<864> stub864;
|
||||||
|
RBX::Lua::LuaStubGen<499> stub499;
|
||||||
|
RBX::Lua::LuaStubGen<130> stub130;
|
||||||
|
RBX::Lua::LuaStubGen<59> stub59;
|
||||||
|
RBX::Lua::LuaStubGen<27> stub27;
|
||||||
|
RBX::Lua::LuaStubGen<162> stub162;
|
||||||
|
RBX::Lua::LuaStubGen<570> stub570;
|
||||||
|
RBX::Lua::LuaStubGen<74> stub74;
|
||||||
|
RBX::Lua::LuaStubGen<117> stub117;
|
||||||
|
RBX::Lua::LuaStubGen<935> stub935;
|
||||||
|
RBX::Lua::LuaStubGen<96> stub96;
|
||||||
|
RBX::Lua::LuaStubGen<629> stub629;
|
||||||
|
RBX::Lua::LuaStubGen<163> stub163;
|
||||||
|
RBX::Lua::LuaStubGen<934> stub934;
|
||||||
|
RBX::Lua::LuaStubGen<275> stub275;
|
||||||
|
RBX::Lua::LuaStubGen<165> stub165;
|
||||||
|
RBX::Lua::LuaStubGen<267> stub267;
|
||||||
|
RBX::Lua::LuaStubGen<195> stub195;
|
||||||
|
RBX::Lua::LuaStubGen<833> stub833;
|
||||||
|
RBX::Lua::LuaStubGen<30> stub30;
|
||||||
|
RBX::Lua::LuaStubGen<304> stub304;
|
||||||
|
RBX::Lua::LuaStubGen<114> stub114;
|
||||||
|
RBX::Lua::LuaStubGen<369> stub369;
|
||||||
|
RBX::Lua::LuaStubGen<708> stub708;
|
||||||
|
RBX::Lua::LuaStubGen<611> stub611;
|
||||||
|
RBX::Lua::LuaStubGen<441> stub441;
|
||||||
|
RBX::Lua::LuaStubGen<512> stub512;
|
||||||
|
RBX::Lua::LuaStubGen<143> stub143;
|
||||||
|
RBX::Lua::LuaStubGen<615> stub615;
|
||||||
|
RBX::Lua::LuaStubGen<792> stub792;
|
||||||
|
RBX::Lua::LuaStubGen<76> stub76;
|
||||||
|
RBX::Lua::LuaStubGen<853> stub853;
|
||||||
|
RBX::Lua::LuaStubGen<500> stub500;
|
||||||
|
RBX::Lua::LuaStubGen<710> stub710;
|
||||||
|
RBX::Lua::LuaStubGen<782> stub782;
|
||||||
|
RBX::Lua::LuaStubGen<869> stub869;
|
||||||
|
RBX::Lua::LuaStubGen<690> stub690;
|
||||||
|
RBX::Lua::LuaStubGen<184> stub184;
|
||||||
|
RBX::Lua::LuaStubGen<424> stub424;
|
||||||
|
RBX::Lua::LuaStubGen<204> stub204;
|
||||||
|
RBX::Lua::LuaStubGen<2> stub2;
|
||||||
|
RBX::Lua::LuaStubGen<354> stub354;
|
||||||
|
RBX::Lua::LuaStubGen<400> stub400;
|
||||||
|
RBX::Lua::LuaStubGen<216> stub216;
|
||||||
|
RBX::Lua::LuaStubGen<152> stub152;
|
||||||
|
RBX::Lua::LuaStubGen<18> stub18;
|
||||||
|
RBX::Lua::LuaStubGen<190> stub190;
|
||||||
|
RBX::Lua::LuaStubGen<380> stub380;
|
||||||
|
RBX::Lua::LuaStubGen<246> stub246;
|
||||||
|
RBX::Lua::LuaStubGen<628> stub628;
|
||||||
|
RBX::Lua::LuaStubGen<26> stub26;
|
||||||
|
RBX::Lua::LuaStubGen<645> stub645;
|
||||||
|
RBX::Lua::LuaStubGen<945> stub945;
|
||||||
|
RBX::Lua::LuaStubGen<347> stub347;
|
||||||
|
RBX::Lua::LuaStubGen<829> stub829;
|
||||||
|
RBX::Lua::LuaStubGen<858> stub858;
|
||||||
|
RBX::Lua::LuaStubGen<802> stub802;
|
||||||
|
RBX::Lua::LuaStubGen<965> stub965;
|
||||||
|
RBX::Lua::LuaStubGen<262> stub262;
|
||||||
|
RBX::Lua::LuaStubGen<268> stub268;
|
||||||
|
RBX::Lua::LuaStubGen<806> stub806;
|
||||||
|
RBX::Lua::LuaStubGen<944> stub944;
|
||||||
|
RBX::Lua::LuaStubGen<225> stub225;
|
||||||
|
RBX::Lua::LuaStubGen<188> stub188;
|
||||||
|
RBX::Lua::LuaStubGen<266> stub266;
|
||||||
|
RBX::Lua::LuaStubGen<417> stub417;
|
||||||
|
RBX::Lua::LuaStubGen<377> stub377;
|
||||||
|
RBX::Lua::LuaStubGen<425> stub425;
|
||||||
|
RBX::Lua::LuaStubGen<286> stub286;
|
||||||
|
RBX::Lua::LuaStubGen<986> stub986;
|
||||||
|
RBX::Lua::LuaStubGen<843> stub843;
|
||||||
|
RBX::Lua::LuaStubGen<827> stub827;
|
||||||
|
RBX::Lua::LuaStubGen<807> stub807;
|
||||||
|
RBX::Lua::LuaStubGen<730> stub730;
|
||||||
|
RBX::Lua::LuaStubGen<440> stub440;
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
|
||||||
|
RBX::Lua::LuaStubGen<525> stub525;
|
||||||
|
RBX::Lua::LuaStubGen<980> stub980;
|
||||||
|
RBX::Lua::LuaStubGen<496> stub496;
|
||||||
|
RBX::Lua::LuaStubGen<194> stub194;
|
||||||
|
RBX::Lua::LuaStubGen<608> stub608;
|
||||||
|
RBX::Lua::LuaStubGen<884> stub884;
|
||||||
|
RBX::Lua::LuaStubGen<265> stub265;
|
||||||
|
RBX::Lua::LuaStubGen<62> stub62;
|
||||||
|
RBX::Lua::LuaStubGen<336> stub336;
|
||||||
|
RBX::Lua::LuaStubGen<538> stub538;
|
||||||
|
RBX::Lua::LuaStubGen<295> stub295;
|
||||||
|
RBX::Lua::LuaStubGen<991> stub991;
|
||||||
|
RBX::Lua::LuaStubGen<795> stub795;
|
||||||
|
RBX::Lua::LuaStubGen<976> stub976;
|
||||||
|
RBX::Lua::LuaStubGen<498> stub498;
|
||||||
|
RBX::Lua::LuaStubGen<103> stub103;
|
||||||
|
RBX::Lua::LuaStubGen<723> stub723;
|
||||||
|
RBX::Lua::LuaStubGen<222> stub222;
|
||||||
|
RBX::Lua::LuaStubGen<886> stub886;
|
||||||
|
RBX::Lua::LuaStubGen<285> stub285;
|
||||||
|
RBX::Lua::LuaStubGen<927> stub927;
|
||||||
|
RBX::Lua::LuaStubGen<765> stub765;
|
||||||
|
RBX::Lua::LuaStubGen<147> stub147;
|
||||||
|
RBX::Lua::LuaStubGen<867> stub867;
|
||||||
|
RBX::Lua::LuaStubGen<597> stub597;
|
||||||
|
RBX::Lua::LuaStubGen<136> stub136;
|
||||||
|
RBX::Lua::LuaStubGen<895> stub895;
|
||||||
|
RBX::Lua::LuaStubGen<837> stub837;
|
||||||
|
RBX::Lua::LuaStubGen<631> stub631;
|
||||||
|
RBX::Lua::LuaStubGen<825> stub825;
|
||||||
|
RBX::Lua::LuaStubGen<575> stub575;
|
||||||
|
RBX::Lua::LuaStubGen<329> stub329;
|
||||||
|
RBX::Lua::LuaStubGen<435> stub435;
|
||||||
|
RBX::Lua::LuaStubGen<769> stub769;
|
||||||
|
RBX::Lua::LuaStubGen<494> stub494;
|
||||||
|
RBX::Lua::LuaStubGen<45> stub45;
|
||||||
|
RBX::Lua::LuaStubGen<31> stub31;
|
||||||
|
RBX::Lua::LuaStubGen<179> stub179;
|
||||||
|
RBX::Lua::LuaStubGen<255> stub255;
|
||||||
|
RBX::Lua::LuaStubGen<943> stub943;
|
||||||
|
RBX::Lua::LuaStubGen<810> stub810;
|
||||||
|
RBX::Lua::LuaStubGen<617> stub617;
|
||||||
|
RBX::Lua::LuaStubGen<988> stub988;
|
||||||
|
RBX::Lua::LuaStubGen<446> stub446;
|
||||||
|
RBX::Lua::LuaStubGen<213> stub213;
|
||||||
|
RBX::Lua::LuaStubGen<567> stub567;
|
||||||
|
RBX::Lua::LuaStubGen<714> stub714;
|
||||||
|
RBX::Lua::LuaStubGen<379> stub379;
|
||||||
|
RBX::Lua::LuaStubGen<301> stub301;
|
||||||
|
RBX::Lua::LuaStubGen<350> stub350;
|
||||||
|
RBX::Lua::LuaStubGen<691> stub691;
|
||||||
|
RBX::Lua::LuaStubGen<551> stub551;
|
||||||
|
RBX::Lua::LuaStubGen<24> stub24;
|
||||||
|
RBX::Lua::LuaStubGen<948> stub948;
|
||||||
|
RBX::Lua::LuaStubGen<931> stub931;
|
||||||
|
RBX::Lua::LuaStubGen<704> stub704;
|
||||||
|
RBX::Lua::LuaStubGen<343> stub343;
|
||||||
|
RBX::Lua::LuaStubGen<133> stub133;
|
||||||
|
RBX::Lua::LuaStubGen<923> stub923;
|
||||||
|
RBX::Lua::LuaStubGen<968> stub968;
|
||||||
|
RBX::Lua::LuaStubGen<735> stub735;
|
||||||
|
RBX::Lua::LuaStubGen<436> stub436;
|
||||||
|
RBX::Lua::LuaStubGen<218> stub218;
|
||||||
|
RBX::Lua::LuaStubGen<957> stub957;
|
||||||
|
RBX::Lua::LuaStubGen<364> stub364;
|
||||||
|
RBX::Lua::LuaStubGen<601> stub601;
|
||||||
|
RBX::Lua::LuaStubGen<982> stub982;
|
||||||
|
RBX::Lua::LuaStubGen<409> stub409;
|
||||||
|
RBX::Lua::LuaStubGen<899> stub899;
|
||||||
|
RBX::Lua::LuaStubGen<953> stub953;
|
||||||
|
RBX::Lua::LuaStubGen<637> stub637;
|
||||||
|
RBX::Lua::LuaStubGen<16> stub16;
|
||||||
|
RBX::Lua::LuaStubGen<402> stub402;
|
||||||
|
RBX::Lua::LuaStubGen<780> stub780;
|
||||||
|
RBX::Lua::LuaStubGen<689> stub689;
|
||||||
|
RBX::Lua::LuaStubGen<373> stub373;
|
||||||
|
RBX::Lua::LuaStubGen<273> stub273;
|
||||||
|
RBX::Lua::LuaStubGen<636> stub636;
|
||||||
|
RBX::Lua::LuaStubGen<210> stub210;
|
||||||
|
RBX::Lua::LuaStubGen<548> stub548;
|
||||||
|
RBX::Lua::LuaStubGen<804> stub804;
|
||||||
|
RBX::Lua::LuaStubGen<1> stub1;
|
||||||
|
RBX::Lua::LuaStubGen<663> stub663;
|
||||||
|
RBX::Lua::LuaStubGen<785> stub785;
|
||||||
|
RBX::Lua::LuaStubGen<811> stub811;
|
||||||
|
RBX::Lua::LuaStubGen<344> stub344;
|
||||||
|
RBX::Lua::LuaStubGen<664> stub664;
|
||||||
|
RBX::Lua::LuaStubGen<831> stub831;
|
||||||
|
RBX::Lua::LuaStubGen<783> stub783;
|
||||||
|
RBX::Lua::LuaStubGen<978> stub978;
|
||||||
|
RBX::Lua::LuaStubGen<841> stub841;
|
||||||
|
RBX::Lua::LuaStubGen<22> stub22;
|
||||||
|
RBX::Lua::LuaStubGen<520> stub520;
|
||||||
|
RBX::Lua::LuaStubGen<6> stub6;
|
||||||
|
RBX::Lua::LuaStubGen<659> stub659;
|
||||||
|
RBX::Lua::LuaStubGen<230> stub230;
|
||||||
|
RBX::Lua::LuaStubGen<72> stub72;
|
||||||
|
RBX::Lua::LuaStubGen<57> stub57;
|
||||||
|
RBX::Lua::LuaStubGen<333> stub333;
|
||||||
|
RBX::Lua::LuaStubGen<80> stub80;
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
|
||||||
|
RBX::Lua::LuaStubGen<355> stub355;
|
||||||
|
RBX::Lua::LuaStubGen<411> stub411;
|
||||||
|
RBX::Lua::LuaStubGen<531> stub531;
|
||||||
|
RBX::Lua::LuaStubGen<281> stub281;
|
||||||
|
RBX::Lua::LuaStubGen<67> stub67;
|
||||||
|
RBX::Lua::LuaStubGen<297> stub297;
|
||||||
|
RBX::Lua::LuaStubGen<415> stub415;
|
||||||
|
RBX::Lua::LuaStubGen<954> stub954;
|
||||||
|
RBX::Lua::LuaStubGen<410> stub410;
|
||||||
|
RBX::Lua::LuaStubGen<798> stub798;
|
||||||
|
RBX::Lua::LuaStubGen<519> stub519;
|
||||||
|
RBX::Lua::LuaStubGen<493> stub493;
|
||||||
|
RBX::Lua::LuaStubGen<299> stub299;
|
||||||
|
RBX::Lua::LuaStubGen<656> stub656;
|
||||||
|
RBX::Lua::LuaStubGen<808> stub808;
|
||||||
|
RBX::Lua::LuaStubGen<906> stub906;
|
||||||
|
RBX::Lua::LuaStubGen<778> stub778;
|
||||||
|
RBX::Lua::LuaStubGen<445> stub445;
|
||||||
|
RBX::Lua::LuaStubGen<468> stub468;
|
||||||
|
RBX::Lua::LuaStubGen<363> stub363;
|
||||||
|
RBX::Lua::LuaStubGen<902> stub902;
|
||||||
|
RBX::Lua::LuaStubGen<740> stub740;
|
||||||
|
RBX::Lua::LuaStubGen<32> stub32;
|
||||||
|
RBX::Lua::LuaStubGen<278> stub278;
|
||||||
|
RBX::Lua::LuaStubGen<767> stub767;
|
||||||
|
RBX::Lua::LuaStubGen<594> stub594;
|
||||||
|
RBX::Lua::LuaStubGen<335> stub335;
|
||||||
|
RBX::Lua::LuaStubGen<356> stub356;
|
||||||
|
RBX::Lua::LuaStubGen<376> stub376;
|
||||||
|
RBX::Lua::LuaStubGen<955> stub955;
|
||||||
|
RBX::Lua::LuaStubGen<315> stub315;
|
||||||
|
RBX::Lua::LuaStubGen<915> stub915;
|
||||||
|
RBX::Lua::LuaStubGen<788> stub788;
|
||||||
|
RBX::Lua::LuaStubGen<940> stub940;
|
||||||
|
RBX::Lua::LuaStubGen<405> stub405;
|
||||||
|
RBX::Lua::LuaStubGen<442> stub442;
|
||||||
|
RBX::Lua::LuaStubGen<250> stub250;
|
||||||
|
RBX::Lua::LuaStubGen<476> stub476;
|
||||||
|
RBX::Lua::LuaStubGen<120> stub120;
|
||||||
|
RBX::Lua::LuaStubGen<528> stub528;
|
||||||
|
RBX::Lua::LuaStubGen<142> stub142;
|
||||||
|
RBX::Lua::LuaStubGen<186> stub186;
|
||||||
|
RBX::Lua::LuaStubGen<754> stub754;
|
||||||
|
RBX::Lua::LuaStubGen<989> stub989;
|
||||||
|
RBX::Lua::LuaStubGen<25> stub25;
|
||||||
|
RBX::Lua::LuaStubGen<223> stub223;
|
||||||
|
RBX::Lua::LuaStubGen<848> stub848;
|
||||||
|
RBX::Lua::LuaStubGen<815> stub815;
|
||||||
|
RBX::Lua::LuaStubGen<658> stub658;
|
||||||
|
RBX::Lua::LuaStubGen<905> stub905;
|
||||||
|
RBX::Lua::LuaStubGen<37> stub37;
|
||||||
|
RBX::Lua::LuaStubGen<338> stub338;
|
||||||
|
RBX::Lua::LuaStubGen<53> stub53;
|
||||||
|
RBX::Lua::LuaStubGen<682> stub682;
|
||||||
|
RBX::Lua::LuaStubGen<904> stub904;
|
||||||
|
RBX::Lua::LuaStubGen<862> stub862;
|
||||||
|
RBX::Lua::LuaStubGen<533> stub533;
|
||||||
|
RBX::Lua::LuaStubGen<694> stub694;
|
||||||
|
RBX::Lua::LuaStubGen<558> stub558;
|
||||||
|
RBX::Lua::LuaStubGen<100> stub100;
|
||||||
|
RBX::Lua::LuaStubGen<518> stub518;
|
||||||
|
RBX::Lua::LuaStubGen<125> stub125;
|
||||||
|
RBX::Lua::LuaStubGen<845> stub845;
|
||||||
|
RBX::Lua::LuaStubGen<503> stub503;
|
||||||
|
RBX::Lua::LuaStubGen<340> stub340;
|
||||||
|
RBX::Lua::LuaStubGen<399> stub399;
|
||||||
|
RBX::Lua::LuaStubGen<89> stub89;
|
||||||
|
RBX::Lua::LuaStubGen<146> stub146;
|
||||||
|
RBX::Lua::LuaStubGen<917> stub917;
|
||||||
|
RBX::Lua::LuaStubGen<877> stub877;
|
||||||
|
RBX::Lua::LuaStubGen<696> stub696;
|
||||||
|
RBX::Lua::LuaStubGen<279> stub279;
|
||||||
|
RBX::Lua::LuaStubGen<368> stub368;
|
||||||
|
RBX::Lua::LuaStubGen<936> stub936;
|
||||||
|
RBX::Lua::LuaStubGen<378> stub378;
|
||||||
|
RBX::Lua::LuaStubGen<958> stub958;
|
||||||
|
RBX::Lua::LuaStubGen<962> stub962;
|
||||||
|
RBX::Lua::LuaStubGen<38> stub38;
|
||||||
|
RBX::Lua::LuaStubGen<444> stub444;
|
||||||
|
RBX::Lua::LuaStubGen<257> stub257;
|
||||||
|
RBX::Lua::LuaStubGen<607> stub607;
|
||||||
|
RBX::Lua::LuaStubGen<427> stub427;
|
||||||
|
RBX::Lua::LuaStubGen<149> stub149;
|
||||||
|
RBX::Lua::LuaStubGen<855> stub855;
|
||||||
|
RBX::Lua::LuaStubGen<135> stub135;
|
||||||
|
RBX::Lua::LuaStubGen<127> stub127;
|
||||||
|
RBX::Lua::LuaStubGen<430> stub430;
|
||||||
|
RBX::Lua::LuaStubGen<511> stub511;
|
||||||
|
RBX::Lua::LuaStubGen<748> stub748;
|
||||||
|
RBX::Lua::LuaStubGen<952> stub952;
|
||||||
|
RBX::Lua::LuaStubGen<104> stub104;
|
||||||
|
RBX::Lua::LuaStubGen<650> stub650;
|
||||||
|
RBX::Lua::LuaStubGen<771> stub771;
|
||||||
|
RBX::Lua::LuaStubGen<680> stub680;
|
||||||
|
RBX::Lua::LuaStubGen<876> stub876;
|
||||||
|
RBX::Lua::LuaStubGen<849> stub849;
|
||||||
|
RBX::Lua::LuaStubGen<251> stub251;
|
||||||
|
RBX::Lua::LuaStubGen<635> stub635;
|
||||||
|
RBX::Lua::LuaStubGen<77> stub77;
|
||||||
|
RBX::Lua::LuaStubGen<141> stub141;
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "lua/lua.hpp"
|
||||||
|
|
||||||
|
RBX::Lua::LuaStubGen<137> stub137;
|
||||||
|
RBX::Lua::LuaStubGen<966> stub966;
|
||||||
|
RBX::Lua::LuaStubGen<894> stub894;
|
||||||
|
RBX::Lua::LuaStubGen<95> stub95;
|
||||||
|
RBX::Lua::LuaStubGen<586> stub586;
|
||||||
|
RBX::Lua::LuaStubGen<715> stub715;
|
||||||
|
RBX::Lua::LuaStubGen<657> stub657;
|
||||||
|
RBX::Lua::LuaStubGen<244> stub244;
|
||||||
|
RBX::Lua::LuaStubGen<826> stub826;
|
||||||
|
RBX::Lua::LuaStubGen<303> stub303;
|
||||||
|
RBX::Lua::LuaStubGen<964> stub964;
|
||||||
|
RBX::Lua::LuaStubGen<732> stub732;
|
||||||
|
RBX::Lua::LuaStubGen<984> stub984;
|
||||||
|
RBX::Lua::LuaStubGen<240> stub240;
|
||||||
|
RBX::Lua::LuaStubGen<342> stub342;
|
||||||
|
RBX::Lua::LuaStubGen<264> stub264;
|
||||||
|
RBX::Lua::LuaStubGen<192> stub192;
|
||||||
|
RBX::Lua::LuaStubGen<874> stub874;
|
||||||
|
RBX::Lua::LuaStubGen<563> stub563;
|
||||||
|
RBX::Lua::LuaStubGen<644> stub644;
|
||||||
|
RBX::Lua::LuaStubGen<495> stub495;
|
||||||
|
RBX::Lua::LuaStubGen<460> stub460;
|
||||||
|
RBX::Lua::LuaStubGen<583> stub583;
|
||||||
|
RBX::Lua::LuaStubGen<39> stub39;
|
||||||
|
RBX::Lua::LuaStubGen<707> stub707;
|
||||||
|
RBX::Lua::LuaStubGen<334> stub334;
|
||||||
|
RBX::Lua::LuaStubGen<8> stub8;
|
||||||
|
RBX::Lua::LuaStubGen<132> stub132;
|
||||||
|
RBX::Lua::LuaStubGen<474> stub474;
|
||||||
|
RBX::Lua::LuaStubGen<407> stub407;
|
||||||
|
RBX::Lua::LuaStubGen<75> stub75;
|
||||||
|
RBX::Lua::LuaStubGen<542> stub542;
|
||||||
|
RBX::Lua::LuaStubGen<789> stub789;
|
||||||
|
RBX::Lua::LuaStubGen<36> stub36;
|
||||||
|
RBX::Lua::LuaStubGen<174> stub174;
|
||||||
|
RBX::Lua::LuaStubGen<252> stub252;
|
||||||
|
RBX::Lua::LuaStubGen<28> stub28;
|
||||||
|
RBX::Lua::LuaStubGen<618> stub618;
|
||||||
|
RBX::Lua::LuaStubGen<205> stub205;
|
||||||
|
RBX::Lua::LuaStubGen<838> stub838;
|
||||||
|
RBX::Lua::LuaStubGen<260> stub260;
|
||||||
|
RBX::Lua::LuaStubGen<116> stub116;
|
||||||
|
RBX::Lua::LuaStubGen<888> stub888;
|
||||||
|
RBX::Lua::LuaStubGen<91> stub91;
|
||||||
|
RBX::Lua::LuaStubGen<153> stub153;
|
||||||
|
RBX::Lua::LuaStubGen<180> stub180;
|
||||||
|
RBX::Lua::LuaStubGen<247> stub247;
|
||||||
|
RBX::Lua::LuaStubGen<850> stub850;
|
||||||
|
RBX::Lua::LuaStubGen<660> stub660;
|
||||||
|
RBX::Lua::LuaStubGen<280> stub280;
|
||||||
|
RBX::Lua::LuaStubGen<942> stub942;
|
||||||
|
RBX::Lua::LuaStubGen<665> stub665;
|
||||||
|
RBX::Lua::LuaStubGen<726> stub726;
|
||||||
|
RBX::Lua::LuaStubGen<332> stub332;
|
||||||
|
RBX::Lua::LuaStubGen<820> stub820;
|
||||||
|
RBX::Lua::LuaStubGen<592> stub592;
|
||||||
|
RBX::Lua::LuaStubGen<793> stub793;
|
||||||
|
RBX::Lua::LuaStubGen<759> stub759;
|
||||||
|
RBX::Lua::LuaStubGen<898> stub898;
|
||||||
|
RBX::Lua::LuaStubGen<746> stub746;
|
||||||
|
RBX::Lua::LuaStubGen<817> stub817;
|
||||||
|
RBX::Lua::LuaStubGen<457> stub457;
|
||||||
|
RBX::Lua::LuaStubGen<449> stub449;
|
||||||
|
RBX::Lua::LuaStubGen<950> stub950;
|
||||||
|
RBX::Lua::LuaStubGen<291> stub291;
|
||||||
|
RBX::Lua::LuaStubGen<140> stub140;
|
||||||
|
RBX::Lua::LuaStubGen<389> stub389;
|
||||||
|
RBX::Lua::LuaStubGen<913> stub913;
|
||||||
|
RBX::Lua::LuaStubGen<549> stub549;
|
||||||
|
RBX::Lua::LuaStubGen<310> stub310;
|
||||||
|
RBX::Lua::LuaStubGen<990> stub990;
|
||||||
|
RBX::Lua::LuaStubGen<259> stub259;
|
||||||
|
RBX::Lua::LuaStubGen<50> stub50;
|
||||||
|
RBX::Lua::LuaStubGen<688> stub688;
|
||||||
|
RBX::Lua::LuaStubGen<52> stub52;
|
||||||
|
RBX::Lua::LuaStubGen<755> stub755;
|
||||||
|
RBX::Lua::LuaStubGen<437> stub437;
|
||||||
|
RBX::Lua::LuaStubGen<48> stub48;
|
||||||
|
RBX::Lua::LuaStubGen<662> stub662;
|
||||||
|
RBX::Lua::LuaStubGen<189> stub189;
|
||||||
|
RBX::Lua::LuaStubGen<123> stub123;
|
||||||
|
RBX::Lua::LuaStubGen<679> stub679;
|
||||||
|
RBX::Lua::LuaStubGen<0> stub0;
|
||||||
|
RBX::Lua::LuaStubGen<283> stub283;
|
||||||
|
RBX::Lua::LuaStubGen<359> stub359;
|
||||||
|
RBX::Lua::LuaStubGen<946> stub946;
|
||||||
|
RBX::Lua::LuaStubGen<670> stub670;
|
||||||
|
RBX::Lua::LuaStubGen<271> stub271;
|
||||||
|
RBX::Lua::LuaStubGen<847> stub847;
|
||||||
|
RBX::Lua::LuaStubGen<416> stub416;
|
||||||
|
RBX::Lua::LuaStubGen<903> stub903;
|
||||||
|
RBX::Lua::LuaStubGen<595> stub595;
|
||||||
|
RBX::Lua::LuaStubGen<970> stub970;
|
||||||
|
RBX::Lua::LuaStubGen<138> stub138;
|
||||||
|
RBX::Lua::LuaStubGen<54> stub54;
|
||||||
|
RBX::Lua::LuaStubGen<590> stub590;
|
||||||
|
RBX::Lua::LuaStubGen<921> stub921;
|
||||||
|
RBX::Lua::LuaStubGen<21> stub21;
|
||||||
|
RBX::Lua::LuaStubGen<171> stub171;
|
||||||
|
RBX::Lua::LuaStubGen<673> stub673;
|
||||||
@@ -0,0 +1,597 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "reflection/type.h"
|
||||||
|
#include "security/securitycontext.h"
|
||||||
|
#include "reflection/member.h"
|
||||||
|
#include "reflection/Type.h"
|
||||||
|
#include <boost/utility/enable_if.hpp>
|
||||||
|
#include <boost/type_traits.hpp>
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
namespace Reflection
|
||||||
|
{
|
||||||
|
class Callback;
|
||||||
|
|
||||||
|
// Base class that describes a Callback
|
||||||
|
class RBXBaseClass CallbackDescriptor : public MemberDescriptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef Callback ConstMember;
|
||||||
|
typedef Callback Member;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SignatureDescriptor signature;
|
||||||
|
bool async;
|
||||||
|
|
||||||
|
CallbackDescriptor(ClassDescriptor& classDescriptor, const char* name, Descriptor::Attributes attributes, Security::Permissions security, bool async);
|
||||||
|
public:
|
||||||
|
inline const SignatureDescriptor& getSignature() const { return signature; }
|
||||||
|
bool isAsync() const { return async; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SyncCallbackDescriptor : public CallbackDescriptor
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
SyncCallbackDescriptor(ClassDescriptor& classDescriptor, const char* name, Descriptor::Attributes attributes, Security::Permissions security);
|
||||||
|
public:
|
||||||
|
typedef boost::function<shared_ptr<Reflection::Tuple>(shared_ptr<const Reflection::Tuple> args)> GenericFunction;
|
||||||
|
|
||||||
|
// the preferred way to set a generic function:
|
||||||
|
virtual void setGenericCallback(DescribedBase* object, shared_ptr<GenericFunction> function) const = 0;
|
||||||
|
virtual void clearCallback(DescribedBase* object) const = 0;
|
||||||
|
|
||||||
|
// use this function if you don't have a shared_ptr:
|
||||||
|
void setGenericCallbackHelper(DescribedBase* object, const GenericFunction& function) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncCallbackDescriptor : public CallbackDescriptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef boost::function<void(shared_ptr<const Reflection::Tuple>)> ResumeFunction;
|
||||||
|
typedef boost::function<void(std::string)> ErrorFunction;
|
||||||
|
typedef boost::function<void(shared_ptr<const Reflection::Tuple> args, ResumeFunction resumeFunction, ErrorFunction errorFunction)> GenericFunction;
|
||||||
|
|
||||||
|
// the preferred way to set a generic function:
|
||||||
|
virtual void setGenericCallback(DescribedBase* object, shared_ptr<GenericFunction> function) const = 0;
|
||||||
|
virtual void clearCallback(DescribedBase* object) const = 0;
|
||||||
|
|
||||||
|
// use this function if you don't have a shared_ptr:
|
||||||
|
void setGenericCallbackHelper(DescribedBase* object, const GenericFunction& function) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AsyncCallbackDescriptor(ClassDescriptor& classDescriptor, const char* name, Descriptor::Attributes attributes, Security::Permissions security);
|
||||||
|
|
||||||
|
static void callGenericImpl(shared_ptr<AsyncCallbackDescriptor::GenericFunction> function, shared_ptr<Tuple> args,
|
||||||
|
AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction);
|
||||||
|
|
||||||
|
template <typename Class, typename Function, typename Value>
|
||||||
|
void setGenericCallbackImpl(DescribedBase* object, Function Class::*member, void (Class::*onChanged)(const Function&), const Value& value) const
|
||||||
|
{
|
||||||
|
Class* c = static_cast<Class*>(object);
|
||||||
|
|
||||||
|
Function oldValue = c->*member;
|
||||||
|
c->*member = value;
|
||||||
|
if (onChanged)
|
||||||
|
(c->*onChanged)(oldValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// A light-weight convenience class that associates a CallbackDescriptor
|
||||||
|
// with a described object to create a "Callback"
|
||||||
|
class Callback
|
||||||
|
{
|
||||||
|
const CallbackDescriptor* descriptor;
|
||||||
|
DescribedBase* instance;
|
||||||
|
public:
|
||||||
|
inline Callback(const CallbackDescriptor& descriptor, DescribedBase* instance)
|
||||||
|
:descriptor(&descriptor),instance(instance)
|
||||||
|
{}
|
||||||
|
|
||||||
|
inline Callback(const Callback& other)
|
||||||
|
:descriptor(other.descriptor),instance(other.instance)
|
||||||
|
{}
|
||||||
|
|
||||||
|
inline Callback& operator =(const Callback& other)
|
||||||
|
{
|
||||||
|
this->descriptor = other.descriptor;
|
||||||
|
this->instance = other.instance;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const RBX::Name& getName() const {
|
||||||
|
return descriptor->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DescribedBase* getInstance() const
|
||||||
|
{
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const CallbackDescriptor& getDescriptor() const
|
||||||
|
{
|
||||||
|
return *descriptor;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Base class of typed CallbackDescriptors
|
||||||
|
template<typename Signature>
|
||||||
|
class SyncCallbackDesc : public SyncCallbackDescriptor
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
typedef typename boost::function<Signature> Function;
|
||||||
|
typedef typename boost::function_traits<Signature>::result_type result_type;
|
||||||
|
|
||||||
|
template<typename Result>
|
||||||
|
static typename boost::enable_if<boost::is_void<Result>, void>::type
|
||||||
|
callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function, shared_ptr<Tuple> args)
|
||||||
|
{
|
||||||
|
(*function)(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Result>
|
||||||
|
static typename boost::disable_if<boost::is_same<shared_ptr<const Tuple>, Result>, Result>::type
|
||||||
|
convertResult(shared_ptr<Reflection::Tuple> result)
|
||||||
|
{
|
||||||
|
// Extract the first value in the Tuple and return it as the result. Ignore other vales
|
||||||
|
if (result->values.size() == 0)
|
||||||
|
throw std::runtime_error("Callback did not return a value");
|
||||||
|
return result->values[0].convert<Result>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Result>
|
||||||
|
static typename boost::enable_if<boost::is_same<shared_ptr<const Tuple>, Result>, Result>::type
|
||||||
|
convertResult(shared_ptr<Reflection::Tuple> result)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Result>
|
||||||
|
static typename boost::disable_if<boost::is_void<Result>, Result>::type
|
||||||
|
callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function, shared_ptr<Tuple> args)
|
||||||
|
{
|
||||||
|
shared_ptr<Reflection::Tuple> result = (*function)(args);
|
||||||
|
return convertResult<Result>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
class RBXInterface ISetter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~ISetter() {}
|
||||||
|
virtual void setCallback(DescribedBase* object, const Function& value) const = 0;
|
||||||
|
};
|
||||||
|
boost::scoped_ptr<ISetter> setter;
|
||||||
|
|
||||||
|
SyncCallbackDesc(ClassDescriptor& classDescriptor, const char* name, Descriptor::Attributes attributes, Security::Permissions security):
|
||||||
|
SyncCallbackDescriptor(classDescriptor, name, attributes, security)
|
||||||
|
{}
|
||||||
|
public:
|
||||||
|
void setCallback(DescribedBase* object, const Function& value) const
|
||||||
|
{
|
||||||
|
setter->setCallback(object, value);
|
||||||
|
}
|
||||||
|
void clearCallback(DescribedBase* object) const
|
||||||
|
{
|
||||||
|
setter->setCallback(object, Function());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialized class that implements generic bindings and sets the signature
|
||||||
|
template <typename Signature, int arity>
|
||||||
|
class SyncCallbackDescImpl;
|
||||||
|
|
||||||
|
template<typename Signature>
|
||||||
|
class SyncCallbackDescImpl<Signature, 0> : public SyncCallbackDesc<Signature>
|
||||||
|
{
|
||||||
|
typedef typename SyncCallbackDesc<Signature>::result_type result_type;
|
||||||
|
static result_type callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function)
|
||||||
|
{
|
||||||
|
shared_ptr<Reflection::Tuple> args(new Tuple());
|
||||||
|
return SyncCallbackDesc<Signature>::template callGeneric<result_type>(function, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SyncCallbackDescImpl(ClassDescriptor& classDescriptor, const char* name, Descriptor::Attributes attributes, Security::Permissions security)
|
||||||
|
:SyncCallbackDesc<Signature>(classDescriptor, name, attributes, security)
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 0));
|
||||||
|
this->signature.resultType = &Type::singleton<result_type>();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
virtual void setGenericCallback(DescribedBase* object, shared_ptr<SyncCallbackDescriptor::GenericFunction> function) const
|
||||||
|
{
|
||||||
|
this->setCallback(object, boost::bind(callGeneric, function));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Signature>
|
||||||
|
class SyncCallbackDescImpl<Signature, 1> : public SyncCallbackDesc<Signature>
|
||||||
|
{
|
||||||
|
typedef typename SyncCallbackDesc<Signature>::result_type result_type;
|
||||||
|
static result_type callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function,
|
||||||
|
// TODO: Use const ref for args and bind with boost::cref?
|
||||||
|
typename boost::function_traits<Signature>::arg1_type arg1)
|
||||||
|
{
|
||||||
|
shared_ptr<Reflection::Tuple> args(new Tuple());
|
||||||
|
args->values.push_back(arg1);
|
||||||
|
return SyncCallbackDesc<Signature>::template callGeneric<result_type>(function, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SyncCallbackDescImpl(ClassDescriptor& classDescriptor, const char* name, const char* arg1name, Descriptor::Attributes attributes, Security::Permissions security)
|
||||||
|
:SyncCallbackDesc<Signature>(classDescriptor, name, attributes, security)
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 1));
|
||||||
|
this->signature.resultType = &Type::singleton<result_type>();
|
||||||
|
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
virtual void setGenericCallback(DescribedBase* object, shared_ptr<SyncCallbackDescriptor::GenericFunction> function) const
|
||||||
|
{
|
||||||
|
this->setCallback(object, boost::bind(callGeneric, function, _1));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Signature>
|
||||||
|
class SyncCallbackDescImpl<Signature, 2> : public SyncCallbackDesc<Signature>
|
||||||
|
{
|
||||||
|
typedef typename SyncCallbackDesc<Signature>::result_type result_type;
|
||||||
|
static result_type callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function,
|
||||||
|
typename boost::function_traits<Signature>::arg1_type arg1,
|
||||||
|
typename boost::function_traits<Signature>::arg2_type arg2)
|
||||||
|
{
|
||||||
|
shared_ptr<Reflection::Tuple> args(new Tuple());
|
||||||
|
args->values.push_back(arg1);
|
||||||
|
args->values.push_back(arg2);
|
||||||
|
return SyncCallbackDesc<Signature>::template callGeneric<result_type>(function, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SyncCallbackDescImpl(ClassDescriptor& classDescriptor, const char* name, const char* arg1name, const char* arg2name, Descriptor::Attributes attributes, Security::Permissions security)
|
||||||
|
:SyncCallbackDesc<Signature>(classDescriptor, name, attributes, security)
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 2));
|
||||||
|
this->signature.resultType = &Type::singleton<result_type>();
|
||||||
|
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
|
||||||
|
this->signature.addArgument(RBX::Name::declare(arg2name), Type::singleton<typename boost::function_traits<Signature>::arg2_type>());
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
virtual void setGenericCallback(DescribedBase* object, shared_ptr<SyncCallbackDescriptor::GenericFunction> function) const
|
||||||
|
{
|
||||||
|
this->setCallback(object, boost::bind(callGeneric, function, _1, _2));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Signature>
|
||||||
|
class SyncCallbackDescImpl<Signature, 3> : public SyncCallbackDesc<Signature>
|
||||||
|
{
|
||||||
|
typedef typename SyncCallbackDesc<Signature>::result_type result_type;
|
||||||
|
static result_type callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function,
|
||||||
|
typename boost::function_traits<Signature>::arg1_type arg1,
|
||||||
|
typename boost::function_traits<Signature>::arg2_type arg2,
|
||||||
|
typename boost::function_traits<Signature>::arg3_type arg3)
|
||||||
|
{
|
||||||
|
shared_ptr<Reflection::Tuple> args(new Tuple());
|
||||||
|
args->values.push_back(arg1);
|
||||||
|
args->values.push_back(arg2);
|
||||||
|
args->values.push_back(arg3);
|
||||||
|
return SyncCallbackDesc<Signature>::template callGeneric<result_type>(function, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SyncCallbackDescImpl(ClassDescriptor& classDescriptor, const char* name, const char* arg1name, const char* arg2name, const char* arg3name, Descriptor::Attributes attributes, Security::Permissions security)
|
||||||
|
:SyncCallbackDesc<Signature>(classDescriptor, name, attributes, security)
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 3));
|
||||||
|
this->signature.resultType = &Type::singleton<result_type>();
|
||||||
|
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
|
||||||
|
this->signature.addArgument(RBX::Name::declare(arg2name), Type::singleton<typename boost::function_traits<Signature>::arg2_type>());
|
||||||
|
this->signature.addArgument(RBX::Name::declare(arg3name), Type::singleton<typename boost::function_traits<Signature>::arg3_type>());
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
virtual void setGenericCallback(DescribedBase* object, shared_ptr<SyncCallbackDescriptor::GenericFunction> function) const
|
||||||
|
{
|
||||||
|
this->setCallback(object, boost::bind(callGeneric, function, _1, _2, _3));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Signature>
|
||||||
|
class SyncCallbackDescImpl<Signature, 4> : public SyncCallbackDesc<Signature>
|
||||||
|
{
|
||||||
|
typedef typename SyncCallbackDesc<Signature>::result_type result_type;
|
||||||
|
static result_type callGeneric(shared_ptr<SyncCallbackDescriptor::GenericFunction> function,
|
||||||
|
typename boost::function_traits<Signature>::arg1_type arg1,
|
||||||
|
typename boost::function_traits<Signature>::arg2_type arg2,
|
||||||
|
typename boost::function_traits<Signature>::arg3_type arg3,
|
||||||
|
typename boost::function_traits<Signature>::arg4_type arg4)
|
||||||
|
{
|
||||||
|
shared_ptr<Reflection::Tuple> args(new Tuple());
|
||||||
|
args->values.push_back(arg1);
|
||||||
|
args->values.push_back(arg2);
|
||||||
|
args->values.push_back(arg3);
|
||||||
|
args->values.push_back(arg4);
|
||||||
|
return SyncCallbackDesc<Signature>::template callGeneric<result_type>(function, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SyncCallbackDescImpl(ClassDescriptor& classDescriptor, const char* name, const char* arg1name, const char* arg2name, const char* arg3name, const char* arg4name, Descriptor::Attributes attributes, Security::Permissions security)
|
||||||
|
:SyncCallbackDesc<Signature>(classDescriptor, name, attributes, security)
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 4));
|
||||||
|
this->signature.resultType = &Type::singleton<result_type>();
|
||||||
|
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
|
||||||
|
this->signature.addArgument(RBX::Name::declare(arg2name), Type::singleton<typename boost::function_traits<Signature>::arg2_type>());
|
||||||
|
this->signature.addArgument(RBX::Name::declare(arg3name), Type::singleton<typename boost::function_traits<Signature>::arg3_type>());
|
||||||
|
this->signature.addArgument(RBX::Name::declare(arg4name), Type::singleton<typename boost::function_traits<Signature>::arg4_type>());
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
virtual void setGenericCallback(DescribedBase* object, shared_ptr<SyncCallbackDescriptor::GenericFunction> function) const
|
||||||
|
{
|
||||||
|
this->setCallback(object, boost::bind(callGeneric, function, _1, _2, _3, _4));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// The fully functional descriptor that binds to class members
|
||||||
|
template<typename Signature>
|
||||||
|
class BoundCallbackDesc : public SyncCallbackDescImpl<Signature, boost::function_traits<Signature>::arity>
|
||||||
|
{
|
||||||
|
typedef typename boost::function<Signature> Function;
|
||||||
|
|
||||||
|
template<class Class>
|
||||||
|
class Setter : public SyncCallbackDesc<Signature>::ISetter
|
||||||
|
{
|
||||||
|
typedef void (Class::*OnChanged)();
|
||||||
|
Function Class::*member;
|
||||||
|
OnChanged onChanged;
|
||||||
|
public:
|
||||||
|
Setter(Function Class::*member, OnChanged onChanged = NULL):member(member),onChanged(onChanged) {}
|
||||||
|
|
||||||
|
virtual void setCallback(DescribedBase* object, const Function& value) const
|
||||||
|
{
|
||||||
|
Class* c = static_cast<Class*>(object);
|
||||||
|
c->*member = value;
|
||||||
|
if (onChanged)
|
||||||
|
(c->*onChanged)();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
template<class Class>
|
||||||
|
BoundCallbackDesc(const char* name, Function Class::*member, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
:SyncCallbackDescImpl<Signature, 0>(Class::classDescriptor(), name, attributes, security)
|
||||||
|
{
|
||||||
|
this->setter.reset(new Setter<Class>(member));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Class>
|
||||||
|
BoundCallbackDesc(const char* name, Function Class::*member, void (Class::*onChanged)(), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
:SyncCallbackDescImpl<Signature, 0>(Class::classDescriptor(), name, attributes, security)
|
||||||
|
{
|
||||||
|
this->setter.reset(new Setter<Class>(member, onChanged));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Class>
|
||||||
|
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
:SyncCallbackDescImpl<Signature, 1>(Class::classDescriptor(), name, arg1name, attributes, security)
|
||||||
|
{
|
||||||
|
this->setter.reset(new Setter<Class>(member));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Class>
|
||||||
|
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, void (Class::*onChanged)(), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
:SyncCallbackDescImpl<Signature, 1>(Class::classDescriptor(), name, arg1name, attributes, security)
|
||||||
|
{
|
||||||
|
this->setter.reset(new Setter<Class>(member, onChanged));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Class>
|
||||||
|
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
:SyncCallbackDescImpl<Signature, 2>(Class::classDescriptor(), name, arg1name, arg2name, attributes, security)
|
||||||
|
{
|
||||||
|
this->setter.reset(new Setter<Class>(member));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Class>
|
||||||
|
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, void (Class::*onChanged)(), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
:SyncCallbackDescImpl<Signature, 2>(Class::classDescriptor(), name, arg1name, arg2name, attributes, security)
|
||||||
|
{
|
||||||
|
this->setter.reset(new Setter<Class>(member, onChanged));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Class>
|
||||||
|
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, const char* arg3name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
:SyncCallbackDescImpl<Signature, 3>(Class::classDescriptor(), name, arg1name, arg2name, arg3name, attributes, security)
|
||||||
|
{
|
||||||
|
this->setter.reset(new Setter<Class>(member));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Class>
|
||||||
|
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, const char* arg3name, void (Class::*onChanged)(), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
:SyncCallbackDescImpl<Signature, 3>(Class::classDescriptor(), name, arg1name, arg2name, arg3name, attributes, security)
|
||||||
|
{
|
||||||
|
this->setter.reset(new Setter<Class>(member, onChanged));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Class>
|
||||||
|
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, const char* arg3name, const char* arg4name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
:SyncCallbackDescImpl<Signature, 4>(Class::classDescriptor(), name, arg1name, arg2name, arg3name, arg4name, attributes, security)
|
||||||
|
{
|
||||||
|
this->setter.reset(new Setter<Class>(member));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Class>
|
||||||
|
BoundCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, const char* arg3name, const char* arg4name, void (Class::*onChanged)(), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
:SyncCallbackDescImpl<Signature, 4>(Class::classDescriptor(), name, arg1name, arg2name, arg3name, arg4name, attributes, security)
|
||||||
|
{
|
||||||
|
this->setter.reset(new Setter<Class>(member, onChanged));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Class, typename Signature, int arity = boost::function_traits<Signature>::arity>
|
||||||
|
class BoundAsyncCallbackDesc;
|
||||||
|
|
||||||
|
template <class Class, typename Signature>
|
||||||
|
class BoundAsyncCallbackDesc<Class, Signature, 0> : public AsyncCallbackDescriptor
|
||||||
|
{
|
||||||
|
typedef boost::function<void(AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)> Function;
|
||||||
|
|
||||||
|
static void callGeneric(shared_ptr<AsyncCallbackDescriptor::GenericFunction> function,
|
||||||
|
AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)
|
||||||
|
{
|
||||||
|
shared_ptr<Reflection::Tuple> args(new Tuple());
|
||||||
|
callGenericImpl(function, args, resumeFunction, errorFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void declareSignature()
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 0));
|
||||||
|
this->signature.resultType = &Type::singleton<typename boost::function_traits<Signature>::result_type>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Class::*member;
|
||||||
|
void (Class::*onChanged)(const Function&);
|
||||||
|
|
||||||
|
public:
|
||||||
|
BoundAsyncCallbackDesc(const char* name, Function Class::*member, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
|
||||||
|
, member(member)
|
||||||
|
, onChanged(NULL)
|
||||||
|
{
|
||||||
|
declareSignature();
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundAsyncCallbackDesc(const char* name, Function Class::*member, void (Class::*onChanged)(const Function&), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
|
||||||
|
, member(member)
|
||||||
|
, onChanged(onChanged)
|
||||||
|
{
|
||||||
|
declareSignature();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void setGenericCallback(DescribedBase* object, shared_ptr<AsyncCallbackDescriptor::GenericFunction> function) const
|
||||||
|
{
|
||||||
|
setGenericCallbackImpl(object, member, onChanged, boost::bind(callGeneric, function, _1, _2));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void clearCallback(DescribedBase* object) const
|
||||||
|
{
|
||||||
|
setGenericCallbackImpl(object, member, onChanged, Function());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Class, typename Signature>
|
||||||
|
class BoundAsyncCallbackDesc<Class, Signature, 1> : public AsyncCallbackDescriptor
|
||||||
|
{
|
||||||
|
typedef typename boost::function_traits<Signature>::arg1_type Arg1;
|
||||||
|
typedef boost::function<void(Arg1, AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)> Function;
|
||||||
|
|
||||||
|
static void callGeneric(shared_ptr<AsyncCallbackDescriptor::GenericFunction> function,
|
||||||
|
Arg1 arg1,
|
||||||
|
AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)
|
||||||
|
{
|
||||||
|
shared_ptr<Reflection::Tuple> args(new Tuple());
|
||||||
|
args->values.push_back(arg1);
|
||||||
|
callGenericImpl(function, args, resumeFunction, errorFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void declareSignature(const char* arg1name)
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 1));
|
||||||
|
this->signature.resultType = &Type::singleton<typename boost::function_traits<Signature>::result_type>();
|
||||||
|
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Class::*member;
|
||||||
|
void (Class::*onChanged)(const Function&);
|
||||||
|
|
||||||
|
public:
|
||||||
|
BoundAsyncCallbackDesc(const char* name, Function Class::*member, const char* arg1name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
|
||||||
|
, member(member)
|
||||||
|
, onChanged(NULL)
|
||||||
|
{
|
||||||
|
declareSignature(arg1name);
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundAsyncCallbackDesc(const char* name, Function Class::*member, const char* arg1name, void (Class::*onChanged)(const Function&), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
|
||||||
|
, member(member)
|
||||||
|
, onChanged(onChanged)
|
||||||
|
{
|
||||||
|
declareSignature(arg1name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void setGenericCallback(DescribedBase* object, shared_ptr<AsyncCallbackDescriptor::GenericFunction> function) const
|
||||||
|
{
|
||||||
|
setGenericCallbackImpl(object, member, onChanged, boost::bind(callGeneric, function, _1, _2, _3));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void clearCallback(DescribedBase* object) const
|
||||||
|
{
|
||||||
|
setGenericCallbackImpl(object, member, onChanged, Function());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Class, typename Signature>
|
||||||
|
class BoundAsyncCallbackDesc<Class, Signature, 2> : public AsyncCallbackDescriptor
|
||||||
|
{
|
||||||
|
typedef typename boost::function_traits<Signature>::arg1_type Arg1;
|
||||||
|
typedef typename boost::function_traits<Signature>::arg2_type Arg2;
|
||||||
|
typedef boost::function<void(Arg1, Arg2, AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)> Function;
|
||||||
|
|
||||||
|
static void callGeneric(shared_ptr<AsyncCallbackDescriptor::GenericFunction> function,
|
||||||
|
Arg1 arg1,
|
||||||
|
Arg2 arg2,
|
||||||
|
AsyncCallbackDescriptor::ResumeFunction resumeFunction, AsyncCallbackDescriptor::ErrorFunction errorFunction)
|
||||||
|
{
|
||||||
|
shared_ptr<Reflection::Tuple> args(new Tuple());
|
||||||
|
args->values.push_back(arg1);
|
||||||
|
args->values.push_back(arg2);
|
||||||
|
callGenericImpl(function, args, resumeFunction, errorFunction);
|
||||||
|
}
|
||||||
|
|
||||||
|
void declareSignature(const char* arg1name, const char* arg2name)
|
||||||
|
{
|
||||||
|
BOOST_STATIC_ASSERT((boost::function_traits<Signature>::arity == 2));
|
||||||
|
this->signature.resultType = &Type::singleton<typename boost::function_traits<Signature>::result_type>();
|
||||||
|
this->signature.addArgument(RBX::Name::declare(arg1name), Type::singleton<typename boost::function_traits<Signature>::arg1_type>());
|
||||||
|
this->signature.addArgument(RBX::Name::declare(arg2name), Type::singleton<typename boost::function_traits<Signature>::arg2_type>());
|
||||||
|
}
|
||||||
|
|
||||||
|
Function Class::*member;
|
||||||
|
void (Class::*onChanged)(const Function&);
|
||||||
|
|
||||||
|
public:
|
||||||
|
BoundAsyncCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
|
||||||
|
, member(member)
|
||||||
|
, onChanged(NULL)
|
||||||
|
{
|
||||||
|
declareSignature(arg1name, arg2name);
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundAsyncCallbackDesc(const char* name, Function Class::*member, const char* arg1name, const char* arg2name, void (Class::*onChanged)(const Function&), Security::Permissions security = Security::None, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
: AsyncCallbackDescriptor(Class::classDescriptor(), name, attributes, security)
|
||||||
|
, member(member)
|
||||||
|
, onChanged(onChanged)
|
||||||
|
{
|
||||||
|
declareSignature(arg1name, arg2name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual void setGenericCallback(DescribedBase* object, shared_ptr<AsyncCallbackDescriptor::GenericFunction> function) const
|
||||||
|
{
|
||||||
|
setGenericCallbackImpl(object, member, onChanged, boost::bind(callGeneric, function, _1, _2, _3, _4));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void clearCallback(DescribedBase* object) const
|
||||||
|
{
|
||||||
|
setGenericCallbackImpl(object, member, onChanged, Function());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "util/Name.h"
|
||||||
|
#include "boost/utility.hpp"
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
namespace Reflection
|
||||||
|
{
|
||||||
|
class Descriptor : public boost::noncopyable
|
||||||
|
{
|
||||||
|
|
||||||
|
static void checkLockedDown()
|
||||||
|
{
|
||||||
|
// If this following assertion fails then you need to put your class
|
||||||
|
// into FactoryRegistrator::FactoryRegistrator() or somewhere else.
|
||||||
|
// Failure of this test is so severe that we want to catch it in production, too.
|
||||||
|
if (lockedDown)
|
||||||
|
RBXCRASH();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
struct Attributes
|
||||||
|
{
|
||||||
|
bool isDeprecated;
|
||||||
|
const Descriptor* preferred; // used if isDeprecated
|
||||||
|
Attributes()
|
||||||
|
:isDeprecated(false)
|
||||||
|
,preferred(NULL)
|
||||||
|
{}
|
||||||
|
static Attributes deprecated(const Descriptor& preferred)
|
||||||
|
{
|
||||||
|
Attributes result;
|
||||||
|
result.isDeprecated = true;
|
||||||
|
result.preferred = &preferred;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
static Attributes deprecated()
|
||||||
|
{
|
||||||
|
Attributes result;
|
||||||
|
result.isDeprecated = true;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool lockedDown; // After the first instance of a described class is created we cannot modify the reflection database
|
||||||
|
|
||||||
|
const RBX::Name& name;
|
||||||
|
scoped_ptr<bool> isReplicable;
|
||||||
|
scoped_ptr<bool> isOutdated;
|
||||||
|
const Attributes attributes;
|
||||||
|
|
||||||
|
Descriptor(const char* name, Attributes attributes)
|
||||||
|
:name(RBX::Name::declare(name))
|
||||||
|
,attributes(attributes)
|
||||||
|
,isReplicable(new bool(false))
|
||||||
|
,isOutdated(new bool(false))
|
||||||
|
{
|
||||||
|
checkLockedDown();
|
||||||
|
RBXASSERT(!this->name.empty());
|
||||||
|
}
|
||||||
|
Descriptor(const RBX::Name& name, Attributes attributes)
|
||||||
|
:name(name)
|
||||||
|
,attributes(attributes)
|
||||||
|
,isReplicable(new bool(false))
|
||||||
|
,isOutdated(new bool(false))
|
||||||
|
{
|
||||||
|
checkLockedDown();
|
||||||
|
RBXASSERT(!this->name.empty());
|
||||||
|
}
|
||||||
|
virtual ~Descriptor() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,375 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "reflection/Type.h"
|
||||||
|
#include "util/utilities.h"
|
||||||
|
#include "util/math.h"
|
||||||
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/unordered_map.hpp>
|
||||||
|
#include <boost/thread/once.hpp>
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
|
||||||
|
namespace Reflection {
|
||||||
|
|
||||||
|
class EnumDescriptor : public Type
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::vector< const EnumDescriptor* >::const_iterator enumsBegin();
|
||||||
|
static std::vector< const EnumDescriptor* >::const_iterator enumsEnd();
|
||||||
|
static size_t allEnumSize() {return allEnums().size();}
|
||||||
|
|
||||||
|
class Item : public Descriptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const EnumDescriptor& owner;
|
||||||
|
const int value; // value of the enum
|
||||||
|
const size_t index; // place in ordered enum values (0<=index<enumCount)
|
||||||
|
Item(const char* name, Descriptor::Attributes attributes, int value, size_t index, const EnumDescriptor& owner)
|
||||||
|
:Descriptor(name, attributes)
|
||||||
|
,value(value)
|
||||||
|
,index(index)
|
||||||
|
,owner(owner)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
bool convertToValue(Variant& value) const
|
||||||
|
{
|
||||||
|
return owner.convertToValue(index, value);
|
||||||
|
}
|
||||||
|
bool convertToString(std::string& value) const
|
||||||
|
{
|
||||||
|
return owner.convertToString(index, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
typedef boost::unordered_map<const RBX::Name*, const EnumDescriptor*> EnumNameTable;
|
||||||
|
#else
|
||||||
|
typedef std::map<const RBX::Name*, const EnumDescriptor*> EnumNameTable;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
static EnumNameTable& allEnumsNameLookup();
|
||||||
|
static std::vector<const EnumDescriptor*>& allEnums();
|
||||||
|
|
||||||
|
static bool equalValue(const Item* item, int intValue)
|
||||||
|
{
|
||||||
|
return item->value == intValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int count;
|
||||||
|
protected:
|
||||||
|
std::vector< const Item* > allItems;
|
||||||
|
size_t enumCount;
|
||||||
|
size_t enumCountMSB;
|
||||||
|
EnumDescriptor(const char* typeName);
|
||||||
|
~EnumDescriptor();
|
||||||
|
public:
|
||||||
|
size_t getEnumCount() const { return enumCount; }
|
||||||
|
size_t getEnumCountMSB() const { return enumCountMSB; }
|
||||||
|
std::vector< const Item* >::const_iterator begin() const {
|
||||||
|
return allItems.begin();
|
||||||
|
}
|
||||||
|
std::vector< const Item* >::const_iterator end() const {
|
||||||
|
return allItems.end();
|
||||||
|
}
|
||||||
|
static const EnumDescriptor* lookupDescriptor(const RBX::Name& name) {
|
||||||
|
EnumNameTable::const_iterator iter = allEnumsNameLookup().find(&name);
|
||||||
|
if (iter!=allEnumsNameLookup().end())
|
||||||
|
return iter->second;
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
static const EnumDescriptor* lookupDescriptor(const Type& type) {
|
||||||
|
if (type.isEnum)
|
||||||
|
return static_cast<const EnumDescriptor*>(&type);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValue(int intValue) const {
|
||||||
|
return std::find_if(allItems.begin(), allItems.end(), boost::bind(&equalValue, _1, intValue)) != allItems.end();
|
||||||
|
}
|
||||||
|
virtual const Item* lookup(const char* text) const = 0;
|
||||||
|
virtual const Item* lookup(const Variant& value) const = 0;
|
||||||
|
virtual bool convertToValue(size_t index, Variant& value) const = 0;
|
||||||
|
virtual bool convertToString(size_t index, std::string& value) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A thread-safe singleton!
|
||||||
|
template<typename T>
|
||||||
|
class Singleton : boost::noncopyable
|
||||||
|
{
|
||||||
|
static T& doGetSingleton()
|
||||||
|
{
|
||||||
|
static T s;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
static void initSingleton()
|
||||||
|
{
|
||||||
|
doGetSingleton();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
static T& singleton()
|
||||||
|
{
|
||||||
|
static boost::once_flag flag = BOOST_ONCE_INIT;
|
||||||
|
boost::call_once(&initSingleton, flag);
|
||||||
|
return doGetSingleton();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Enum> class EnumRegistrar;
|
||||||
|
|
||||||
|
template<typename Enum>
|
||||||
|
class EnumDesc : public EnumDescriptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
friend class Singleton<const EnumDesc<Enum> >;
|
||||||
|
static const EnumDesc& singleton()
|
||||||
|
{
|
||||||
|
return Singleton<const EnumDesc<Enum> >::singleton();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// You must implement the following constructor for each EnumDesc that you define
|
||||||
|
EnumDesc();
|
||||||
|
~EnumDesc()
|
||||||
|
{
|
||||||
|
// Force linking of EnumRegistrar<Enum>, which will force clients
|
||||||
|
// of this library to define EnumRegistrar<Enum>::registrar in
|
||||||
|
// their startup code.
|
||||||
|
|
||||||
|
|
||||||
|
Reflection::EnumRegistrar<Enum>::registrar.dummy();
|
||||||
|
|
||||||
|
std::for_each(allItems.begin(), allItems.end(), &del_fun<const Item>);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<const RBX::Name*, Enum> nameToEnum;
|
||||||
|
std::map<const RBX::Name*, Enum> nameToEnumLegacy;
|
||||||
|
std::vector< const RBX::Name* > enumToName; // maps enum to Name (there may be gaps)
|
||||||
|
|
||||||
|
std::vector< std::string > enumToString; // maps enum to String (there may be gaps)
|
||||||
|
std::vector< const Item* > enumToItem; // maps enum to Item (there may be gaps)
|
||||||
|
|
||||||
|
std::vector< Enum > intToEnum; // maps legacy values to proper enum
|
||||||
|
std::vector< Enum > indexToEnum;
|
||||||
|
std::vector< size_t > enumToIndex; // maps enum to Index (there may be gaps)
|
||||||
|
|
||||||
|
|
||||||
|
// Used in constructor
|
||||||
|
void addPair(Enum value, const char* name, Descriptor::Attributes attributes = Descriptor::Attributes())
|
||||||
|
{
|
||||||
|
RBXASSERT_VERY_FAST(value >= 0);
|
||||||
|
// No spaces in enums:
|
||||||
|
RBXASSERT_VERY_FAST(std::string(name).find(' ') == std::string::npos);
|
||||||
|
// No no CamelCase in enums:
|
||||||
|
RBXASSERT_VERY_FAST(!isCamel(name));
|
||||||
|
|
||||||
|
const Item* item = new Item(name, attributes, value, enumCount, *this);
|
||||||
|
|
||||||
|
allItems.push_back(item);
|
||||||
|
|
||||||
|
if (intToEnum.size()<=(size_t)value)
|
||||||
|
intToEnum.resize(value+1, (Enum)-1);
|
||||||
|
intToEnum[value] = value;
|
||||||
|
|
||||||
|
RBXASSERT(value>=0);
|
||||||
|
|
||||||
|
if (enumToIndex.size()<=(size_t)value)
|
||||||
|
enumToIndex.resize(value+1, -1);
|
||||||
|
enumToIndex[value] = enumCount;
|
||||||
|
indexToEnum.push_back(value);
|
||||||
|
|
||||||
|
if (enumToName.size()<=(size_t)value)
|
||||||
|
enumToName.resize(value+1, &RBX::Name::getNullName());
|
||||||
|
enumToName[value] = &item->name;
|
||||||
|
|
||||||
|
if (enumToString.size()<=(size_t)value)
|
||||||
|
enumToString.resize(value+1);
|
||||||
|
enumToString[value] = name;
|
||||||
|
|
||||||
|
if (enumToItem.size()<=(size_t)value)
|
||||||
|
enumToItem.resize(value+1);
|
||||||
|
enumToItem[value] = item;
|
||||||
|
|
||||||
|
nameToEnum[&item->name] = value;
|
||||||
|
|
||||||
|
enumCount++;
|
||||||
|
enumCountMSB = Math::computeMSB(enumCount);
|
||||||
|
}
|
||||||
|
void addLegacy(int oldValue, const char* name, Enum value)
|
||||||
|
{
|
||||||
|
RBXASSERT_VERY_FAST(value >= 0);
|
||||||
|
|
||||||
|
if (intToEnum.size()<=(size_t)oldValue)
|
||||||
|
intToEnum.resize(oldValue+1, (Enum)-1);
|
||||||
|
intToEnum[oldValue] = value;
|
||||||
|
nameToEnumLegacy[&RBX::Name::declare(name)] = value;
|
||||||
|
}
|
||||||
|
void addLegacyName(const char* name, Enum value)
|
||||||
|
{
|
||||||
|
nameToEnumLegacy[&RBX::Name::declare(name)] = value;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
const RBX::Name& convertToName(const Enum& value) const
|
||||||
|
{
|
||||||
|
RBXASSERT(value>=0);
|
||||||
|
RBXASSERT(value<enumToItem.size());
|
||||||
|
if (value<0)
|
||||||
|
return RBX::Name::getNullName();
|
||||||
|
if ((size_t)value>=enumToName.size())
|
||||||
|
return RBX::Name::getNullName();
|
||||||
|
|
||||||
|
return *enumToName[value];
|
||||||
|
}
|
||||||
|
std::string convertToString(const Enum& value) const
|
||||||
|
{
|
||||||
|
RBXASSERT(value>=0);
|
||||||
|
RBXASSERT((size_t)value<enumToItem.size());
|
||||||
|
if (value<0)
|
||||||
|
return "";
|
||||||
|
if ((size_t)value>=enumToString.size())
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return enumToString[value];
|
||||||
|
}
|
||||||
|
const Item* convertToItem(const Enum& value) const
|
||||||
|
{
|
||||||
|
RBXASSERT(value>=0);
|
||||||
|
RBXASSERT((size_t)value<enumToItem.size());
|
||||||
|
if (value<0)
|
||||||
|
return NULL;
|
||||||
|
if ((size_t)value>=enumToItem.size())
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return enumToItem[value];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mapIntValue(int intValue, Enum& value) const
|
||||||
|
{
|
||||||
|
if (intValue < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if ((size_t)intValue >= intToEnum.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
value = intToEnum[intValue];
|
||||||
|
if ((int)value == -1)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool convertToValue(const RBX::Name& name, Enum& value) const
|
||||||
|
{
|
||||||
|
typename std::map<const RBX::Name*, Enum>::const_iterator iter = nameToEnum.find(&name);
|
||||||
|
if (iter!=nameToEnum.end()) {
|
||||||
|
value = iter->second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter = nameToEnumLegacy.find(&name);
|
||||||
|
if (iter!=nameToEnumLegacy.end()) {
|
||||||
|
value = iter->second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/*implement*/ const Item* lookup(const char* text) const
|
||||||
|
{
|
||||||
|
Enum e;
|
||||||
|
if (convertToValue(RBX::Name::lookup(text), e))
|
||||||
|
return convertToItem(e);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*implement*/ const Item* lookup(const Variant& value) const
|
||||||
|
{
|
||||||
|
return convertToItem(value.cast<Enum>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/*implement*/ bool convertToValue(size_t index, Variant& value) const
|
||||||
|
{
|
||||||
|
Enum enumValue;
|
||||||
|
bool result = convertToValue(index, enumValue);
|
||||||
|
value = enumValue;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
/*implement*/ bool convertToString(size_t index, std::string& stringValue) const
|
||||||
|
{
|
||||||
|
Enum enumValue;
|
||||||
|
if(convertToValue(index, enumValue)){
|
||||||
|
stringValue = convertToString(enumValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool convertToValue(const char* text, Enum& value) const
|
||||||
|
{
|
||||||
|
return convertToValue(RBX::Name::lookup(text), value);
|
||||||
|
}
|
||||||
|
size_t convertToIndex(Enum value) const
|
||||||
|
{
|
||||||
|
RBXASSERT(value>=0);
|
||||||
|
if ((size_t)value<enumToIndex.size())
|
||||||
|
return enumToIndex[value];
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
bool convertToValue(size_t index, Enum& value) const
|
||||||
|
{
|
||||||
|
if (index<enumCount) {
|
||||||
|
value = indexToEnum[index];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper macro
|
||||||
|
// GCC does not generate the registrar variable defination & fails at Link Time. Force Construct by passing in an dummy arg to ctor. That works. WEIRD huh?
|
||||||
|
#define RBX_REGISTER_ENUM(Enum) namespace RBX { namespace Reflection { \
|
||||||
|
template<> \
|
||||||
|
const Type& Type::getSingleton<Enum>() \
|
||||||
|
{ \
|
||||||
|
return EnumDesc<Enum>::singleton(); \
|
||||||
|
} \
|
||||||
|
template<> EnumRegistrar<Enum> EnumRegistrar<Enum>::registrar(0); \
|
||||||
|
template<> TypeRegistrar<Enum> TypeRegistrar<Enum>::registrar(0); \
|
||||||
|
}}
|
||||||
|
|
||||||
|
// This class is intended to prevent clients of the library
|
||||||
|
// from forgetting to initialize the enum descriptor
|
||||||
|
template<typename Enum>
|
||||||
|
class EnumRegistrar : boost::noncopyable
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
|
||||||
|
//// GCC does not generate the registrar variable defination & fails at Link Time. Force Construct by passing in an dummy arg to ctor. That works. WEIRD huh?
|
||||||
|
EnumRegistrar(int i):x(i)
|
||||||
|
{
|
||||||
|
// This call registers the enum descriptor
|
||||||
|
// in the reflection database
|
||||||
|
EnumDesc<Enum>::singleton();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
void dummy()
|
||||||
|
{
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The instantiation of this static member must be in a unit
|
||||||
|
// that is initialized in the main thread before any objects
|
||||||
|
// are created. Otherwise the reflection database
|
||||||
|
// can change at runtime, which would be a disaster
|
||||||
|
static EnumRegistrar registrar;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,108 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "reflection/type.h"
|
||||||
|
#include "security/securitycontext.h"
|
||||||
|
#include "reflection/member.h"
|
||||||
|
#include "util/G3DCore.h"
|
||||||
|
#include "util/Region3.h"
|
||||||
|
#include "util/Region3Int16.h"
|
||||||
|
|
||||||
|
struct lua_State;
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
namespace Reflection
|
||||||
|
{
|
||||||
|
class Function;
|
||||||
|
class EnumDescriptor;
|
||||||
|
|
||||||
|
// Base that describes a Function
|
||||||
|
class RBXBaseClass FunctionDescriptor : public MemberDescriptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Kind
|
||||||
|
{
|
||||||
|
Kind_Default,
|
||||||
|
Kind_Custom
|
||||||
|
};
|
||||||
|
|
||||||
|
class RBXInterface Arguments
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Variant returnValue;
|
||||||
|
|
||||||
|
virtual size_t size() const = 0;
|
||||||
|
// Place the value for the requested parameter in "value".
|
||||||
|
//
|
||||||
|
// index: 1-based index into the argument list
|
||||||
|
// returns: true if the index contains a valid argument
|
||||||
|
// value: the value to set. the function returns false then value is unchanged
|
||||||
|
virtual bool getVariant(int index, Variant& value) const = 0;
|
||||||
|
virtual bool getBool(int index, bool& value) const = 0;
|
||||||
|
virtual bool getLong(int index, long& value) const = 0;
|
||||||
|
virtual bool getDouble(int index, double& value) const = 0;
|
||||||
|
virtual bool getString(int index, std::string& value) const = 0;
|
||||||
|
virtual bool getVector3int16(int index, Vector3int16& value) const = 0;
|
||||||
|
virtual bool getRegion3int16(int index, Region3int16& value) const = 0;
|
||||||
|
virtual bool getVector3(int index, Vector3& value) const = 0;
|
||||||
|
virtual bool getRegion3(int index, Region3& value) const = 0;
|
||||||
|
virtual bool getRect(int index, Rect2D& value) const = 0;
|
||||||
|
virtual bool getObject(int index, shared_ptr<DescribedBase>& value) const = 0;
|
||||||
|
virtual bool getEnum(int index, const EnumDescriptor& desc, int& value) const = 0;
|
||||||
|
};
|
||||||
|
typedef Function ConstMember;
|
||||||
|
typedef Function Member;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SignatureDescriptor signature;
|
||||||
|
Kind kind;
|
||||||
|
FunctionDescriptor(ClassDescriptor& classDescriptor, const char* name, Security::Permissions security, Attributes attributes);
|
||||||
|
|
||||||
|
public:
|
||||||
|
const SignatureDescriptor& getSignature() const { return signature; }
|
||||||
|
|
||||||
|
Kind getKind() const { return kind; }
|
||||||
|
|
||||||
|
virtual int executeCustom(DescribedBase* instance, lua_State*) const { return 0; }
|
||||||
|
|
||||||
|
virtual void execute(DescribedBase* instance, Arguments& arguments) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// A light-weight convenience class that associates a FunctionDescriptor
|
||||||
|
// with a described object to create a "Function"
|
||||||
|
class Function
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
const FunctionDescriptor* descriptor;
|
||||||
|
DescribedBase* instance;
|
||||||
|
public:
|
||||||
|
inline Function(const FunctionDescriptor& descriptor, DescribedBase* instance)
|
||||||
|
:descriptor(&descriptor),instance(instance)
|
||||||
|
{}
|
||||||
|
|
||||||
|
inline Function(const Function& other)
|
||||||
|
:descriptor(other.descriptor),instance(other.instance)
|
||||||
|
{}
|
||||||
|
inline Function& operator =(const Function& other)
|
||||||
|
{
|
||||||
|
this->descriptor = other.descriptor;
|
||||||
|
this->instance = other.instance;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const RBX::Name& getName() const {
|
||||||
|
return descriptor->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const FunctionDescriptor* getDescriptor() const {
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute(FunctionDescriptor::Arguments& arguments) const {
|
||||||
|
return descriptor->execute(const_cast<DescribedBase*>(instance), arguments);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,337 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "reflection/Property.h"
|
||||||
|
#include "reflection/Function.h"
|
||||||
|
#include "reflection/YieldFunction.h"
|
||||||
|
#include "Reflection/Event.h"
|
||||||
|
#include "reflection/Callback.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include "boost/crc.hpp"
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
namespace Reflection
|
||||||
|
{
|
||||||
|
enum ReplicationLevel{
|
||||||
|
NEVER_REPLICATE = 0, //Never replicate this object
|
||||||
|
STANDARD_REPLICATE= 1, //Replicate to/from server according to standard rules
|
||||||
|
PLAYER_REPLICATE = 2, //Replicate changes to/from the "player" who owns this object
|
||||||
|
} ;
|
||||||
|
|
||||||
|
class ClassDescriptor
|
||||||
|
: public Descriptor
|
||||||
|
, public MemberDescriptorContainer<PropertyDescriptor>
|
||||||
|
, public MemberDescriptorContainer<EventDescriptor>
|
||||||
|
, public MemberDescriptorContainer<FunctionDescriptor>
|
||||||
|
, public MemberDescriptorContainer<YieldFunctionDescriptor>
|
||||||
|
, public MemberDescriptorContainer<CallbackDescriptor>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::vector<ClassDescriptor*> ClassDescriptors;
|
||||||
|
|
||||||
|
enum Functionality{
|
||||||
|
PERSISTENT = 0x1 + 0x2 + 0x8 + 0x10, // isPublic, Replicate, canXmlWrite, isScriptable
|
||||||
|
PERSISTENT_PLAYER = 0x1 + 0x4 + 0x8 + 0x10, // isPublic, ReplicatePlayer, canXmlWrite, isScriptable
|
||||||
|
PERSISTENT_LOCAL = 0x1 + 0x0 + 0x8 + 0x10, // isPublic, canXmlWrite, isScriptable
|
||||||
|
RUNTIME = 0x1 + 0x2 + 0x0 + 0x10, // isPublic, Replicate, isScriptable
|
||||||
|
RUNTIME_PLAYER = 0x1 + 0x4 + 0x0 + 0x10, // isPublic, ReplicatePlayer, isScriptable
|
||||||
|
RUNTIME_LOCAL = 0x1 + 0x0 + 0x0 + 0x10, // isPublic, isScriptable
|
||||||
|
INTERNAL = 0x1 + 0x2 + 0x0 + 0x0, // isPublic, Replicate
|
||||||
|
INTERNAL_PLAYER = 0x1 + 0x4 + 0x0 + 0x0, // isPublic, ReplicatePlayer,
|
||||||
|
INTERNAL_LOCAL = 0x1 + 0x0 + 0x0 + 0x0, // isPublic
|
||||||
|
PERSISTENT_HIDDEN = 0x1 + 0x2 + 0x8 + 0x0, // isPublic, Replicate, canXmlWrite
|
||||||
|
PERSISTENT_LOCAL_INTERNAL = 0x1 + 0x0 + 0x8 + 0x0, // isPublic, canXmlWrite
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Attributes : public Descriptor::Attributes
|
||||||
|
{
|
||||||
|
Functionality flags;
|
||||||
|
|
||||||
|
Attributes(Functionality flags):flags(flags) {}
|
||||||
|
static Attributes deprecated(Functionality flags, const ClassDescriptor* preferred);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Security::Permissions security;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ClassDescriptor();
|
||||||
|
static ClassDescriptors& allClasses();
|
||||||
|
|
||||||
|
ClassDescriptors derivedClasses;
|
||||||
|
ClassDescriptor* const base;
|
||||||
|
const unsigned bReplicateType : 2;
|
||||||
|
const unsigned bCanXmlWrite : 1;
|
||||||
|
const unsigned bIsScriptable : 1;
|
||||||
|
|
||||||
|
static int count;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ClassDescriptor(ClassDescriptor& base, const char* name, Attributes attributes, Security::Permissions security);
|
||||||
|
~ClassDescriptor() { count--; }
|
||||||
|
|
||||||
|
const ClassDescriptor* getBase() const { return base; }
|
||||||
|
|
||||||
|
bool isBaseOf(const ClassDescriptor& child) const;
|
||||||
|
bool isA(const ClassDescriptor& test) const;
|
||||||
|
|
||||||
|
bool isBaseOf(const char* childName) const;
|
||||||
|
bool isA(const char* testName) const;
|
||||||
|
|
||||||
|
inline ReplicationLevel getReplicationLevel() const { return (ReplicationLevel)bReplicateType; }
|
||||||
|
inline bool isScriptCreatable() const { return bIsScriptable != 0; }
|
||||||
|
inline bool isSerializable() const { return bCanXmlWrite != 0; }
|
||||||
|
|
||||||
|
// The root ClassDescriptor of all other Descriptors
|
||||||
|
static ClassDescriptor& rootDescriptor()
|
||||||
|
{
|
||||||
|
static ClassDescriptor root;
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Class enumeration
|
||||||
|
static ClassDescriptors::const_iterator all_begin() {
|
||||||
|
return allClasses().begin();
|
||||||
|
}
|
||||||
|
static ClassDescriptors::const_iterator all_end() {
|
||||||
|
return allClasses().end();
|
||||||
|
}
|
||||||
|
static size_t all_size()
|
||||||
|
{
|
||||||
|
return allClasses().size();
|
||||||
|
}
|
||||||
|
static unsigned int checksum();
|
||||||
|
static unsigned int checksum(const PropertyDescriptor* t, boost::crc_32_type& result);
|
||||||
|
static unsigned int checksum(const EventDescriptor* t, boost::crc_32_type& result);
|
||||||
|
static unsigned int checksum(const ClassDescriptor* t, boost::crc_32_type& result);
|
||||||
|
static unsigned int checksum(const Type* t, boost::crc_32_type& result);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Derived Class enumeration
|
||||||
|
ClassDescriptors::const_iterator derivedClasses_begin() const {
|
||||||
|
return derivedClasses.begin();
|
||||||
|
}
|
||||||
|
ClassDescriptors::const_iterator derivedClasses_end() const {
|
||||||
|
return derivedClasses.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Convenience functions for enumerating and querying members of a Class
|
||||||
|
PropertyDescriptor* findPropertyDescriptor(const char* name) const
|
||||||
|
{
|
||||||
|
return MemberDescriptorContainer<PropertyDescriptor>::findDescriptor(name);
|
||||||
|
}
|
||||||
|
FunctionDescriptor* findFunctionDescriptor(const char* name) const
|
||||||
|
{
|
||||||
|
return MemberDescriptorContainer<FunctionDescriptor>::findDescriptor(name);
|
||||||
|
}
|
||||||
|
YieldFunctionDescriptor* findYieldFunctionDescriptor(const char* name) const
|
||||||
|
{
|
||||||
|
return MemberDescriptorContainer<YieldFunctionDescriptor>::findDescriptor(name);
|
||||||
|
}
|
||||||
|
EventDescriptor* findEventDescriptor(const char* name) const
|
||||||
|
{
|
||||||
|
return MemberDescriptorContainer<EventDescriptor>::findDescriptor(name);
|
||||||
|
}
|
||||||
|
CallbackDescriptor* findCallbackDescriptor(const char* name) const
|
||||||
|
{
|
||||||
|
return MemberDescriptorContainer<CallbackDescriptor>::findDescriptor(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
typename MemberDescriptorContainer<T>::Collection::const_iterator begin() const {
|
||||||
|
return MemberDescriptorContainer<T>::descriptors_begin();
|
||||||
|
}
|
||||||
|
template<class T>
|
||||||
|
typename MemberDescriptorContainer<T>::Collection::const_iterator end() const {
|
||||||
|
return MemberDescriptorContainer<T>::descriptors_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const ClassDescriptor& other) const;
|
||||||
|
bool operator!=(const ClassDescriptor& other) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convenience typedefs:
|
||||||
|
typedef MemberDescriptorContainer<PropertyDescriptor>::ConstIterator ConstPropertyIterator;
|
||||||
|
typedef MemberDescriptorContainer<PropertyDescriptor>::Iterator PropertyIterator;
|
||||||
|
typedef MemberDescriptorContainer<FunctionDescriptor>::ConstIterator FunctionIterator;
|
||||||
|
typedef MemberDescriptorContainer<YieldFunctionDescriptor>::ConstIterator YieldFunctionIterator;
|
||||||
|
typedef MemberDescriptorContainer<EventDescriptor>::ConstIterator ConstSignalIterator;
|
||||||
|
typedef MemberDescriptorContainer<EventDescriptor>::Iterator SignalIterator;
|
||||||
|
typedef MemberDescriptorContainer<CallbackDescriptor>::Iterator CallbackIterator;
|
||||||
|
|
||||||
|
// The base class of any class that supports Reflection
|
||||||
|
class RBXBaseClass DescribedBase
|
||||||
|
: public EventSource
|
||||||
|
, public boost::enable_shared_from_this<DescribedBase>
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
// Each instance has a reference to it's most-specific ClassDescriptor:
|
||||||
|
const ClassDescriptor* descriptor;
|
||||||
|
boost::scoped_ptr<std::string> xmlId;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// The ClassDescriptor for this base class
|
||||||
|
static ClassDescriptor& classDescriptor()
|
||||||
|
{
|
||||||
|
return ClassDescriptor::rootDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
DescribedBase()
|
||||||
|
{
|
||||||
|
Descriptor::lockedDown = true; // See Descriptor::checkLockedDown() for an explanation
|
||||||
|
|
||||||
|
// By default, each DescribedBase has a null ClassDescriptor
|
||||||
|
this->descriptor = &classDescriptor();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~DescribedBase()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const ClassDescriptor& getDescriptor() const { return *descriptor; };
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
inline bool isA() const
|
||||||
|
{
|
||||||
|
return getDescriptor().isA(T::classDescriptor());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
static inline bool isA(const DescribedBase* instance)
|
||||||
|
{
|
||||||
|
return instance ? instance->getDescriptor().isA(T::classDescriptor()) : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is slower than the others
|
||||||
|
bool isA(std::string className)
|
||||||
|
{
|
||||||
|
return getDescriptor().isA(className.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular dynamic_casts are very slow. These faster versions uses our reflection framework to determine type then uses static_cast for speed.
|
||||||
|
// Use these functions to replace dynamic_casts for classes that derives from DescribedCreatable or DescribedNonCreatable.
|
||||||
|
template<class T>
|
||||||
|
inline T* fastDynamicCast()
|
||||||
|
{
|
||||||
|
return (getDescriptor().isA(T::classDescriptor())) ? static_cast<T*>(this) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
inline const T* fastDynamicCast() const
|
||||||
|
{
|
||||||
|
return (getDescriptor().isA(T::classDescriptor())) ? static_cast<const T*>(this) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
static inline T* fastDynamicCast(DescribedBase* instance)
|
||||||
|
{
|
||||||
|
return (instance && instance->getDescriptor().isA(T::classDescriptor())) ? static_cast<T*>(instance) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
static inline const T* fastDynamicCast(const DescribedBase* instance)
|
||||||
|
{
|
||||||
|
return (instance && instance->getDescriptor().isA(T::classDescriptor())) ? static_cast<const T*>(instance) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function replaces shared_dynamic_cast for classes that derives from DescribedCreatable or DescribedNonCreatable.
|
||||||
|
template<class T, class U>
|
||||||
|
static inline shared_ptr<T> fastSharedDynamicCast(const shared_ptr<U>& instance)
|
||||||
|
{
|
||||||
|
return isA<T>(instance.get()) ? shared_static_cast<T>(instance) : shared_ptr<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Convenience functions for getting members of a described object
|
||||||
|
PropertyDescriptor* findPropertyDescriptor(const char* name)
|
||||||
|
{
|
||||||
|
return getDescriptor().MemberDescriptorContainer<PropertyDescriptor>::findDescriptor(name);
|
||||||
|
}
|
||||||
|
ConstPropertyIterator properties_begin() const {
|
||||||
|
return getDescriptor().MemberDescriptorContainer<PropertyDescriptor>::members_begin(this);
|
||||||
|
}
|
||||||
|
ConstPropertyIterator properties_end() const {
|
||||||
|
return getDescriptor().MemberDescriptorContainer<PropertyDescriptor>::members_end(this);
|
||||||
|
}
|
||||||
|
PropertyIterator properties_begin() {
|
||||||
|
return getDescriptor().MemberDescriptorContainer<PropertyDescriptor>::members_begin(this);
|
||||||
|
}
|
||||||
|
PropertyIterator properties_end() {
|
||||||
|
return getDescriptor().MemberDescriptorContainer<PropertyDescriptor>::members_end(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
FunctionDescriptor* findFunctionDescriptor(const char* name)
|
||||||
|
{
|
||||||
|
return getDescriptor().MemberDescriptorContainer<FunctionDescriptor>::findDescriptor(name);
|
||||||
|
}
|
||||||
|
FunctionIterator functions_begin() const {
|
||||||
|
return getDescriptor().MemberDescriptorContainer<FunctionDescriptor>::members_begin(this);
|
||||||
|
}
|
||||||
|
FunctionIterator functions_end() const {
|
||||||
|
return getDescriptor().MemberDescriptorContainer<FunctionDescriptor>::members_end(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
YieldFunctionDescriptor* findYieldFunctionDescriptor(const char* name) const
|
||||||
|
{
|
||||||
|
return getDescriptor().MemberDescriptorContainer<YieldFunctionDescriptor>::findDescriptor(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
YieldFunctionIterator yield_functions_begin() const {
|
||||||
|
return getDescriptor().MemberDescriptorContainer<YieldFunctionDescriptor>::members_begin(this);
|
||||||
|
}
|
||||||
|
YieldFunctionIterator yield_functions_end() const {
|
||||||
|
return getDescriptor().MemberDescriptorContainer<YieldFunctionDescriptor>::members_end(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
CallbackDescriptor* findCallbackDescriptor(const char* name)
|
||||||
|
{
|
||||||
|
return getDescriptor().MemberDescriptorContainer<CallbackDescriptor>::findDescriptor(name);
|
||||||
|
}
|
||||||
|
CallbackIterator callbacks_begin() {
|
||||||
|
return getDescriptor().MemberDescriptorContainer<CallbackDescriptor>::members_begin(this);
|
||||||
|
}
|
||||||
|
CallbackIterator callbacks_end() {
|
||||||
|
return getDescriptor().MemberDescriptorContainer<CallbackDescriptor>::members_end(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
EventDescriptor* findSignalDescriptor(const char* name) const
|
||||||
|
{
|
||||||
|
return getDescriptor().MemberDescriptorContainer<EventDescriptor>::findDescriptor(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstSignalIterator signals_begin() const {
|
||||||
|
return getDescriptor().MemberDescriptorContainer<EventDescriptor>::members_begin(this);
|
||||||
|
}
|
||||||
|
ConstSignalIterator signals_end() const {
|
||||||
|
return getDescriptor().MemberDescriptorContainer<EventDescriptor>::members_end(this);
|
||||||
|
}
|
||||||
|
SignalIterator signals_begin() {
|
||||||
|
return getDescriptor().MemberDescriptorContainer<EventDescriptor>::members_begin(this);
|
||||||
|
}
|
||||||
|
SignalIterator signals_end() {
|
||||||
|
return getDescriptor().MemberDescriptorContainer<EventDescriptor>::members_end(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string* getXmlId() const {
|
||||||
|
return xmlId.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setXmlId(const std::string& newId) {
|
||||||
|
if (!xmlId)
|
||||||
|
{
|
||||||
|
xmlId.reset(new std::string(newId));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*xmlId = newId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const RBX::Name& getClassName() const = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,491 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "reflection/member.h"
|
||||||
|
#include "reflection/enumconverter.h"
|
||||||
|
#include "reflection/type.h"
|
||||||
|
#include "v8xml/xmlelement.h"
|
||||||
|
#include "V8Xml/Reference.h" // TODO: Reflection namespace should not know about V8Tree
|
||||||
|
#include "boost/cast.hpp"
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
namespace Reflection
|
||||||
|
{
|
||||||
|
class ConstProperty;
|
||||||
|
class Property;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
READONLY,
|
||||||
|
READWRITE
|
||||||
|
} Mutability;
|
||||||
|
|
||||||
|
// Base that describes a Property
|
||||||
|
class RBXBaseClass PropertyDescriptor : public MemberDescriptor
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
unsigned bIsPublic : 1;
|
||||||
|
unsigned bIsEditable : 1;
|
||||||
|
unsigned bCanReplicate : 1;
|
||||||
|
unsigned bCanXmlRead : 1;
|
||||||
|
unsigned bCanXmlWrite : 1;
|
||||||
|
unsigned bIsScriptable : 1;
|
||||||
|
unsigned bAlwaysClone : 1;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef ConstProperty ConstMember;
|
||||||
|
typedef Property Member;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Note: isPublic == PropertyUI shown, and Can BaseScript against. ToDO: possibly split?
|
||||||
|
|
||||||
|
enum Functionality {
|
||||||
|
STANDARD = 1 + 2 + 4 + 8 + 16, // isPublic, canReplicate, canXmlRead , canXmlWrite, isScriptable
|
||||||
|
NO_XML_WRITE = 1 + 2 + 4 + 0 + 16, // isPublic, canReplicate, canXmlRead , , isScriptable
|
||||||
|
UI = 1 + 0 +(4)+ 0 + 16, // isPublic, (canXmlRead), isScriptable //Remove canXmlRead from UI
|
||||||
|
SCRIPTING = 1 + 2 + 0 + 0 + 16, // isPublic, canReplicate, isScriptable
|
||||||
|
STREAMING = 0 + 2 + 4 + 8 + 0, // canReplicate, canXmlRead , canXmlWrite,
|
||||||
|
CLUSTER = 0 + 0 + 4 + 8 + 0, // canXmlRead , canXmlWrite,
|
||||||
|
LEGACY = 0 + 0 + 4 + 0 + 0, // canXmlRead ,
|
||||||
|
REPLICATE_ONLY = 0 + 2 + 0 + 0 + 0, // canReplicate
|
||||||
|
LEGACY_SCRIPTING = 0 + 0 + 4 + 0 + 16, // canXmlRead , isScriptable
|
||||||
|
HIDDEN_SCRIPTING = 0 + 0 + 0 + 0 + 16, // isScriptable
|
||||||
|
PUBLIC_SERIALIZED = 1 + 0 + 4 + 8 + 0, // isPublic, canXmlRead , canXmlWrite,
|
||||||
|
REPLICATE_CLONE = 0 + 2 + 0 + 0 + 0 + 32, // canReplicate alwaysClone
|
||||||
|
STANDARD_NO_REPLICATE = 1 + 0 + 4 + 8 + 16, // isPublic, canXmlRead , canXmlWrite, isScriptable
|
||||||
|
STANDARD_NO_SCRIPTING = 1 + 2 + 4 + 8 + 0, // isPublic, canReplicate, canXmlRead , canXmlWrite
|
||||||
|
PUBLIC_REPLICATE = 1 + 2 + 0 + 0 + 0, // isPublic, canReplicate
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Attributes : public Descriptor::Attributes
|
||||||
|
{
|
||||||
|
Functionality flags;
|
||||||
|
|
||||||
|
Attributes():flags(STANDARD) {}
|
||||||
|
Attributes(Functionality flags):flags(flags) {}
|
||||||
|
static Attributes deprecated(const MemberDescriptor& preferred, Functionality flags = UI);
|
||||||
|
static Attributes deprecated(Functionality flags = UI);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Type& type;
|
||||||
|
const bool bIsEnum;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
PropertyDescriptor(ClassDescriptor& classDescriptor, const Type& type, const char* name, const char* category, Attributes attributes, Security::Permissions security, bool isEnum = false);
|
||||||
|
|
||||||
|
inline void checkFlags()
|
||||||
|
{
|
||||||
|
if (isWriteOnly())
|
||||||
|
{
|
||||||
|
bCanXmlWrite = 0;
|
||||||
|
bCanReplicate = 0;
|
||||||
|
}
|
||||||
|
if (isReadOnly())
|
||||||
|
{
|
||||||
|
bCanXmlRead = 0;
|
||||||
|
bCanReplicate = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
inline bool isPublic() const { return bIsPublic != 0; }
|
||||||
|
inline bool isScriptable() const { return bIsScriptable != 0; }
|
||||||
|
|
||||||
|
void setEditable(bool editable) { bIsEditable = editable ? 1 : 0; }
|
||||||
|
inline bool isEditable() const { return bIsEditable != 0; }
|
||||||
|
|
||||||
|
virtual bool isReadOnly() const = 0;
|
||||||
|
virtual bool isWriteOnly() const = 0;
|
||||||
|
inline bool canXmlRead() const
|
||||||
|
{
|
||||||
|
RBXASSERT(bCanXmlRead == 0 || !isReadOnly());
|
||||||
|
return bCanXmlRead != 0;
|
||||||
|
}
|
||||||
|
inline bool canXmlWrite() const
|
||||||
|
{
|
||||||
|
RBXASSERT(bCanXmlWrite == 0 || !isWriteOnly());
|
||||||
|
return bCanXmlWrite != 0;
|
||||||
|
}
|
||||||
|
inline bool canReplicate() const
|
||||||
|
{
|
||||||
|
RBXASSERT(bCanReplicate == 0 || (!isReadOnly() && !isWriteOnly()));
|
||||||
|
return bCanReplicate != 0;
|
||||||
|
}
|
||||||
|
inline bool alwaysClone() const
|
||||||
|
{
|
||||||
|
return bAlwaysClone != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const PropertyDescriptor& other) const {
|
||||||
|
return this == &other;
|
||||||
|
}
|
||||||
|
bool operator!=(const PropertyDescriptor& other) const {
|
||||||
|
return this != &other;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool equalValues(const DescribedBase* a, const DescribedBase* b) const = 0;
|
||||||
|
|
||||||
|
virtual void getVariant(const DescribedBase* instance, Variant& value) const = 0;
|
||||||
|
virtual void setVariant(DescribedBase* instance, const Variant& value) const = 0;
|
||||||
|
virtual void copyValue(const DescribedBase* source, DescribedBase* destination) const = 0;
|
||||||
|
|
||||||
|
virtual int getDataSize(const DescribedBase* instance) const = 0;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// String conversion interface
|
||||||
|
public:
|
||||||
|
virtual bool hasStringValue() const = 0;
|
||||||
|
virtual std::string getStringValue(const DescribedBase* instance) const {
|
||||||
|
if (hasStringValue())
|
||||||
|
debugAssertM(false, "you must implement getStringValue");
|
||||||
|
else
|
||||||
|
debugAssertM(false, "don't call getStringValue when hasStringValue()==false");
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
virtual bool setStringValue(DescribedBase* instance, const std::string& text) const {
|
||||||
|
if (hasStringValue())
|
||||||
|
debugAssertM(false, "you must implement setStringValue");
|
||||||
|
else
|
||||||
|
debugAssertM(false, "don't call setStringValue when hasStringValue()==false");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Xml streaming interface
|
||||||
|
public:
|
||||||
|
XmlElement* write(const DescribedBase* instance, bool ignoreWriteProtection = false) const;
|
||||||
|
virtual void read(DescribedBase* instance, const XmlElement* element, RBX::IReferenceBinder& binder) const;
|
||||||
|
private:
|
||||||
|
virtual void writeValue(const DescribedBase* instance, XmlElement* element) const = 0;
|
||||||
|
virtual void readValue(DescribedBase* instance, const XmlElement* element, RBX::IReferenceBinder& binder) const = 0;
|
||||||
|
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <typename V>
|
||||||
|
class TypedPropertyDescriptor : public PropertyDescriptor
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef PropertyDescriptor Super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
class RBXInterface GetSet
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual bool isReadOnly() const = 0;
|
||||||
|
virtual bool isWriteOnly() const = 0;
|
||||||
|
virtual V getValue(const DescribedBase* object) const = 0;
|
||||||
|
virtual void setValue(DescribedBase* object, const V& value) const = 0;
|
||||||
|
};
|
||||||
|
protected:
|
||||||
|
std::auto_ptr<GetSet> getset;
|
||||||
|
TypedPropertyDescriptor(ClassDescriptor& classDescriptor, const Type& type, const char* name, const char* category, std::auto_ptr<GetSet> getset, Attributes flags, Security::Permissions security)
|
||||||
|
:PropertyDescriptor(classDescriptor, type, name, category, flags, security),getset(getset)
|
||||||
|
{
|
||||||
|
if (this->getset.get())
|
||||||
|
this->checkFlags();
|
||||||
|
}
|
||||||
|
TypedPropertyDescriptor(ClassDescriptor& classDescriptor, const char* name, const char* category, std::auto_ptr<GetSet> getset, Attributes flags, Security::Permissions security)
|
||||||
|
:PropertyDescriptor(classDescriptor, Type::singleton<V>(), name, category, flags, security),getset(getset)
|
||||||
|
{
|
||||||
|
if (this->getset.get())
|
||||||
|
this->checkFlags();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
/*implement*/ V get(const DescribedBase* instance) const
|
||||||
|
{
|
||||||
|
return getset->getValue(instance);
|
||||||
|
}
|
||||||
|
/*implement*/ void set(DescribedBase* instance, const V& value) const
|
||||||
|
{
|
||||||
|
getset->setValue(instance, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*implement*/ void getVariant(const DescribedBase* instance, Variant& value) const
|
||||||
|
{
|
||||||
|
value = getset->getValue(instance);
|
||||||
|
}
|
||||||
|
/*implement*/ void setVariant(DescribedBase* instance, const Variant& value) const
|
||||||
|
{
|
||||||
|
// TODO: This might be inefficient. How is the value stored in getset???
|
||||||
|
getset->setValue(instance, value.get<V>());
|
||||||
|
}
|
||||||
|
/*implement*/ void copyValue(const DescribedBase* source, DescribedBase* destination) const
|
||||||
|
{
|
||||||
|
set(destination, get(source));
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Variant interface
|
||||||
|
public:
|
||||||
|
virtual bool isReadOnly() const {
|
||||||
|
return getset->isReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool isWriteOnly() const {
|
||||||
|
return getset->isWriteOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
V getValue(const DescribedBase* object) const {
|
||||||
|
return getset->getValue(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setValue(DescribedBase* object, const V& value) const {
|
||||||
|
getset->setValue(object, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*implement*/ bool equalValues(const DescribedBase* a, const DescribedBase* b) const {
|
||||||
|
return getValue(a) == getValue(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int getDataSize(const DescribedBase* instance) const;
|
||||||
|
|
||||||
|
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\/
|
||||||
|
|
||||||
|
virtual bool hasStringValue() const;
|
||||||
|
virtual std::string getStringValue(const DescribedBase* instance) const;
|
||||||
|
virtual bool setStringValue(DescribedBase* instance, const std::string& text) const;
|
||||||
|
private:
|
||||||
|
virtual void readValue(DescribedBase* instance, const XmlElement* element, IReferenceBinder& binder) const;
|
||||||
|
virtual void writeValue(const DescribedBase* instance, XmlElement* element) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// A light-weight convenience class that associates a PropertyDescriptor
|
||||||
|
// with a described object to create a "Property"
|
||||||
|
class ConstProperty
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
const PropertyDescriptor* descriptor;
|
||||||
|
const DescribedBase* instance;
|
||||||
|
public:
|
||||||
|
inline ConstProperty():descriptor(0),instance(0) {}
|
||||||
|
inline ConstProperty(const PropertyDescriptor& descriptor, const DescribedBase* instance)
|
||||||
|
:descriptor(&descriptor),instance(instance)
|
||||||
|
{
|
||||||
|
RBXASSERT(!instance || descriptor.isMemberOf(instance));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ConstProperty(const ConstProperty& other)
|
||||||
|
:descriptor(other.descriptor),instance(other.instance)
|
||||||
|
{}
|
||||||
|
|
||||||
|
inline const DescribedBase* getInstance() const { return instance; }
|
||||||
|
inline const PropertyDescriptor& getDescriptor() const { return *descriptor; }
|
||||||
|
|
||||||
|
inline ConstProperty& operator =(const ConstProperty& other)
|
||||||
|
{
|
||||||
|
this->descriptor = other.descriptor;
|
||||||
|
this->instance = other.instance;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator ==(const ConstProperty& other) const
|
||||||
|
{
|
||||||
|
return (this->descriptor == other.descriptor) && (this->instance == other.instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const RBX::Name& getName() const {
|
||||||
|
return descriptor->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename V>
|
||||||
|
inline bool isValueType() const
|
||||||
|
{
|
||||||
|
return descriptor->type==Type::singleton<V>();
|
||||||
|
}
|
||||||
|
template<typename V>
|
||||||
|
inline V getValue() const
|
||||||
|
{
|
||||||
|
RBXASSERT(isValueType<V>());
|
||||||
|
return static_cast<const TypedPropertyDescriptor<V>*>(descriptor)->getValue(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool hasStringValue() const
|
||||||
|
{
|
||||||
|
return descriptor->hasStringValue();
|
||||||
|
}
|
||||||
|
inline std::string getStringValue() const
|
||||||
|
{
|
||||||
|
return descriptor->getStringValue(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline XmlElement* write() const
|
||||||
|
{
|
||||||
|
return descriptor->write(instance);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// A light-weight convenience class that associates a PropertyDescriptor
|
||||||
|
// with a described object to create a "Property"
|
||||||
|
class Property : public ConstProperty
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline Property(const PropertyDescriptor& descriptor, DescribedBase* instance)
|
||||||
|
:ConstProperty(descriptor, instance)
|
||||||
|
{}
|
||||||
|
inline Property(const Property& other)
|
||||||
|
:ConstProperty(*other.descriptor, other.instance)
|
||||||
|
{}
|
||||||
|
inline Property& operator =(const Property& other)
|
||||||
|
{
|
||||||
|
this->descriptor = other.descriptor;
|
||||||
|
this->instance = other.instance;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
inline bool operator ==(const Property& other) const
|
||||||
|
{
|
||||||
|
return this->descriptor==other.descriptor && this->instance==other.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator !=(const Property& other) const
|
||||||
|
{
|
||||||
|
return this->descriptor!=other.descriptor || this->instance!=other.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
DescribedBase* getInstance() const { return const_cast<DescribedBase*>(instance); }
|
||||||
|
|
||||||
|
template<typename V>
|
||||||
|
inline void setValue(const V& value)
|
||||||
|
{
|
||||||
|
RBXASSERT(isValueType<V>());
|
||||||
|
static_cast<const TypedPropertyDescriptor<V>*>(descriptor)->setValue(const_cast<DescribedBase*>(instance), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool setStringValue(const std::string& text)
|
||||||
|
{
|
||||||
|
return descriptor->setStringValue(const_cast<DescribedBase*>(instance), text);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void read(const XmlElement* element, RBX::IReferenceBinder& binder)
|
||||||
|
{
|
||||||
|
descriptor->read(const_cast<DescribedBase*>(instance), element, binder);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
std::size_t hash_value(const ConstProperty& prop);
|
||||||
|
|
||||||
|
// Interface
|
||||||
|
// maps enums to an index (Used by UIs like a property grid)
|
||||||
|
class RBXInterface EnumPropertyDescriptor : public PropertyDescriptor {
|
||||||
|
public:
|
||||||
|
const EnumDescriptor& enumDescriptor;
|
||||||
|
virtual size_t getIndexValue(const DescribedBase* instance) const = 0;
|
||||||
|
virtual bool setIndexValue(DescribedBase* instance, size_t value) const = 0; // throws an exception if value is illegal
|
||||||
|
virtual int getEnumValue(const DescribedBase* instance) const = 0;
|
||||||
|
virtual bool setEnumValue(DescribedBase* instance, int index) const = 0;
|
||||||
|
virtual const EnumDescriptor::Item* getEnumItem(const DescribedBase* instance) const = 0;
|
||||||
|
bool setEnumItem(DescribedBase* instance, const EnumDescriptor::Item& item) const {
|
||||||
|
if (item.owner!=enumDescriptor)
|
||||||
|
return false;
|
||||||
|
return setEnumValue(instance, item.value);
|
||||||
|
}
|
||||||
|
virtual int getDataSize(const DescribedBase* instance) const
|
||||||
|
{ return sizeof(int); }
|
||||||
|
protected:
|
||||||
|
EnumPropertyDescriptor(ClassDescriptor& classDescriptor, const EnumDescriptor& enumDescriptor, const char* name, const char* category, Attributes flags = STANDARD, Security::Permissions security=Security::None)
|
||||||
|
:PropertyDescriptor(classDescriptor, enumDescriptor, name, category, flags, security, true)
|
||||||
|
,enumDescriptor(enumDescriptor)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
class RBXBaseClass RefPropertyDescriptor : public PropertyDescriptor {
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef PropertyDescriptor Super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual DescribedBase* getRefValue(const DescribedBase* instance) const = 0;
|
||||||
|
virtual void setRefValue(DescribedBase* instance, DescribedBase* value) const = 0;
|
||||||
|
virtual void setRefValueUnsafe(DescribedBase* instance, DescribedBase* value) const = 0;
|
||||||
|
|
||||||
|
RefPropertyDescriptor(ClassDescriptor& classDescriptor, const Type& type, const char* name, const char* category, Attributes flags = STANDARD, Security::Permissions security=Security::None)
|
||||||
|
:PropertyDescriptor(classDescriptor, type, name, category, flags, security)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual int getDataSize(const DescribedBase* instance) const
|
||||||
|
{ return 0; }
|
||||||
|
|
||||||
|
bool hasStringValue() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::string getStringValue(const DescribedBase* instance) const{
|
||||||
|
return Super::getStringValue(instance);
|
||||||
|
}
|
||||||
|
bool setStringValue(DescribedBase* instance, const std::string& text) const {
|
||||||
|
return Super::setStringValue(instance, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool isRefPropertyDescriptor(const Reflection::Type& type)
|
||||||
|
{
|
||||||
|
static const RBX::Name& name = RBX::Name::lookup("Object");
|
||||||
|
return (type.name == name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isRefPropertyDescriptor(const PropertyDescriptor& descriptor)
|
||||||
|
{
|
||||||
|
// See RefType in reflection.h
|
||||||
|
bool result = isRefPropertyDescriptor(descriptor.type);
|
||||||
|
RBXASSERT(result == (0 != dynamic_cast<const Reflection::RefPropertyDescriptor*>(&descriptor)));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// A very useful class for binding Instance members to PropertyDescriptors
|
||||||
|
template<typename V, Mutability mutability = READWRITE>
|
||||||
|
class BoundProp : public Reflection::TypedPropertyDescriptor<V>
|
||||||
|
{
|
||||||
|
template<class Class>
|
||||||
|
class BoundPropGetSet : public TypedPropertyDescriptor<V>::GetSet
|
||||||
|
{
|
||||||
|
BoundProp& desc;
|
||||||
|
V Class::*member;
|
||||||
|
typedef void (Class::*ChangedMember)(const Reflection::PropertyDescriptor&);
|
||||||
|
ChangedMember changed;
|
||||||
|
public:
|
||||||
|
BoundPropGetSet(BoundProp& desc, V Class::*member, ChangedMember changed):desc(desc),member(member),changed(changed) {}
|
||||||
|
virtual bool isReadOnly() const {
|
||||||
|
return mutability == READONLY;
|
||||||
|
}
|
||||||
|
virtual bool isWriteOnly() const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
virtual V getValue(const Reflection::DescribedBase* object) const {
|
||||||
|
const Class* c = static_cast<const Class*>(object);
|
||||||
|
return c->*member;
|
||||||
|
}
|
||||||
|
virtual void setValue(Reflection::DescribedBase* object, const V& value) const {
|
||||||
|
if (mutability == READONLY)
|
||||||
|
throw std::runtime_error("can't set value");
|
||||||
|
|
||||||
|
Class* c = static_cast<Class*>(object);
|
||||||
|
if (c->*member != value)
|
||||||
|
{
|
||||||
|
c->*member = value;
|
||||||
|
if (changed)
|
||||||
|
(c->*changed)(desc);
|
||||||
|
c->raisePropertyChanged(desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
template<class Class>
|
||||||
|
BoundProp(const char* name, const char* category, V Class::*member, void (Class::*changed)(const Reflection::PropertyDescriptor&), typename PropertyDescriptor::Attributes flags = PropertyDescriptor::STANDARD, Security::Permissions security = Security::None)
|
||||||
|
:Reflection::TypedPropertyDescriptor<V>(Class::classDescriptor(), name, category, std::auto_ptr<typename TypedPropertyDescriptor<V>::GetSet>(), flags, security)
|
||||||
|
{
|
||||||
|
this->getset.reset(new BoundPropGetSet<Class>(*this, member, changed));
|
||||||
|
this->checkFlags();
|
||||||
|
}
|
||||||
|
template<class Class>
|
||||||
|
BoundProp(const char* name, const char* category, V Class::*member, typename PropertyDescriptor::Attributes flags = PropertyDescriptor::STANDARD, Security::Permissions security = Security::None)
|
||||||
|
:Reflection::TypedPropertyDescriptor<V>(Class::classDescriptor(), name, category, std::auto_ptr<typename TypedPropertyDescriptor<V>::GetSet>(), flags, security)
|
||||||
|
{
|
||||||
|
this->getset.reset(new BoundPropGetSet<Class>(*this, member, NULL));
|
||||||
|
this->checkFlags();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,323 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "reflection/Descriptor.h"
|
||||||
|
#include <boost/any.hpp>
|
||||||
|
#include <boost/static_assert.hpp>
|
||||||
|
#include <util/utilities.h>
|
||||||
|
|
||||||
|
#include <boost/unordered_map.hpp>
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
namespace Reflection
|
||||||
|
{
|
||||||
|
template<typename T> class TypeRegistrar;
|
||||||
|
|
||||||
|
// Types supported by the Reflection framework
|
||||||
|
class Type : public Descriptor
|
||||||
|
{
|
||||||
|
template<class T>
|
||||||
|
friend class TypeRegistrar;
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
static const Type& getSingleton(); // Must be implemented for each type used
|
||||||
|
void addToAllTypes();
|
||||||
|
|
||||||
|
public:
|
||||||
|
const Name& tag;
|
||||||
|
const bool isFloat;
|
||||||
|
const bool isNumber;
|
||||||
|
const bool isEnum;
|
||||||
|
|
||||||
|
static const std::vector<const Type*>& getAllTypes();
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
static inline const Type& singleton()
|
||||||
|
{
|
||||||
|
return getSingleton<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Type& right) const {
|
||||||
|
return this==&right;
|
||||||
|
}
|
||||||
|
bool operator!=(const Type& right) const {
|
||||||
|
return this!=&right;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
bool isType() const {
|
||||||
|
return this == &getSingleton<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template<class T>
|
||||||
|
Type(const char* name, T* dummy)
|
||||||
|
:Descriptor(name, Descriptor::Attributes())
|
||||||
|
,tag(Name::lookup(name))
|
||||||
|
,isNumber(boost::is_arithmetic<T>::value)
|
||||||
|
,isFloat(boost::is_float<T>::value)
|
||||||
|
,isEnum(false)
|
||||||
|
{
|
||||||
|
*isOutdated = false;
|
||||||
|
*isReplicable = true;
|
||||||
|
RBXASSERT(!this->tag.empty());
|
||||||
|
addToAllTypes();
|
||||||
|
}
|
||||||
|
template<class T>
|
||||||
|
Type(const char* name, const char* tag, T* dummy)
|
||||||
|
:Descriptor(name, Descriptor::Attributes())
|
||||||
|
,tag(Name::declare(tag))
|
||||||
|
,isNumber(boost::is_arithmetic<T>::value)
|
||||||
|
,isFloat(boost::is_float<T>::value)
|
||||||
|
,isEnum(false)
|
||||||
|
{
|
||||||
|
RBXASSERT(!this->tag.empty());
|
||||||
|
addToAllTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
Type(const char* name, const char* tag, bool isNumber, bool isFloat, bool isEnum)
|
||||||
|
:Descriptor(name, Descriptor::Attributes())
|
||||||
|
,tag(Name::declare(tag))
|
||||||
|
,isNumber(isNumber)
|
||||||
|
,isFloat(isFloat)
|
||||||
|
,isEnum(isEnum)
|
||||||
|
{
|
||||||
|
RBXASSERT(!this->tag.empty());
|
||||||
|
addToAllTypes();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const RBX::Reflection::Type& type);
|
||||||
|
|
||||||
|
// Handy macro for registering a type
|
||||||
|
#define RBX_REGISTER_TYPE(mType) template<> RBX::Reflection::TypeRegistrar<mType> RBX::Reflection::TypeRegistrar<mType>::registrar(0)
|
||||||
|
|
||||||
|
// This class is designed to prevent clients of the library
|
||||||
|
// from forgetting to initialize their class descriptors
|
||||||
|
template<class T>
|
||||||
|
class TypeRegistrar : boost::noncopyable
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
|
||||||
|
//// GCC does not generate the registrar variable defination & fails at Link Time. Force Construct by passing in an dummy arg to ctor. That works. WEIRD huh?
|
||||||
|
TypeRegistrar(int i):x(i)
|
||||||
|
{
|
||||||
|
// This assertion is added to catch a nasty implicit use of boost::any with Variant objects.
|
||||||
|
// If you get a tricky link error, add your own assertion here
|
||||||
|
BOOST_STATIC_ASSERT((!boost::is_same<T, boost::any>::value));
|
||||||
|
// This call registers the Type descriptor
|
||||||
|
// in the reflection database
|
||||||
|
Type::getSingleton<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// The instantiation of this static member must be in a unit
|
||||||
|
// that is initialized in the main thread before any objects
|
||||||
|
// are created. Otherwise the reflection database
|
||||||
|
// can change at runtime, which would be a disaster
|
||||||
|
static TypeRegistrar registrar;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper class
|
||||||
|
template<typename T>
|
||||||
|
class TType : public Type
|
||||||
|
{
|
||||||
|
friend class Type;
|
||||||
|
protected:
|
||||||
|
TType(const char* name)
|
||||||
|
:Type(name, (T*)NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
TType(const char* name, const char* tag)
|
||||||
|
:Type(name, tag, (T*)NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Variant
|
||||||
|
{
|
||||||
|
struct Storage
|
||||||
|
{
|
||||||
|
char data[96];
|
||||||
|
};
|
||||||
|
|
||||||
|
const Type* _type;
|
||||||
|
rbx::placement_any<Storage> value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline Variant()
|
||||||
|
: _type(&Type::singleton<void>())
|
||||||
|
, value()
|
||||||
|
{}
|
||||||
|
|
||||||
|
inline Variant(const Variant& other)
|
||||||
|
: _type(other._type)
|
||||||
|
, value(other.value)
|
||||||
|
{}
|
||||||
|
|
||||||
|
inline Variant& operator=(const Variant& rhs)
|
||||||
|
{
|
||||||
|
_type = rhs._type;
|
||||||
|
value = rhs.value;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ValueType>
|
||||||
|
inline Variant(const ValueType& value)
|
||||||
|
: _type(&Type::singleton<ValueType>())
|
||||||
|
, value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename ValueType>
|
||||||
|
inline Variant& operator=(const ValueType& rhs)
|
||||||
|
{
|
||||||
|
_type = &Type::singleton<ValueType>();
|
||||||
|
value = rhs;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const Type& type() const {
|
||||||
|
return *_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isVoid() const
|
||||||
|
{
|
||||||
|
return *_type==Type::singleton<void>();
|
||||||
|
}
|
||||||
|
inline bool isFloat() const { return type().isFloat; }
|
||||||
|
inline bool isNumber() const { return type().isNumber; }
|
||||||
|
inline bool isString() const { return isType<std::string>();}
|
||||||
|
|
||||||
|
template<class ValueType>
|
||||||
|
inline bool isType() const {
|
||||||
|
return _type->isType<ValueType>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// throws an exception if unable to convert
|
||||||
|
template<typename ValueType>
|
||||||
|
ValueType& convert();
|
||||||
|
|
||||||
|
// throws an exception if unable to convert
|
||||||
|
template<typename ValueType>
|
||||||
|
inline ValueType get() const
|
||||||
|
{
|
||||||
|
if (isType<ValueType>())
|
||||||
|
return cast<ValueType>();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Create a non-const copy to extract the value from
|
||||||
|
Variant v(*this);
|
||||||
|
return v.convert<ValueType>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline const T& cast() const {
|
||||||
|
if (!isType<T>())
|
||||||
|
throw std::runtime_error("Variant cast failed");
|
||||||
|
return *reinterpret_cast<const T*>(value.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline T& cast() {
|
||||||
|
if (!isType<T>())
|
||||||
|
throw std::runtime_error("Variant cast failed");
|
||||||
|
return *reinterpret_cast<T*>(value.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline const T* tryCast() const {
|
||||||
|
if (!isType<T>())
|
||||||
|
return NULL;
|
||||||
|
return reinterpret_cast<const T*>(value.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline T* tryCast() {
|
||||||
|
if (!isType<T>())
|
||||||
|
return NULL;
|
||||||
|
return reinterpret_cast<T*>(value.getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<class ValueType>
|
||||||
|
ValueType& genericConvert();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Equivalent to an array in Lua
|
||||||
|
typedef std::vector<Variant> ValueArray;
|
||||||
|
|
||||||
|
// A limited table in Lua (keys must be strings for now)
|
||||||
|
typedef boost::unordered_map<std::string, Variant> ValueTable;
|
||||||
|
|
||||||
|
struct Tuple
|
||||||
|
{
|
||||||
|
ValueArray values;
|
||||||
|
Tuple() {}
|
||||||
|
Tuple(size_t count):values(count) {}
|
||||||
|
Tuple(const Tuple& other):values(other.values) {}
|
||||||
|
//Tuple(const ValueArray& values):values(values) {}
|
||||||
|
Variant& at(size_t i) { return values[i]; }
|
||||||
|
const Variant& at(size_t i) const { return values[i]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// The same as a ValueTable for now, but will always have a string key.
|
||||||
|
// TODO: Use boost::unordered_map<> or vector<> instead?
|
||||||
|
typedef std::map<std::string, Variant> ValueMap;
|
||||||
|
|
||||||
|
// Describes a function's signature
|
||||||
|
class SignatureDescriptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Item {
|
||||||
|
friend class SignatureDescriptor;
|
||||||
|
public:
|
||||||
|
Item(const RBX::Name* name, const Type* type, const Variant& defaultValue);
|
||||||
|
Item(const RBX::Name* name, const Type* type);
|
||||||
|
const RBX::Name* name;
|
||||||
|
const Type* type;
|
||||||
|
const Variant defaultValue;
|
||||||
|
bool hasDefaultValue() const
|
||||||
|
{
|
||||||
|
return defaultValue.type() == *type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// TODO: Would vector be more efficient?
|
||||||
|
typedef std::list<Item> Arguments;
|
||||||
|
|
||||||
|
const Type* resultType;
|
||||||
|
Arguments arguments;
|
||||||
|
|
||||||
|
void addArgument(const RBX::Name& name, const Type& type);
|
||||||
|
void addArgument(const RBX::Name& name, const Type& type, const Variant& defaultValue);
|
||||||
|
|
||||||
|
SignatureDescriptor();
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class ValueType>
|
||||||
|
ValueType& RBX::Reflection::Variant::genericConvert()
|
||||||
|
{
|
||||||
|
ValueType* id = tryCast<ValueType>();
|
||||||
|
if (id!=NULL)
|
||||||
|
return *id;
|
||||||
|
|
||||||
|
if (_type->isType<std::string>())
|
||||||
|
{
|
||||||
|
ValueType v;
|
||||||
|
if (StringConverter<ValueType>::convertToValue(cast<std::string>(), v))
|
||||||
|
{
|
||||||
|
value = v;
|
||||||
|
_type = &Type::singleton<ValueType>();
|
||||||
|
return cast<ValueType>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw RBX::runtime_error("Unable to cast %s to %s", _type->tag.c_str(), Type::singleton<ValueType>().tag.c_str() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Reflection/Function.h"
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
namespace Reflection
|
||||||
|
{
|
||||||
|
class YieldFunction;
|
||||||
|
|
||||||
|
// Base that describes a YieldFunction
|
||||||
|
class RBXBaseClass YieldFunctionDescriptor : public MemberDescriptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
typedef YieldFunction ConstMember;
|
||||||
|
typedef YieldFunction Member;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SignatureDescriptor signature;
|
||||||
|
YieldFunctionDescriptor(ClassDescriptor& classDescriptor, const char* name, Security::Permissions security, Attributes attributes);
|
||||||
|
|
||||||
|
public:
|
||||||
|
const SignatureDescriptor& getSignature() const { return signature; }
|
||||||
|
virtual void execute(DescribedBase* instance, FunctionDescriptor::Arguments& arguments, boost::function<void(Variant)> resumeFunction, boost::function<void(std::string)> errorFunction) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// A light-weight convenience class that associates a FunctionDescriptor
|
||||||
|
// with a described object to create a "Function"
|
||||||
|
class YieldFunction
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
const YieldFunctionDescriptor* descriptor;
|
||||||
|
DescribedBase* instance;
|
||||||
|
public:
|
||||||
|
inline YieldFunction(const YieldFunctionDescriptor& descriptor, DescribedBase* instance)
|
||||||
|
:descriptor(&descriptor),instance(instance)
|
||||||
|
{}
|
||||||
|
|
||||||
|
inline YieldFunction(const YieldFunction& other)
|
||||||
|
:descriptor(other.descriptor),instance(other.instance)
|
||||||
|
{}
|
||||||
|
inline YieldFunction& operator =(const YieldFunction& other)
|
||||||
|
{
|
||||||
|
this->descriptor = other.descriptor;
|
||||||
|
this->instance = other.instance;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const RBX::Name& getName() const {
|
||||||
|
return descriptor->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const YieldFunctionDescriptor* getDescriptor() const {
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute(FunctionDescriptor::Arguments& arguments, boost::function<void(Variant)> resumeFunction, boost::function<void(std::string)> errorFunction) const {
|
||||||
|
return descriptor->execute(const_cast<DescribedBase*>(instance), arguments, resumeFunction, errorFunction);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,353 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "reflection/Descriptor.h"
|
||||||
|
#include "util/Exception.h"
|
||||||
|
#include <vector>
|
||||||
|
#include "security/SecurityContext.h"
|
||||||
|
|
||||||
|
#include "rbx/DenseHash.h"
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
namespace Reflection
|
||||||
|
{
|
||||||
|
class ClassDescriptor;
|
||||||
|
class DescribedBase;
|
||||||
|
|
||||||
|
struct StringHashPredicate
|
||||||
|
{
|
||||||
|
size_t operator()(const char* s) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StringEqualPredicate
|
||||||
|
{
|
||||||
|
bool operator()(const char* lhs, const char* rhs) const
|
||||||
|
{
|
||||||
|
return strcmp(lhs, rhs) == 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base class of describing a described object's member: (Member, Event, etc.)
|
||||||
|
class RBXBaseClass MemberDescriptor : public Descriptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void (*memberHidingHook)(MemberDescriptor*, MemberDescriptor*);
|
||||||
|
|
||||||
|
// Category is a name used to group properties in the UI
|
||||||
|
const RBX::Name& category;
|
||||||
|
|
||||||
|
const ClassDescriptor& owner;
|
||||||
|
const Security::Permissions security;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MemberDescriptor(const ClassDescriptor& owner, const char* name, const char* category, Attributes attributes, Security::Permissions security)
|
||||||
|
:Descriptor(name, attributes)
|
||||||
|
,owner(owner)
|
||||||
|
,category(RBX::Name::declare(category))
|
||||||
|
,security(security)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
virtual ~MemberDescriptor() {}
|
||||||
|
public:
|
||||||
|
bool isMemberOf(const ClassDescriptor& classDescriptor) const;
|
||||||
|
bool isMemberOf(const DescribedBase* instance) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class MemberException : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const MemberDescriptor& desc;
|
||||||
|
MemberException(const MemberDescriptor& desc, const std::string& _Message)
|
||||||
|
:std::runtime_error(_Message)
|
||||||
|
,desc(desc)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class MemberDescriptorType>
|
||||||
|
class MemberDescriptorContainer
|
||||||
|
{
|
||||||
|
// Used for sorting
|
||||||
|
static bool compare(const MemberDescriptorType* a, const MemberDescriptorType* b)
|
||||||
|
{
|
||||||
|
return a->name < b->name;
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
class Collection : public std::vector<MemberDescriptorType*>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef DenseHashMap<const char*, MemberDescriptorType*, StringHashPredicate, StringEqualPredicate> DescriptorLookup;
|
||||||
|
|
||||||
|
typedef typename MemberDescriptorType::ConstMember ConstMemberType;
|
||||||
|
typedef typename MemberDescriptorType::Member MemberType;
|
||||||
|
class ConstIterator : public std::iterator<std::forward_iterator_tag, MemberType, void, MemberType>
|
||||||
|
{
|
||||||
|
friend class ClassDescriptor;
|
||||||
|
const DescribedBase* instance;
|
||||||
|
typename Collection::const_iterator iter;
|
||||||
|
public:
|
||||||
|
ConstIterator(const typename Collection::const_iterator& iter, const DescribedBase* instance)
|
||||||
|
:iter(iter),instance(instance)
|
||||||
|
{}
|
||||||
|
ConstMemberType operator*() const
|
||||||
|
{ // return designated object
|
||||||
|
return ConstMemberType(**iter, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const ConstIterator& other) const { return iter==other.iter; }
|
||||||
|
bool operator!=(const ConstIterator& other) const { return iter!=other.iter; }
|
||||||
|
ConstIterator& operator++()
|
||||||
|
{ // preincrement
|
||||||
|
++iter;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConstIterator operator++(int)
|
||||||
|
{ // postincrement
|
||||||
|
ConstIterator _Tmp = *this;
|
||||||
|
++*this;
|
||||||
|
return (_Tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
const MemberDescriptorType& getDescriptor() const { return **iter; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Iterator : public std::iterator<std::forward_iterator_tag, MemberType, void, MemberType>
|
||||||
|
{
|
||||||
|
friend class ClassDescriptor;
|
||||||
|
DescribedBase* instance;
|
||||||
|
// iter is a const iterator, since we never modifiy the collection of descriptors
|
||||||
|
typename Collection::const_iterator iter;
|
||||||
|
public:
|
||||||
|
Iterator(const typename Collection::const_iterator& iter, DescribedBase* instance)
|
||||||
|
:iter(iter),instance(instance)
|
||||||
|
{}
|
||||||
|
MemberType operator*() const
|
||||||
|
{ // return designated object
|
||||||
|
return MemberType(**iter, instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Iterator& other) const { return iter==other.iter; }
|
||||||
|
bool operator!=(const Iterator& other) const { return iter!=other.iter; }
|
||||||
|
Iterator& operator++()
|
||||||
|
{ // preincrement
|
||||||
|
++iter;
|
||||||
|
return (*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator operator++(int)
|
||||||
|
{ // postincrement
|
||||||
|
Iterator _Tmp = *this;
|
||||||
|
++*this;
|
||||||
|
return (_Tmp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Collection descriptors;
|
||||||
|
DescriptorLookup descriptorLookup;
|
||||||
|
private:
|
||||||
|
static Collection& staticData()
|
||||||
|
{
|
||||||
|
static Collection result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
static void initStaticData()
|
||||||
|
{
|
||||||
|
staticData();
|
||||||
|
}
|
||||||
|
static Collection& allDescriptors()
|
||||||
|
{
|
||||||
|
static boost::once_flag flag = BOOST_ONCE_INIT;
|
||||||
|
boost::call_once(&initStaticData, flag);
|
||||||
|
return staticData();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// This is a list of "subclasses"
|
||||||
|
std::vector<MemberDescriptorContainer*> derivedContainers;
|
||||||
|
|
||||||
|
MemberDescriptorContainer* const base;
|
||||||
|
protected:
|
||||||
|
MemberDescriptorContainer(MemberDescriptorContainer* base)
|
||||||
|
:base(base), descriptorLookup("")
|
||||||
|
{
|
||||||
|
if (base!=NULL)
|
||||||
|
{
|
||||||
|
// Grab base members that have already been declared
|
||||||
|
mergeMembers(base);
|
||||||
|
|
||||||
|
// Subsequent members declared in a base class will be pushed down in the declare() function
|
||||||
|
base->derivedContainers.push_back(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void declareSub(MemberDescriptorType* descriptor, MemberDescriptorType* replaceable)
|
||||||
|
{
|
||||||
|
RBXASSERT(replaceable != descriptor);
|
||||||
|
{
|
||||||
|
typename Collection::iterator iter = std::lower_bound(descriptors.begin(), descriptors.end(), descriptor, compare);
|
||||||
|
if (iter == descriptors.end())
|
||||||
|
{
|
||||||
|
descriptors.insert(iter, descriptor);
|
||||||
|
descriptorLookup[descriptor->name.c_str()] = descriptor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RBXASSERT(*iter != descriptor);
|
||||||
|
|
||||||
|
if (*iter == replaceable)
|
||||||
|
{
|
||||||
|
// Replace it
|
||||||
|
*iter = descriptor;
|
||||||
|
descriptorLookup[descriptor->name.c_str()] = descriptor;
|
||||||
|
}
|
||||||
|
else if ((*iter)->name != descriptor->name)
|
||||||
|
{
|
||||||
|
descriptors.insert(iter, descriptor);
|
||||||
|
descriptorLookup[descriptor->name.c_str()] = descriptor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We've hit upon a member that will hide this member
|
||||||
|
if (MemberDescriptor::memberHidingHook)
|
||||||
|
(*MemberDescriptor::memberHidingHook)(descriptor, replaceable);
|
||||||
|
return; // No need to continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// recurse:
|
||||||
|
for (typename std::vector<MemberDescriptorContainer*>::iterator iter = derivedContainers.begin(); iter != derivedContainers.end(); ++iter)
|
||||||
|
(*iter)->declareSub(descriptor, replaceable);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
void declare(MemberDescriptorType* descriptor)
|
||||||
|
{
|
||||||
|
MemberDescriptorType* replaceable = NULL;
|
||||||
|
|
||||||
|
{
|
||||||
|
typename Collection::iterator iter = std::lower_bound(descriptors.begin(), descriptors.end(), descriptor, compare);
|
||||||
|
if (iter == descriptors.end())
|
||||||
|
{
|
||||||
|
// add a new one
|
||||||
|
descriptors.insert(iter, descriptor);
|
||||||
|
descriptorLookup[descriptor->name.c_str()] = descriptor;
|
||||||
|
}
|
||||||
|
else if (*iter == descriptor)
|
||||||
|
{
|
||||||
|
// drop out if we've been here before
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if ((*iter)->name != descriptor->name)
|
||||||
|
{
|
||||||
|
// add a new one
|
||||||
|
descriptors.insert(iter, descriptor);
|
||||||
|
descriptorLookup[descriptor->name.c_str()] = descriptor;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// hide a member of a base class
|
||||||
|
// TODO: Eventually we'd like to nuke this feature, but it is
|
||||||
|
// required for some legacy things, like BoolValue
|
||||||
|
replaceable = *iter;
|
||||||
|
*iter = descriptor;
|
||||||
|
descriptorLookup[descriptor->name.c_str()] = descriptor;
|
||||||
|
if (MemberDescriptor::memberHidingHook)
|
||||||
|
(*MemberDescriptor::memberHidingHook)(descriptor, replaceable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also declare this member in sub-classes
|
||||||
|
for (typename std::vector<MemberDescriptorContainer*>::iterator iter = derivedContainers.begin(); iter != derivedContainers.end(); ++iter)
|
||||||
|
(*iter)->declareSub(descriptor, replaceable);
|
||||||
|
|
||||||
|
// Add this to allDescriptors (in a determanistic order)
|
||||||
|
{
|
||||||
|
typename Collection::iterator iter = allDescriptors().begin();
|
||||||
|
while (iter!=allDescriptors().end())
|
||||||
|
{
|
||||||
|
MemberDescriptorType* desc = *iter;
|
||||||
|
if (desc==descriptor)
|
||||||
|
goto SKIP;
|
||||||
|
int compare = RBX::Name::compare(descriptor->name, desc->name);
|
||||||
|
if (compare<0)
|
||||||
|
break;
|
||||||
|
if (compare==0)
|
||||||
|
{
|
||||||
|
// This descriptor name already exists in a different class
|
||||||
|
compare = RBX::Name::compare(descriptor->owner.name, desc->owner.name);
|
||||||
|
// Enforce order using class name
|
||||||
|
if (compare<0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
allDescriptors().insert(iter, descriptor);
|
||||||
|
SKIP: ;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
// Type info enumeration
|
||||||
|
typename Collection::const_iterator descriptors_begin() const {
|
||||||
|
return descriptors.begin();
|
||||||
|
}
|
||||||
|
typename Collection::const_iterator descriptors_end() const {
|
||||||
|
return descriptors.end();
|
||||||
|
}
|
||||||
|
size_t descriptor_size() const
|
||||||
|
{
|
||||||
|
return descriptors.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
// Enumeration of all descriptors
|
||||||
|
static typename Collection::const_iterator all_begin() {
|
||||||
|
return allDescriptors().begin();
|
||||||
|
}
|
||||||
|
static typename Collection::const_iterator all_end() {
|
||||||
|
return allDescriptors().end();
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
// Type info query
|
||||||
|
MemberDescriptorType* findDescriptor(const char* name) const
|
||||||
|
{
|
||||||
|
MemberDescriptorType* const * item = descriptorLookup.find(name);
|
||||||
|
|
||||||
|
return item ? *item : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////
|
||||||
|
// Member enumeration
|
||||||
|
ConstIterator members_begin(const DescribedBase* instance) const {
|
||||||
|
return ConstIterator(descriptors.begin(), instance);
|
||||||
|
}
|
||||||
|
ConstIterator members_end(const DescribedBase* instance) const {
|
||||||
|
return ConstIterator(descriptors.end(), instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator members_begin(DescribedBase* instance) const {
|
||||||
|
return Iterator(descriptors.begin(), instance);
|
||||||
|
}
|
||||||
|
Iterator members_end(DescribedBase* instance) const {
|
||||||
|
return Iterator(descriptors.end(), instance);
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
void mergeMembers(const MemberDescriptorContainer* source)
|
||||||
|
{
|
||||||
|
for (typename Collection::const_iterator iter = source->descriptors.begin(); iter != source->descriptors.end(); ++iter)
|
||||||
|
declare(*iter);
|
||||||
|
|
||||||
|
// Recursively merge parent members as well
|
||||||
|
if (source->base!=NULL)
|
||||||
|
mergeMembers(source->base);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Script/Script.h"
|
||||||
|
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
extern const char* const sCoreScript;
|
||||||
|
class CoreScript
|
||||||
|
: public DescribedNonCreatable<CoreScript, BaseScript, sCoreScript, RBX::Reflection::ClassDescriptor::INTERNAL_LOCAL>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef DescribedNonCreatable<CoreScript, BaseScript, sCoreScript, RBX::Reflection::ClassDescriptor::INTERNAL_LOCAL> Super;
|
||||||
|
Code code;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CoreScript();
|
||||||
|
|
||||||
|
static boost::optional<ProtectedString> fetchSource(const std::string& name);
|
||||||
|
|
||||||
|
virtual Code requestCode(ScriptInformationProvider* scriptInfoProvider=NULL);
|
||||||
|
|
||||||
|
virtual void extraErrorReporting(lua_State *thread);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Instance
|
||||||
|
/*override*/ void onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,400 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "V8Tree/Instance.h"
|
||||||
|
#include "V8Tree/Service.h"
|
||||||
|
#include "script/ThreadRef.h"
|
||||||
|
#include "script/ScriptContext.h"
|
||||||
|
|
||||||
|
struct lua_State;
|
||||||
|
struct lua_Debug;
|
||||||
|
struct Table;
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
class Script;
|
||||||
|
class ModuleScript;
|
||||||
|
class DataModel;
|
||||||
|
|
||||||
|
namespace Scripting
|
||||||
|
{
|
||||||
|
class ScriptDebugger;
|
||||||
|
|
||||||
|
enum BreakOnErrorMode
|
||||||
|
{
|
||||||
|
BreakOnErrorMode_Never = 0,
|
||||||
|
BreakOnErrorMode_AllExceptions,
|
||||||
|
BreakOnErrorMode_UnhandledExceptions
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ExecutionMode
|
||||||
|
{
|
||||||
|
ExecutionMode_Continue = 0,
|
||||||
|
ExecutionMode_Break
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ISpecialBreakpoint
|
||||||
|
{
|
||||||
|
virtual ~ISpecialBreakpoint() {}
|
||||||
|
virtual bool hitTest(lua_State* L, lua_Debug *ar) = 0;
|
||||||
|
lua_State* baseThread;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const char* const sDebuggerManager;
|
||||||
|
// Contains all data related to Lua debugging of Scripts
|
||||||
|
class DebuggerManager
|
||||||
|
: public DescribedNonCreatable<DebuggerManager, Instance, sDebuggerManager, Reflection::ClassDescriptor::INTERNAL_LOCAL, Security::LocalUser>
|
||||||
|
{
|
||||||
|
typedef DescribedNonCreatable<DebuggerManager, Instance, sDebuggerManager, Reflection::ClassDescriptor::INTERNAL_LOCAL, Security::LocalUser> Super;
|
||||||
|
public:
|
||||||
|
typedef boost::unordered_map<const Instance*, ScriptDebugger*> Debuggers;
|
||||||
|
private:
|
||||||
|
bool enabled;
|
||||||
|
Debuggers debuggers;
|
||||||
|
|
||||||
|
rbx::signals::connection errorSignalConnection;
|
||||||
|
rbx::signals::connection descendantAddedSignalConnection;
|
||||||
|
|
||||||
|
typedef boost::unordered_map<const Instance*, boost::shared_ptr<ScriptDebugger> > UnaddedDebuggers;
|
||||||
|
UnaddedDebuggers unaddedDebuggers;
|
||||||
|
|
||||||
|
typedef boost::unordered_map<const lua_State*, ScriptDebugger*> DebuggersLookup;
|
||||||
|
DebuggersLookup debuggersLookup;
|
||||||
|
|
||||||
|
RBX::DataModel *dataModel;
|
||||||
|
BreakOnErrorMode breakOnErrorMode;
|
||||||
|
|
||||||
|
boost::scoped_ptr<ISpecialBreakpoint> specialBreakpoint;
|
||||||
|
ExecutionMode executionMode;
|
||||||
|
std::list<Lua::WeakThreadRef> pausedThreads, resumingPausedThreads, errorThreads;
|
||||||
|
bool resuming;
|
||||||
|
bool scriptAutoResume;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DebuggerManager();
|
||||||
|
~DebuggerManager();
|
||||||
|
|
||||||
|
static DebuggerManager& singleton();
|
||||||
|
|
||||||
|
void setDataModel(RBX::DataModel *pDataModel);
|
||||||
|
RBX::DataModel* getDataModel();
|
||||||
|
|
||||||
|
void enableDebugging();
|
||||||
|
bool getEnabled() const { return enabled; }
|
||||||
|
|
||||||
|
BreakOnErrorMode getBreakOnErrorMode() const { return breakOnErrorMode; }
|
||||||
|
void setBreakOnErrorMode(BreakOnErrorMode mode);
|
||||||
|
|
||||||
|
static Reflection::Variant readWatchValue(std::string expression, int stackFrame, lua_State* L);
|
||||||
|
|
||||||
|
const Debuggers& getDebuggers()
|
||||||
|
{
|
||||||
|
return debuggers;
|
||||||
|
}
|
||||||
|
shared_ptr<const Instances> getDebuggers_Reflection();
|
||||||
|
|
||||||
|
ScriptDebugger* findDebugger(lua_State* L);
|
||||||
|
ScriptDebugger* findDebugger(Instance* script);
|
||||||
|
|
||||||
|
shared_ptr<ScriptDebugger> addDebugger(Instance* script);
|
||||||
|
shared_ptr<Instance> addDebugger_Reflection(shared_ptr<Instance> script);
|
||||||
|
void addDebugger(shared_ptr<ScriptDebugger> debugger);
|
||||||
|
|
||||||
|
void populateForLookup(lua_State* L, ScriptDebugger* debugger);
|
||||||
|
|
||||||
|
void pause();
|
||||||
|
void resume();
|
||||||
|
void stepOver();
|
||||||
|
void stepInto();
|
||||||
|
void stepOut();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
void setScriptAutoResume(bool state) { scriptAutoResume = state; }
|
||||||
|
|
||||||
|
static void hook(lua_State* L, lua_Debug *ar);
|
||||||
|
|
||||||
|
rbx::signal<void(shared_ptr<Instance>)> debuggerAdded;
|
||||||
|
rbx::signal<void(shared_ptr<Instance>)> debuggerRemoved;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*override*/ bool askForbidChild(const Instance* instance) const;
|
||||||
|
/*override*/ void verifyAddChild(const Instance* newChild) const;
|
||||||
|
/*override*/ void onChildAdded(Instance* child);
|
||||||
|
/*override*/ void onChildRemoved(Instance* child);
|
||||||
|
/*override*/ void onChildChanged(Instance* instance, const PropertyChanged& event);
|
||||||
|
|
||||||
|
void addScriptDebugger(Instance* instance);
|
||||||
|
void onErrorSignal(lua_State* L);
|
||||||
|
void onHook(lua_State* L, lua_Debug *ar);
|
||||||
|
|
||||||
|
void addUnaddedDebuggerForAddedDescendant(shared_ptr<RBX::Instance> instance);
|
||||||
|
};
|
||||||
|
|
||||||
|
class DebuggerBreakpoint;
|
||||||
|
class DebuggerWatch;
|
||||||
|
|
||||||
|
extern const char* const sScriptDebugger;
|
||||||
|
// Debugs an RBX::Script
|
||||||
|
class ScriptDebugger
|
||||||
|
: public DescribedCreatable<ScriptDebugger, Instance, sScriptDebugger, Reflection::ClassDescriptor::PERSISTENT_HIDDEN, Security::LocalUser>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef boost::unordered_map<int, DebuggerBreakpoint*> Breakpoints;
|
||||||
|
typedef std::vector<DebuggerWatch*> Watches;
|
||||||
|
struct PausedThreadData;
|
||||||
|
typedef boost::unordered_map<long, PausedThreadData> PausedThreads;
|
||||||
|
private:
|
||||||
|
typedef DescribedCreatable<ScriptDebugger, Instance, sScriptDebugger, Reflection::ClassDescriptor::PERSISTENT_HIDDEN, Security::LocalUser> Super;
|
||||||
|
|
||||||
|
Breakpoints breakpoints;
|
||||||
|
Watches watches;
|
||||||
|
|
||||||
|
boost::scoped_ptr<ISpecialBreakpoint> specialBreakpoint;
|
||||||
|
|
||||||
|
shared_ptr<Instance> script;
|
||||||
|
rbx::signals::scoped_connection scriptStartedConnection;
|
||||||
|
rbx::signals::scoped_connection scriptStoppedConnection;
|
||||||
|
rbx::signals::scoped_connection scriptParentChangedConnection;
|
||||||
|
rbx::signals::scoped_connection scriptClonedConnection;
|
||||||
|
Lua::WeakThreadRef rootThread; // The root thread of script. Set when the Script starts and reset when it stops
|
||||||
|
|
||||||
|
typedef boost::function<void(lua_State* L, lua_Debug *ar)> HookFunction;
|
||||||
|
HookFunction hookFunction; // used to overload the hook function
|
||||||
|
|
||||||
|
Lua::WeakThreadRef pausedThread; // the thread that a breakpoint hit
|
||||||
|
Lua::WeakThreadRef errorThread; // the thread that has error
|
||||||
|
lua_Debug *breakpointHookData; // set for a short period of time during the hook when we encounter a breakpoint
|
||||||
|
void* globalRawScriptPtr;
|
||||||
|
Table* prevFuncTable;
|
||||||
|
void* prevRawScriptPtr;
|
||||||
|
int currentLine; // the current line when a breakpoint is hit
|
||||||
|
bool ignoreDebuggerBreak; // whether to ignore breakpoint at the current line
|
||||||
|
long currentThreadID;
|
||||||
|
PausedThreads pausedThreads;
|
||||||
|
bool rootThreadResumed;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ScriptDebugger()
|
||||||
|
:currentLine(0)
|
||||||
|
,breakpointHookData(NULL)
|
||||||
|
,globalRawScriptPtr(NULL)
|
||||||
|
,prevFuncTable(NULL)
|
||||||
|
,prevRawScriptPtr(NULL)
|
||||||
|
,ignoreDebuggerBreak(false)
|
||||||
|
,currentThreadID(0)
|
||||||
|
,rootThreadResumed(false)
|
||||||
|
{}
|
||||||
|
ScriptDebugger(Instance& script);
|
||||||
|
~ScriptDebugger();
|
||||||
|
|
||||||
|
Instance* getScript() const { return script.get(); }
|
||||||
|
|
||||||
|
void setScript(Script* value);
|
||||||
|
void setScript(ModuleScript* value);
|
||||||
|
|
||||||
|
std::string getScriptPath() const;
|
||||||
|
void setScriptPath(std::string scriptPath);
|
||||||
|
|
||||||
|
void setIgnoreDebuggerBreak(bool state) { ignoreDebuggerBreak = state; }
|
||||||
|
|
||||||
|
DebuggerBreakpoint* findBreakpoint(int line);
|
||||||
|
shared_ptr<DebuggerBreakpoint> setBreakpoint(int line);
|
||||||
|
shared_ptr<Instance> setBreakpoint_Reflection(int line);
|
||||||
|
const Breakpoints& getBreakpoints()
|
||||||
|
{
|
||||||
|
return breakpoints;
|
||||||
|
}
|
||||||
|
shared_ptr<const Instances> getBreakpoints_Reflection();
|
||||||
|
|
||||||
|
shared_ptr<DebuggerWatch> addWatch(std::string expression);
|
||||||
|
shared_ptr<Instance> addWatch_Reflection(std::string expression);
|
||||||
|
const Watches& getWatches()
|
||||||
|
{
|
||||||
|
return watches;
|
||||||
|
}
|
||||||
|
shared_ptr<const Instances> getWatches_Reflection();
|
||||||
|
Reflection::Variant getWatchValue(DebuggerWatch* watch, int stackFrame = 0);
|
||||||
|
Reflection::Variant getWatchValue_Reflection(shared_ptr<Instance> watch);
|
||||||
|
|
||||||
|
Reflection::Variant getKeyValue(std::string key, int stackFrame);
|
||||||
|
|
||||||
|
bool isDebugging() const
|
||||||
|
{
|
||||||
|
return !rootThread.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPaused() const;
|
||||||
|
|
||||||
|
bool hasError() const
|
||||||
|
{
|
||||||
|
return !errorThread.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
int getCurrentLine() const
|
||||||
|
{
|
||||||
|
return currentLine;
|
||||||
|
}
|
||||||
|
void pause();
|
||||||
|
void resume();
|
||||||
|
void resumeTo(int line);
|
||||||
|
void stepOver();
|
||||||
|
void stepInto();
|
||||||
|
void stepOut();
|
||||||
|
|
||||||
|
struct FunctionInfo
|
||||||
|
{
|
||||||
|
boost::shared_ptr<RBX::Instance> script;
|
||||||
|
int frame;
|
||||||
|
std::string name;
|
||||||
|
std::string what;
|
||||||
|
std::string namewhat;
|
||||||
|
std::string short_src;
|
||||||
|
int currentline;
|
||||||
|
int linedefined;
|
||||||
|
int lastlinedefined;
|
||||||
|
};
|
||||||
|
typedef std::vector<FunctionInfo> Stack;
|
||||||
|
Stack getStack();
|
||||||
|
shared_ptr<const Reflection::ValueArray> getStack_Reflection();
|
||||||
|
shared_ptr<const Reflection::ValueMap> getLocals(int stackIndex);
|
||||||
|
shared_ptr<const Reflection::ValueMap> getUpvalues(int stackIndex);
|
||||||
|
shared_ptr<const Reflection::ValueMap> getGlobals();
|
||||||
|
void setLocal(std::string name, Reflection::Variant value, int stackFrame = 0);
|
||||||
|
void setUpvalue(std::string name, Reflection::Variant value, int stackFrame = 0);
|
||||||
|
void setGlobal(std::string name, Reflection::Variant value);
|
||||||
|
|
||||||
|
void handleError(lua_State* L);
|
||||||
|
void updateHook();
|
||||||
|
|
||||||
|
ScriptContext::Result resumeThread(lua_State* L, bool evalLineHookForCurrentLine = false);
|
||||||
|
bool handleHook(lua_State* L, lua_Debug *ar);
|
||||||
|
bool onLineHook(lua_State* L, lua_Debug *ar);
|
||||||
|
void debuggerBreak(lua_State* L, lua_Debug *ar);
|
||||||
|
|
||||||
|
struct PausedThreadData
|
||||||
|
{
|
||||||
|
int pausedLine;
|
||||||
|
Lua::WeakThreadRef thread;
|
||||||
|
|
||||||
|
bool hasError;
|
||||||
|
Stack callStack;
|
||||||
|
std::string errorMessage;
|
||||||
|
|
||||||
|
PausedThreadData()
|
||||||
|
:hasError(false)
|
||||||
|
,pausedLine(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const PausedThreads& getPausedThreads() { return pausedThreads; }
|
||||||
|
|
||||||
|
bool isPausedThread(long threadID);
|
||||||
|
bool isErrorThread(long threadID);
|
||||||
|
|
||||||
|
bool isRootThread(long threadID);
|
||||||
|
bool isRootThreadResumed() { return rootThreadResumed; }
|
||||||
|
|
||||||
|
void setCurrentThread(long threadID);
|
||||||
|
long getCurrentThread() { return currentThreadID; }
|
||||||
|
|
||||||
|
rbx::signal<void(int)> encounteredBreak;
|
||||||
|
rbx::signal<void()> resuming;
|
||||||
|
|
||||||
|
rbx::signal<void(shared_ptr<Instance>)> breakpointAdded;
|
||||||
|
rbx::signal<void(shared_ptr<Instance>)> breakpointRemoved;
|
||||||
|
rbx::signal<void(shared_ptr<Instance>)> watchAdded;
|
||||||
|
rbx::signal<void(shared_ptr<Instance>)> watchRemoved;
|
||||||
|
rbx::signal<void(int, std::string, Stack)> scriptErrorDetected;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*override*/ bool askForbidChild(const Instance* instance) const;
|
||||||
|
/*override*/ void verifySetParent(const Instance* newParent) const;
|
||||||
|
/*override*/ void verifyAddChild(const Instance* newChild) const;
|
||||||
|
/*override*/ void onChildAdded(Instance* child);
|
||||||
|
/*override*/ void onChildRemoved(Instance* child);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onScriptStarting(lua_State* L);
|
||||||
|
void onScriptStopped();
|
||||||
|
void onScriptParentChanged(shared_ptr<RBX::Instance> newParent);
|
||||||
|
void onScriptCloned(boost::shared_ptr<Instance> clonedScript);
|
||||||
|
bool shouldBreak(DebuggerBreakpoint* bp, lua_State* L);
|
||||||
|
bool hasDifferentScriptInstances(lua_State* L);
|
||||||
|
void handleError(std::string errorMessage, const Stack& stack = Stack());
|
||||||
|
void setScript(Instance* value);
|
||||||
|
boost::shared_ptr<ScriptDebugger> createClone(boost::shared_ptr<Instance> clonedScript);
|
||||||
|
|
||||||
|
template<class R>
|
||||||
|
void withPausedThreadHook(lua_State* L, lua_Debug *ar, boost::function<R(lua_State* L, lua_Debug *ar)> f, R& r, shared_ptr<std::string>& error);
|
||||||
|
|
||||||
|
// TODO: template specialization for R=void
|
||||||
|
template<class R>
|
||||||
|
R withPausedThread(boost::function<R(lua_State* L, lua_Debug *ar)> f);
|
||||||
|
static shared_ptr<Reflection::ValueMap> readLocals(int stackIndex, lua_State* L);
|
||||||
|
static shared_ptr<Reflection::ValueMap> readUpvalues(int stackIndex, lua_State* L);
|
||||||
|
static shared_ptr<Reflection::ValueMap> readGlobals(lua_State* L);
|
||||||
|
static Stack readStack(lua_State* L);
|
||||||
|
static RBX::Instance* getScriptForLuaState(lua_State* L);
|
||||||
|
static void updateRootThread(ScriptDebugger* scriptDebugger, lua_State *L);
|
||||||
|
static void setLuaHook(ScriptDebugger* scriptDebugger, int hookMask, lua_State *L);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const char* const sDebuggerBreakpoint;
|
||||||
|
class DebuggerBreakpoint
|
||||||
|
: public DescribedCreatable<DebuggerBreakpoint, Instance, sDebuggerBreakpoint, Reflection::ClassDescriptor::PERSISTENT_HIDDEN, Security::LocalUser>
|
||||||
|
{
|
||||||
|
bool enabled;
|
||||||
|
int line;
|
||||||
|
std::string condition;
|
||||||
|
public:
|
||||||
|
DebuggerBreakpoint();
|
||||||
|
DebuggerBreakpoint(int line);
|
||||||
|
~DebuggerBreakpoint();
|
||||||
|
|
||||||
|
int getLine() const { return line; }
|
||||||
|
|
||||||
|
bool isEnabled() const { return enabled; }
|
||||||
|
|
||||||
|
const std::string& getCondition() const { return condition; }
|
||||||
|
|
||||||
|
static Reflection::BoundProp<bool> prop_Enabled;
|
||||||
|
static Reflection::BoundProp<std::string> prop_Condition;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*override*/ void verifySetParent(const Instance* newParent) const;
|
||||||
|
/*override*/ bool askForbidChild(const Instance* instance) const { return true; }
|
||||||
|
/*override*/ void verifyAddChild(const Instance* newChild) const
|
||||||
|
{
|
||||||
|
throw std::runtime_error("DebuggerBreakpoint can have no children");
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void setLine(int line);
|
||||||
|
static Reflection::BoundProp<int> prop_Line_Data;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const char* const sDebuggerWatch;
|
||||||
|
class DebuggerWatch
|
||||||
|
: public DescribedCreatable<DebuggerWatch, Instance, sDebuggerWatch, Reflection::ClassDescriptor::PERSISTENT, Security::LocalUser>
|
||||||
|
{
|
||||||
|
std::string expression;
|
||||||
|
public:
|
||||||
|
DebuggerWatch() {}
|
||||||
|
DebuggerWatch(std::string expression);
|
||||||
|
const std::string& getCondition() const { return expression; }
|
||||||
|
void checkExpressionSyntax();
|
||||||
|
|
||||||
|
const std::string& getExpression() const { return expression; }
|
||||||
|
|
||||||
|
static Reflection::BoundProp<std::string> prop_Expression;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*override*/ void verifySetParent(const Instance* newParent) const;
|
||||||
|
/*override*/ bool askForbidChild(const Instance* instance) const { return true; }
|
||||||
|
/*override*/ void verifyAddChild(const Instance* newChild) const
|
||||||
|
{
|
||||||
|
throw std::runtime_error("DebuggerWatch can have no children");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "boost/function.hpp"
|
||||||
|
#include "reflection/Type.h"
|
||||||
|
|
||||||
|
struct lua_State;
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
class BaseScript;
|
||||||
|
|
||||||
|
namespace Scripts
|
||||||
|
{
|
||||||
|
typedef boost::function<void(shared_ptr<const Reflection::Tuple> results)> SuccessHandler;
|
||||||
|
typedef boost::function<void(const char* message, const char* callStack, shared_ptr<BaseScript> source, int line)> ErrorHandler;
|
||||||
|
struct Continuations
|
||||||
|
{
|
||||||
|
SuccessHandler successHandler;
|
||||||
|
ErrorHandler errorHandler;
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return successHandler.empty() && errorHandler.empty();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Lua
|
||||||
|
{
|
||||||
|
class Continuations
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Continuations(const Scripts::Continuations& eh);
|
||||||
|
Continuations() {}
|
||||||
|
boost::function<void(lua_State*)> success; // called when the thread exits via ScriptContext::resume
|
||||||
|
boost::function<void(lua_State*)> error; // called when the thread errors via ScriptContext::resume
|
||||||
|
private:
|
||||||
|
static void onSuccessHandler(lua_State* thread, Scripts::SuccessHandler handler);
|
||||||
|
static void onErrorHandler(lua_State* thread, Scripts::ErrorHandler handler);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "util/RunStateOwner.h"
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
class BaseScript;
|
||||||
|
class ModuleScript;
|
||||||
|
|
||||||
|
// Interface for Instances that turn in-game Scripts on and off
|
||||||
|
// Implementations can add/remove the script from ScriptContext
|
||||||
|
class RBXInterface IScriptFilter
|
||||||
|
{
|
||||||
|
friend class BaseScript;
|
||||||
|
protected:
|
||||||
|
// If script should run - pass back the IScriptOwner who should run it, otherwise NULL
|
||||||
|
virtual bool scriptShouldRun(BaseScript* script) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const char *const sRuntimeScriptService;
|
||||||
|
|
||||||
|
class RuntimeScriptService
|
||||||
|
: public DescribedNonCreatable<RuntimeScriptService, Instance, sRuntimeScriptService, Reflection::ClassDescriptor::INTERNAL_LOCAL>
|
||||||
|
, public Service
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef DescribedNonCreatable<RuntimeScriptService, Instance, sRuntimeScriptService, Reflection::ClassDescriptor::INTERNAL_LOCAL> Super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RuntimeScriptService():isRunning(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void runScript(BaseScript* script);
|
||||||
|
void releaseScript(BaseScript* script);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider);
|
||||||
|
private:
|
||||||
|
rbx::signals::scoped_connection runTransitionConnection;
|
||||||
|
std::set<weak_ptr<BaseScript> > pendingScripts; // holds Scripts that are waiting for "Run"
|
||||||
|
std::set<weak_ptr<BaseScript> > runningScripts;
|
||||||
|
|
||||||
|
bool isRunning;
|
||||||
|
|
||||||
|
void onRunTransition(RunTransition event)
|
||||||
|
{
|
||||||
|
onRunState(event.newState);
|
||||||
|
}
|
||||||
|
void onRunState(RunState state);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,249 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "reflection/Function.h"
|
||||||
|
#include "script/LuaAtomicClasses.h"
|
||||||
|
#include "script/LuaEnum.h"
|
||||||
|
#include "script/ThreadRef.h"
|
||||||
|
#include "script/LuaInstanceBridge.h"
|
||||||
|
#include "rbx/make_shared.h"
|
||||||
|
#include "rbx/DenseHash.h"
|
||||||
|
#include "util/ProtectedString.h"
|
||||||
|
#include "util/PhysicalProperties.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
// Utility function that expands a variant to a strongly-typed value
|
||||||
|
template<typename R, typename F>
|
||||||
|
R withVariantValue(const Reflection::Variant& value, F f)
|
||||||
|
{
|
||||||
|
if (value.isType<void>())
|
||||||
|
return f();
|
||||||
|
|
||||||
|
if (value.isType<bool>())
|
||||||
|
return f(value.cast<bool>());
|
||||||
|
|
||||||
|
if (value.isType<int>())
|
||||||
|
return f(value.cast<int>());
|
||||||
|
|
||||||
|
if (value.isType<long>())
|
||||||
|
return f(value.cast<long>());
|
||||||
|
|
||||||
|
if (value.isType<float>())
|
||||||
|
return f(value.cast<float>());
|
||||||
|
|
||||||
|
if (value.isType<double>())
|
||||||
|
return f(value.cast<double>());
|
||||||
|
|
||||||
|
if (value.isType<std::string>())
|
||||||
|
return f(value.cast<std::string>());
|
||||||
|
|
||||||
|
if (value.isType<RBX::ProtectedString>())
|
||||||
|
return f(value.cast<RBX::ProtectedString>());
|
||||||
|
|
||||||
|
if (value.isType< shared_ptr<Instance> >())
|
||||||
|
return f(value.cast<shared_ptr<Instance> >());
|
||||||
|
|
||||||
|
if (const Reflection::EnumDescriptor* desc = Reflection::EnumDescriptor::lookupDescriptor(value.type()))
|
||||||
|
{
|
||||||
|
const Reflection::EnumDescriptor::Item* item = desc->lookup(value);
|
||||||
|
if (item == NULL)
|
||||||
|
throw RBX::runtime_error("Invalid value for enum %s", desc->name.c_str());
|
||||||
|
return f(*item);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.isType<Lua::WeakFunctionRef>())
|
||||||
|
return f(value.cast<Lua::WeakFunctionRef>());
|
||||||
|
|
||||||
|
if (value.isType<shared_ptr<const Reflection::ValueArray> >())
|
||||||
|
return f(value.cast<shared_ptr<const Reflection::ValueArray> >());
|
||||||
|
|
||||||
|
if (value.isType<shared_ptr<const Reflection::ValueMap> >())
|
||||||
|
return f(value.cast<shared_ptr<const Reflection::ValueMap> >());
|
||||||
|
|
||||||
|
if (value.isType<shared_ptr<const Reflection::ValueTable> >())
|
||||||
|
return f(value.cast<shared_ptr<const Reflection::ValueTable> >());
|
||||||
|
|
||||||
|
if (value.isType<shared_ptr<const Instances> >())
|
||||||
|
return f(value.cast<shared_ptr<const Instances> >());
|
||||||
|
|
||||||
|
if (value.isType<shared_ptr<const Reflection::Tuple> >())
|
||||||
|
return f(value.cast<shared_ptr<const Reflection::Tuple> >());
|
||||||
|
|
||||||
|
if (value.isType< shared_ptr<Lua::GenericFunction> >())
|
||||||
|
return f(value.cast< shared_ptr<Lua::GenericFunction> >());
|
||||||
|
|
||||||
|
if (value.isType< shared_ptr<Lua::GenericAsyncFunction> >())
|
||||||
|
return f(value.cast< shared_ptr<Lua::GenericAsyncFunction> >());
|
||||||
|
|
||||||
|
if (value.isType<G3D::Vector3int16>())
|
||||||
|
return f(value.cast<G3D::Vector3int16>());
|
||||||
|
if (value.isType<G3D::Vector2int16>())
|
||||||
|
return f(value.cast<G3D::Vector2int16>());
|
||||||
|
if (value.isType<G3D::Vector3>())
|
||||||
|
return f(value.cast<G3D::Vector3>());
|
||||||
|
if (value.isType<RBX::Vector2>())
|
||||||
|
return f(value.cast<G3D::Vector2>());
|
||||||
|
if (value.isType<G3D::Rect2D>())
|
||||||
|
return f(value.cast<G3D::Rect2D>());
|
||||||
|
if (value.isType<PhysicalProperties>())
|
||||||
|
return f(value.cast<PhysicalProperties>());
|
||||||
|
if (value.isType<RBX::RbxRay>())
|
||||||
|
return f(value.cast<RBX::RbxRay>());
|
||||||
|
if (value.isType<G3D::CoordinateFrame>())
|
||||||
|
return f(value.cast<G3D::CoordinateFrame>());
|
||||||
|
if (value.isType<G3D::Color3>())
|
||||||
|
return f(value.cast<G3D::Color3>());
|
||||||
|
if (value.isType<BrickColor>())
|
||||||
|
return f(value.cast<BrickColor>());
|
||||||
|
if (value.isType<RBX::Region3>())
|
||||||
|
return f(value.cast<RBX::Region3>());
|
||||||
|
if( value.isType<RBX::Region3int16>())
|
||||||
|
return f(value.cast<RBX::Region3int16>());
|
||||||
|
if (value.isType<UDim>())
|
||||||
|
return f(value.cast<UDim>());
|
||||||
|
if (value.isType<UDim2>())
|
||||||
|
return f(value.cast<UDim2>());
|
||||||
|
if (value.isType<Faces>())
|
||||||
|
return f(value.cast<Faces>());
|
||||||
|
if (value.isType<Axes>())
|
||||||
|
return f(value.cast<Axes>());
|
||||||
|
if (value.isType<CellID>())
|
||||||
|
return f(value.cast<CellID>());
|
||||||
|
if (value.isType<ContentId>())
|
||||||
|
return f(value.cast<ContentId>());
|
||||||
|
|
||||||
|
if (value.isType<const Reflection::PropertyDescriptor*>())
|
||||||
|
return f(*value.cast<const Reflection::PropertyDescriptor*>());
|
||||||
|
|
||||||
|
if (value.isType<rbx::signals::connection>())
|
||||||
|
return f(value.cast<rbx::signals::connection>());
|
||||||
|
|
||||||
|
if (value.isType<NumberSequence>())
|
||||||
|
return f(value.cast<NumberSequence>());
|
||||||
|
if (value.isType<ColorSequence>())
|
||||||
|
return f(value.cast<ColorSequence>());
|
||||||
|
if (value.isType<NumberRange>())
|
||||||
|
return f(value.cast<NumberRange>());
|
||||||
|
if (value.isType<NumberSequenceKeypoint>())
|
||||||
|
return f(value.cast<NumberSequenceKeypoint>());
|
||||||
|
if (value.isType<ColorSequenceKeypoint>())
|
||||||
|
return f(value.cast<ColorSequenceKeypoint>());
|
||||||
|
|
||||||
|
RBXASSERT(0);
|
||||||
|
return f();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace Lua {
|
||||||
|
|
||||||
|
class LuaArguments : public Reflection::FunctionDescriptor::Arguments
|
||||||
|
{
|
||||||
|
typedef DenseHashMap<const void*, bool> TablesCollection;
|
||||||
|
static bool getRec(lua_State *L, int luaIndex, Reflection::Variant& value, bool treatNilAsMissing, TablesCollection* visitedTables = NULL);
|
||||||
|
|
||||||
|
const int offset;
|
||||||
|
lua_State * const L;
|
||||||
|
public:
|
||||||
|
LuaArguments(lua_State *L, int offset):L(L),offset(offset) {}
|
||||||
|
|
||||||
|
virtual size_t size() const {
|
||||||
|
return lua_gettop(L) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets all arguments from the stack and puts them into the ValueArray
|
||||||
|
static shared_ptr<Reflection::Tuple> getValues(lua_State* L)
|
||||||
|
{
|
||||||
|
int argCount = lua_gettop(L);
|
||||||
|
|
||||||
|
shared_ptr<Reflection::Tuple> args(rbx::make_shared<Reflection::Tuple>(argCount));
|
||||||
|
|
||||||
|
for (int i = 0; i<argCount; ++i)
|
||||||
|
{
|
||||||
|
Reflection::Variant& v = args->values.at(i);
|
||||||
|
bool success = RBX::Lua::LuaArguments::get(L, i+1, v, false);
|
||||||
|
RBXASSERT(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pushTuple(const Reflection::Tuple& arguments, lua_State* L)
|
||||||
|
{
|
||||||
|
return pushValues(arguments.values, L);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pushes all the values from the ValueArray onto the stack
|
||||||
|
static int pushValues(const Reflection::ValueArray& arguments, lua_State* L)
|
||||||
|
{
|
||||||
|
int argCount = 0;
|
||||||
|
Reflection::ValueArray::const_iterator end = arguments.end();
|
||||||
|
for (Reflection::ValueArray::const_iterator iter = arguments.begin(); iter != end; ++iter)
|
||||||
|
{
|
||||||
|
argCount += push(*iter, L);
|
||||||
|
}
|
||||||
|
return argCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////
|
||||||
|
// Implemenent virtual functions
|
||||||
|
//
|
||||||
|
// Place the value for the requested parameter in "value".
|
||||||
|
//
|
||||||
|
// index: 1-based index into the argument list
|
||||||
|
// value: the value to set. If index >= size(), then value is unchanged
|
||||||
|
/*implement*/ bool getVariant(int index, Reflection::Variant& value) const {
|
||||||
|
const int luaIndex = index + offset;
|
||||||
|
RBXASSERT(luaIndex>0);
|
||||||
|
return get(L, luaIndex, value, true);
|
||||||
|
}
|
||||||
|
/*implement*/ bool getLong(int index, long& value) const
|
||||||
|
{
|
||||||
|
// All numbers in Lua are double, so just call the double version of get
|
||||||
|
double v;
|
||||||
|
if (getDouble(index, v))
|
||||||
|
{
|
||||||
|
value = G3D::iRound(v);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/*implement*/ bool getDouble(int index, double& value) const;
|
||||||
|
/*implement*/ bool getObject(int index, shared_ptr<Reflection::DescribedBase>& value) const;
|
||||||
|
/*implement*/ bool getBool(int index, bool& value) const;
|
||||||
|
/*implement*/ bool getString(int index, std::string& value) const;
|
||||||
|
/*implement*/ bool getVector3(int index, Vector3& value) const;
|
||||||
|
/*implement*/ bool getRegion3(int index, Region3& value) const;
|
||||||
|
/*implement*/ bool getVector3int16(int index, Vector3int16& value) const;
|
||||||
|
/*implement*/ bool getRegion3int16(int index, Region3int16& value) const;
|
||||||
|
/*implement*/ bool getRect(int index, Rect2D& value) const;
|
||||||
|
/*implement*/ bool getPhysicalProperties(int index, PhysicalProperties& value) const;
|
||||||
|
/*implement*/ bool getEnum(int index, const Reflection::EnumDescriptor& desc, int& value) const;
|
||||||
|
//
|
||||||
|
//////////////////////////////////////
|
||||||
|
|
||||||
|
// Gets a value from the Lua stack. Returns false if no value is found
|
||||||
|
static bool get(lua_State *L, int luaIndex, Reflection::Variant& value, bool treatNilAsMissing);
|
||||||
|
template<class _InIt>
|
||||||
|
static int pushArray(_InIt _First, _InIt _Last, lua_State * const L) {
|
||||||
|
lua_createtable(L, _Last - _First, 0);
|
||||||
|
unsigned int i = 0;
|
||||||
|
while (_First!=_Last)
|
||||||
|
{
|
||||||
|
int count = push(*_First, L);
|
||||||
|
RBXASSERT(count == 1); // If not 1, then what do we do?
|
||||||
|
lua_rawseti(L, -2, ++i);
|
||||||
|
++_First;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int push(const Reflection::Variant& value, lua_State * const L);
|
||||||
|
|
||||||
|
static int pushReturnValue(const Reflection::Variant& value, lua_State * const L);
|
||||||
|
static shared_ptr<Reflection::Tuple> convertToReturnValues(const Reflection::Variant& value);
|
||||||
|
};
|
||||||
|
|
||||||
|
}}
|
||||||
@@ -0,0 +1,402 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Lua/LuaBridge.h"
|
||||||
|
#include "util/G3DCore.h"
|
||||||
|
#include "g3d/Color3.h"
|
||||||
|
#include "g3d/CoordinateFrame.h"
|
||||||
|
#include "g3d/Vector3.h"
|
||||||
|
#include "g3d/Vector3int16.h"
|
||||||
|
#include "RbxG3D/RbxRay.h"
|
||||||
|
#include "Util/BrickColor.h"
|
||||||
|
#include "Util/UDim.h"
|
||||||
|
#include "Util/Region3.h"
|
||||||
|
#include "Util/Region3int16.h"
|
||||||
|
#include "Util/Faces.h"
|
||||||
|
#include "Util/Axes.h"
|
||||||
|
#include "Util/CellID.h"
|
||||||
|
#include "util/PhysicalProperties.h"
|
||||||
|
#include "v8datamodel/NumberSequence.h"
|
||||||
|
#include "v8datamodel/ColorSequence.h"
|
||||||
|
#include "v8datamodel/NumberRange.h"
|
||||||
|
|
||||||
|
namespace RBX { namespace Lua {
|
||||||
|
|
||||||
|
class CoordinateFrameBridge : public Bridge<G3D::CoordinateFrame>
|
||||||
|
{
|
||||||
|
friend class Bridge< G3D::CoordinateFrame >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L);
|
||||||
|
|
||||||
|
static void pushCoordinateFrame(lua_State *L, const G3D::CoordinateFrame& CF)
|
||||||
|
{
|
||||||
|
pushNewObject(L, CF);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static int newCoordinateFrame(lua_State *L);
|
||||||
|
static int fromEulerAnglesXYZ(lua_State *L);
|
||||||
|
static int fromAxisAngle(lua_State *L);
|
||||||
|
static int on_add(lua_State *L);
|
||||||
|
static int on_sub(lua_State *L);
|
||||||
|
static int on_mul(lua_State *L);
|
||||||
|
static int on_inverse(lua_State *L);
|
||||||
|
static int on_lerp(lua_State *L);
|
||||||
|
|
||||||
|
// Implementation of G3D::CoordinateFrame help functions
|
||||||
|
static int on_toWorldSpace(lua_State *L);
|
||||||
|
static int on_toObjectSpace(lua_State *L);
|
||||||
|
static int on_pointToWorldSpace(lua_State *L);
|
||||||
|
static int on_pointToObjectSpace(lua_State *L);
|
||||||
|
static int on_vectorToWorldSpace(lua_State *L);
|
||||||
|
static int on_vectorToObjectSpace(lua_State *L);
|
||||||
|
static int on_toEulerAnglesXYZ(lua_State *L);
|
||||||
|
static int on_components(lua_State *L);
|
||||||
|
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class PhysicalPropertiesBridge : public Bridge<PhysicalProperties>
|
||||||
|
{
|
||||||
|
friend class Bridge<PhysicalProperties>;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L);
|
||||||
|
|
||||||
|
static void pushPhysicalProperties(lua_State *L, const PhysicalProperties& v)
|
||||||
|
{
|
||||||
|
if (v.getCustomEnabled() == true)
|
||||||
|
{
|
||||||
|
pushNewObject(L, v);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lua_pushnil(L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static int newPhysicalProperties(lua_State *L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class Rect2DBridge : public Bridge<G3D::Rect2D>
|
||||||
|
{
|
||||||
|
friend class Bridge< G3D::Rect2D >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L);
|
||||||
|
|
||||||
|
static void pushRect2D(lua_State *L, const G3D::Rect2D& v)
|
||||||
|
{
|
||||||
|
pushNewObject(L, v);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static int newRect2D(lua_State *L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class Region3Bridge : public Bridge<RBX::Region3>
|
||||||
|
{
|
||||||
|
friend class Bridge< RBX::Region3 >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L) ;
|
||||||
|
|
||||||
|
static void pushRegion3(lua_State *L, const RBX::Region3& v)
|
||||||
|
{
|
||||||
|
pushNewObject(L, v);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static int newRegion3(lua_State *L);
|
||||||
|
static int expandToGrid(lua_State *L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class Region3int16Bridge : public Bridge<RBX::Region3int16>
|
||||||
|
{
|
||||||
|
friend class Bridge< RBX::Region3int16 >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L);
|
||||||
|
|
||||||
|
static void pushRegion3int16(lua_State *L, const RBX::Region3int16& v)
|
||||||
|
{
|
||||||
|
pushNewObject(L, v);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static int newRegion3int16(lua_State *L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class Vector3Bridge : public Bridge<G3D::Vector3>
|
||||||
|
{
|
||||||
|
friend class Bridge< G3D::Vector3 >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L);
|
||||||
|
|
||||||
|
static void pushVector3(lua_State *L, const G3D::Vector3& v)
|
||||||
|
{
|
||||||
|
pushNewObject(L, v);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static int newVector3(lua_State *L);
|
||||||
|
static int newVector3FromNormalId(lua_State *L);
|
||||||
|
static int newVector3FromAxis(lua_State *L);
|
||||||
|
static int on_add(lua_State *L);
|
||||||
|
static int on_sub(lua_State *L);
|
||||||
|
static int on_mul(lua_State *L);
|
||||||
|
static int on_div(lua_State *L);
|
||||||
|
static int on_unm(lua_State *L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class Vector3int16Bridge : public Bridge<G3D::Vector3int16>
|
||||||
|
{
|
||||||
|
friend class Bridge< G3D::Vector3int16 >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L);
|
||||||
|
|
||||||
|
static void pushVector3int16(lua_State *L, const G3D::Vector3int16& v)
|
||||||
|
{
|
||||||
|
pushNewObject(L, v);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static int newVector3int16(lua_State *L);
|
||||||
|
static int on_add(lua_State *L);
|
||||||
|
static int on_sub(lua_State *L);
|
||||||
|
static int on_mul(lua_State *L);
|
||||||
|
static int on_div(lua_State *L);
|
||||||
|
static int on_unm(lua_State *L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class RbxRayBridge : public Bridge<RBX::RbxRay>
|
||||||
|
{
|
||||||
|
friend class Bridge< RBX::RbxRay >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L);
|
||||||
|
|
||||||
|
static void pushRay(lua_State *L, const RBX::RbxRay& v)
|
||||||
|
{
|
||||||
|
pushNewObject(L, v);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static int newRbxRay(lua_State *L);
|
||||||
|
//static int on_add(lua_State *L);
|
||||||
|
//static int on_sub(lua_State *L);
|
||||||
|
//static int on_mul(lua_State *L);
|
||||||
|
//static int on_div(lua_State *L);
|
||||||
|
//static int on_unm(lua_State *L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Vector2Bridge : public Bridge<RBX::Vector2>
|
||||||
|
{
|
||||||
|
friend class Bridge< RBX::Vector2 >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L);
|
||||||
|
|
||||||
|
static void pushVector2(lua_State *L, const RBX::Vector2& v)
|
||||||
|
{
|
||||||
|
pushNewObject(L, v);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static int newVector2(lua_State *L);
|
||||||
|
static int on_add(lua_State *L);
|
||||||
|
static int on_sub(lua_State *L);
|
||||||
|
static int on_mul(lua_State *L);
|
||||||
|
static int on_div(lua_State *L);
|
||||||
|
static int on_unm(lua_State *L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class Vector2int16Bridge : public Bridge<RBX::Vector2int16>
|
||||||
|
{
|
||||||
|
friend class Bridge< RBX::Vector2int16 >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L);
|
||||||
|
|
||||||
|
static void pushVector2int16(lua_State *L, const RBX::Vector2int16& v)
|
||||||
|
{
|
||||||
|
pushNewObject(L, v);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static int newVector2int16(lua_State *L);
|
||||||
|
static int on_add(lua_State *L);
|
||||||
|
static int on_sub(lua_State *L);
|
||||||
|
static int on_mul(lua_State *L);
|
||||||
|
static int on_div(lua_State *L);
|
||||||
|
static int on_unm(lua_State *L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class Color3Bridge : public Bridge<G3D::Color3>
|
||||||
|
{
|
||||||
|
friend class Bridge< G3D::Color3 >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L);
|
||||||
|
static void pushColor3(lua_State *L, const G3D::Color3& color);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int newColor3(lua_State *L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class UDimBridge : public Bridge<RBX::UDim>
|
||||||
|
{
|
||||||
|
friend class Bridge< RBX::UDim>;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L);
|
||||||
|
|
||||||
|
static void pushUDim(lua_State *L, const RBX::UDim& v)
|
||||||
|
{
|
||||||
|
pushNewObject(L, v);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static int newUDim(lua_State *L);
|
||||||
|
static int on_add(lua_State *L);
|
||||||
|
static int on_sub(lua_State *L);
|
||||||
|
static int on_unm(lua_State *L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class UDim2Bridge : public Bridge<RBX::UDim2>
|
||||||
|
{
|
||||||
|
friend class Bridge< RBX::UDim2>;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int newUDim2 (lua_State *L);
|
||||||
|
static int on_add(lua_State *L);
|
||||||
|
static int on_sub(lua_State *L);
|
||||||
|
static int on_unm(lua_State *L);
|
||||||
|
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class FacesBridge : public Bridge<RBX::Faces>
|
||||||
|
{
|
||||||
|
friend class Bridge< RBX::Faces>;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int newFaces (lua_State *L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class AxesBridge : public Bridge<RBX::Axes>
|
||||||
|
{
|
||||||
|
friend class Bridge< RBX::Axes>;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int newAxes(lua_State *L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class BrickColorBridge : public Bridge<RBX::BrickColor>
|
||||||
|
{
|
||||||
|
friend class Bridge< RBX::BrickColor >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L) ;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int newBrickColor(lua_State *L);
|
||||||
|
static int randomBrickColor(lua_State *L);
|
||||||
|
static int paletteBrickColor(lua_State *L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
// CellID bridge for cluster access
|
||||||
|
class CellIDBridge : public Bridge<CellID>
|
||||||
|
{
|
||||||
|
friend class Bridge< CellID >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L) ;
|
||||||
|
|
||||||
|
static void pushCellID(lua_State *L, const CellID& v)
|
||||||
|
{
|
||||||
|
pushNewObject(L, v);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
static int newCellID(lua_State *L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Number sequence for particle props
|
||||||
|
class NumberSequenceBridge : public Bridge<NumberSequence>
|
||||||
|
{
|
||||||
|
friend class Bridge< NumberSequence >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary(lua_State* L);
|
||||||
|
static void pushNumberSequence(lua_State* L, const NumberSequence& v) { pushNewObject(L, v); }
|
||||||
|
private:
|
||||||
|
static int newNumberSequence(lua_State* L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Number sequence for particle props
|
||||||
|
class ColorSequenceBridge : public Bridge<ColorSequence>
|
||||||
|
{
|
||||||
|
friend class Bridge< ColorSequence >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary(lua_State* L);
|
||||||
|
static void pushColorSequence(lua_State* L, const ColorSequence& v) { pushNewObject(L, v); }
|
||||||
|
private:
|
||||||
|
static int newColorSequence(lua_State* L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class NumberSequenceKeypointBridge : public Bridge<NumberSequenceKeypoint>
|
||||||
|
{
|
||||||
|
friend class Bridge< NumberSequenceKeypoint >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary(lua_State* L);
|
||||||
|
static void pushNumberSequenceKeypoint(lua_State* L, const NumberSequenceKeypoint& v) { pushNewObject(L, v); }
|
||||||
|
private:
|
||||||
|
static int newNumberSequenceKeypoint(lua_State* L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class ColorSequenceKeypointBridge : public Bridge<ColorSequenceKeypoint>
|
||||||
|
{
|
||||||
|
friend class Bridge< ColorSequenceKeypoint >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary(lua_State* L);
|
||||||
|
static void pushColorSequenceKeypoint(lua_State* L, const ColorSequenceKeypoint& v) { pushNewObject(L, v); }
|
||||||
|
private:
|
||||||
|
static int newColorSequenceKeypoint(lua_State* L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
class NumberRangeBridge : public Bridge<NumberRange>
|
||||||
|
{
|
||||||
|
friend class Bridge< NumberRange >;
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary(lua_State* L);
|
||||||
|
static void pushNumberRange(lua_State* L, const NumberRange& v) { pushNewObject(L, v); }
|
||||||
|
private:
|
||||||
|
static int newNumberRange(lua_State* L);
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialization to implement arithmatic operators
|
||||||
|
template<>
|
||||||
|
void Bridge<G3D::Vector3int16>::registerClass (lua_State *L);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void Bridge<G3D::Vector3>::registerClass (lua_State *L);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void Bridge<RBX::Vector2>::registerClass (lua_State *L);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void Bridge<G3D::CoordinateFrame>::registerClass (lua_State *L);
|
||||||
|
|
||||||
|
// Specialization to implement arithmatic operators
|
||||||
|
template<>
|
||||||
|
void Bridge<RBX::UDim>::registerClass (lua_State *L);
|
||||||
|
|
||||||
|
// Specialization to implement arithmatic operators
|
||||||
|
template<>
|
||||||
|
void Bridge<RBX::UDim2>::registerClass (lua_State *L);
|
||||||
|
|
||||||
|
} }
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "lauxlib.h"
|
||||||
|
|
||||||
|
namespace LuaOsExtension
|
||||||
|
{
|
||||||
|
extern const luaL_Reg registry[];
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace LuaMathExtension
|
||||||
|
{
|
||||||
|
int noise(lua_State* L);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace LuaDebugExtension
|
||||||
|
{
|
||||||
|
extern const luaL_Reg registry[];
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Lua/LuaBridge.h"
|
||||||
|
#include "reflection/enumConverter.h"
|
||||||
|
#include "rbxformat.h"
|
||||||
|
|
||||||
|
namespace RBX { namespace Lua {
|
||||||
|
|
||||||
|
class AllEnumDescriptors
|
||||||
|
{
|
||||||
|
};
|
||||||
|
typedef const AllEnumDescriptors* AllEnumDescriptorsPtr;
|
||||||
|
|
||||||
|
// Represents a Reflection::EnumDescriptor::Item in Lua
|
||||||
|
class Enums : public SingletonBridge<AllEnumDescriptorsPtr>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void declareAllEnums(lua_State *L);
|
||||||
|
static bool getValue(lua_State *L, unsigned int index, RBX::Reflection::Variant& value);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef const Reflection::EnumDescriptor* EnumDescriptorPtr;
|
||||||
|
|
||||||
|
// Represents a Reflection::EnumDescriptor::Item in Lua
|
||||||
|
class Enum : public SingletonBridge<EnumDescriptorPtr>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef const Reflection::EnumDescriptor::Item* EnumDescriptorItemPtr;
|
||||||
|
|
||||||
|
// Represents a Reflection::EnumDescriptor::Item in Lua
|
||||||
|
class EnumItem : public SingletonBridge<EnumDescriptorItemPtr>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static EnumDescriptorItemPtr getItem(lua_State *L, unsigned int index) {
|
||||||
|
return getObject(L, index);
|
||||||
|
}
|
||||||
|
static bool getItem(lua_State *L, unsigned int index, EnumDescriptorItemPtr& value) {
|
||||||
|
return getValue(L, index, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// specialization
|
||||||
|
template<>
|
||||||
|
int Bridge< AllEnumDescriptorsPtr, false >::on_tostring(const AllEnumDescriptorsPtr& object, lua_State *L);
|
||||||
|
|
||||||
|
// specialization
|
||||||
|
template<>
|
||||||
|
int Bridge< EnumDescriptorPtr, false >::on_tostring(const EnumDescriptorPtr& object, lua_State *L);
|
||||||
|
|
||||||
|
// specialization
|
||||||
|
template<>
|
||||||
|
int Bridge< EnumDescriptorItemPtr, false >::on_tostring(const EnumDescriptorItemPtr& object, lua_State *L);
|
||||||
|
|
||||||
|
} }
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "Lua/LuaBridge.h"
|
||||||
|
#include "V8Tree/Instance.h"
|
||||||
|
|
||||||
|
namespace RBX { namespace Lua {
|
||||||
|
|
||||||
|
// specialization
|
||||||
|
template<>
|
||||||
|
int Bridge< shared_ptr<Instance>, false >::on_tostring(const shared_ptr<Instance>& object, lua_State *L);
|
||||||
|
|
||||||
|
class ObjectBridge : public SharedPtrBridge<Instance>
|
||||||
|
{
|
||||||
|
friend class SharedPtrBridge<Instance>;
|
||||||
|
static const luaL_reg classLibrary[];
|
||||||
|
public:
|
||||||
|
static int callMemberFunction(lua_State *L);
|
||||||
|
static int callMemberYieldFunction(lua_State *L);
|
||||||
|
|
||||||
|
static void registerInstanceClassLibrary (lua_State *L) {
|
||||||
|
|
||||||
|
// Register the "new" function for Instances
|
||||||
|
luaL_register(L, "Instance", classLibrary);
|
||||||
|
lua_setreadonly(L, -1, true);
|
||||||
|
lua_pop(L,1); // Pop table from stack. http://lua-users.org/lists/lua-l/2003-12/msg00139.html
|
||||||
|
}
|
||||||
|
|
||||||
|
static int newInstance(lua_State *L);
|
||||||
|
static int lockInstance(lua_State *L);
|
||||||
|
static int unlockInstance(lua_State *L);
|
||||||
|
|
||||||
|
static boost::shared_ptr<Instance> getInstance(lua_State *L, unsigned int index)
|
||||||
|
{
|
||||||
|
return getPtr(L, index);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void Bridge< shared_ptr<Instance>, false >::on_newindex(shared_ptr<Instance>& object, const char* name, lua_State *L);
|
||||||
|
|
||||||
|
} }
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Lua/LuaBridge.h"
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
namespace Lua {
|
||||||
|
|
||||||
|
class Library
|
||||||
|
{
|
||||||
|
std::string libraryName;
|
||||||
|
public:
|
||||||
|
Library(std::string libraryName)
|
||||||
|
:libraryName(libraryName)
|
||||||
|
{};
|
||||||
|
|
||||||
|
const std::string& getLibraryName() const { return libraryName; }
|
||||||
|
bool operator ==(const Library& other) const
|
||||||
|
{
|
||||||
|
return this->libraryName == other.libraryName;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Represents a Reflection::EnumDescriptor::Item in Lua
|
||||||
|
class LibraryBridge : public Bridge<Library>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void registerClassLibrary (lua_State *L);
|
||||||
|
static int find(lua_State *L, const std::string& libraryName);
|
||||||
|
static void push(lua_State *L, const Library& item);
|
||||||
|
static void saveLibraryResult(lua_State *L, int results, std::string libraryName);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Util/Memory.h"
|
||||||
|
#include "boost/pool/object_pool.hpp"
|
||||||
|
#include "boost/iostreams/filter/gzip.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
class LuaAllocator
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
size_t heapSize;
|
||||||
|
size_t heapCount;
|
||||||
|
size_t maxHeapSize;
|
||||||
|
size_t maxHeapCount;
|
||||||
|
|
||||||
|
// memory pools
|
||||||
|
std::vector<boost::pool<>*> memPools;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LuaAllocator(bool usePool = false);
|
||||||
|
~LuaAllocator();
|
||||||
|
|
||||||
|
static size_t heapLimit; // maximum heap size allowed. 0 == no limit
|
||||||
|
|
||||||
|
void clearHeapMax();
|
||||||
|
void getHeapStats(size_t& heapSize, size_t& heapCount, size_t& maxHeapSize, size_t& maxHeapCount) const;
|
||||||
|
void getHeapStats(size_t& heapSize, size_t& heapCount) const;
|
||||||
|
|
||||||
|
bool hasSpace(const long diff);
|
||||||
|
virtual void* alloc(void *ptr, size_t osize, size_t nsize);
|
||||||
|
static void * alloc(void *ud, void *ptr, size_t osize, size_t nsize);
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "V8DataModel/GlobalSettings.h"
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
extern const char *const sLuaSettings;
|
||||||
|
class LuaSettings
|
||||||
|
: public GlobalAdvancedSettingsItem<LuaSettings, sLuaSettings>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LuaSettings();
|
||||||
|
int gcPause;
|
||||||
|
int gcStepMul;
|
||||||
|
double defaultWaitTime;
|
||||||
|
double smallestWaitTime;
|
||||||
|
|
||||||
|
int gcLimit; //Ideal limit above which we trigger aggressive garbage collection, in average KB per gcFrequency
|
||||||
|
int gcFrequency; //How many heartbeats between maunal GC steps
|
||||||
|
|
||||||
|
bool areScriptStartsReported;
|
||||||
|
float waitingThreadsBudget; // 0..1 A percentage
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ template<>
|
|||||||
int Bridge<EventInstance>::on_index(const EventInstance& object, const char* name, lua_State *L)
|
int Bridge<EventInstance>::on_index(const EventInstance& object, const char* name, lua_State *L)
|
||||||
{
|
{
|
||||||
// The pre-defined "connect()" method
|
// The pre-defined "connect()" method
|
||||||
if (strcmp(name, "connect") == 0 || strcmp(name, "Connect") == 0)
|
if (strcmp(name, "connect")==0)
|
||||||
{
|
{
|
||||||
lua_pushcfunction(L, EventBridge::connect);
|
lua_pushcfunction(L, EventBridge::connect);
|
||||||
return 1;
|
return 1;
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Lua/LuaBridge.h"
|
||||||
|
#include "reflection/object.h"
|
||||||
|
#include "Reflection/Event.h"
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
class Instance;
|
||||||
|
namespace Lua
|
||||||
|
{
|
||||||
|
struct EventInstance
|
||||||
|
{
|
||||||
|
const Reflection::EventDescriptor* descriptor;
|
||||||
|
// We use a weak pointer because references to a Event shouldn't lock the source of the event.
|
||||||
|
// If the source has been collected, then connecting to the Event will return an empty connection.
|
||||||
|
weak_ptr<Instance> source;
|
||||||
|
|
||||||
|
bool operator== (const EventInstance& other) const
|
||||||
|
{
|
||||||
|
if (descriptor != other.descriptor)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
shared_ptr<Instance> l = source.lock();
|
||||||
|
if (!l)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
shared_ptr<Instance> l2 = other.source.lock();
|
||||||
|
if (!l2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return l == l2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// specialization
|
||||||
|
template<>
|
||||||
|
int Bridge<EventInstance>::on_tostring(const EventInstance& object, lua_State *L);
|
||||||
|
|
||||||
|
class EventBridge : public Bridge<EventInstance>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static int connect(lua_State *L);
|
||||||
|
|
||||||
|
static int wait(lua_State *L);
|
||||||
|
};
|
||||||
|
|
||||||
|
class SignalConnectionBridge : public Bridge< rbx::signals::connection >
|
||||||
|
{
|
||||||
|
friend class Bridge< rbx::signals::connection >;
|
||||||
|
static int disconnect(lua_State *L);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Util/AsyncHttpQueue.h"
|
||||||
|
#include "Util/ContentId.h"
|
||||||
|
#include "Util/ProtectedString.h"
|
||||||
|
#include "V8Tree/Instance.h"
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
|
||||||
|
class ContentProvider;
|
||||||
|
|
||||||
|
extern const char* const sLuaSourceContainer;
|
||||||
|
class LuaSourceContainer
|
||||||
|
: public DescribedNonCreatable<LuaSourceContainer, Instance, sLuaSourceContainer>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum RemoteSourceLoadState
|
||||||
|
{
|
||||||
|
NotAttemptedToLoad,
|
||||||
|
Loaded,
|
||||||
|
FailedToLoad
|
||||||
|
};
|
||||||
|
|
||||||
|
static void loadLinkedScripts(shared_ptr<ContentProvider> cp, Instance* root, AsyncHttpQueue::ResultJob jobType, boost::function<void()> callback);
|
||||||
|
static void loadLinkedScriptsForInstances(shared_ptr<ContentProvider> cp, Instances& instances, AsyncHttpQueue::ResultJob jobType, boost::function<void()> callback);
|
||||||
|
static void blockingLoadLinkedScripts(ContentProvider* cp, Instance* root);
|
||||||
|
static void blockingLoadLinkedScriptsForInstances(ContentProvider* cp, Instances& instances);
|
||||||
|
static Reflection::RemoteEventDesc<LuaSourceContainer, void()> event_requestLock;
|
||||||
|
|
||||||
|
LuaSourceContainer();
|
||||||
|
|
||||||
|
const ContentId& getScriptId() const;
|
||||||
|
void setScriptId(const ContentId& contentId);
|
||||||
|
const ProtectedString& getCachedRemoteSource() const;
|
||||||
|
void setCachedRemoteSource(const ProtectedString& value);
|
||||||
|
int getCachedRemoteSourceLoadState() const;
|
||||||
|
void setCachedRemoteSourceLoadState(int value);
|
||||||
|
Instance* getCurrentEditor() const;
|
||||||
|
void setCurrentEditor(Instance* newEditor);
|
||||||
|
virtual void fireSourceChanged() {};
|
||||||
|
|
||||||
|
rbx::remote_signal<void()> requestLock;
|
||||||
|
rbx::remote_signal<void(bool)> lockGrantedOrNot;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void onScriptIdChanged() {}
|
||||||
|
void processRemoteEvent(const Reflection::EventDescriptor& descriptor, const Reflection::EventArguments& args, const SystemAddress& source) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct LinkedScriptLoadData
|
||||||
|
{
|
||||||
|
rbx::atomic<int> scriptCount;
|
||||||
|
boost::function<void()> callbackWhenDone;
|
||||||
|
shared_ptr<Instance> context;
|
||||||
|
AsyncHttpQueue::ResultJob jobType;
|
||||||
|
|
||||||
|
boost::mutex scriptApplyResultClosuresMutex;
|
||||||
|
std::vector<boost::function<void()> > scriptApplyResultClosures;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void linkedSourceCountingVisitor(shared_ptr<Instance> descendant, int* counter);
|
||||||
|
static void linkedSourceLoadedHandler(weak_ptr<LuaSourceContainer> weakScript, AsyncHttpQueue::RequestResult result,
|
||||||
|
shared_ptr<const std::string> loadedSource, shared_ptr<LinkedScriptLoadData> metadata);
|
||||||
|
static void updateScriptInstancesUnderWriteLock(DataModel* dm, shared_ptr<LinkedScriptLoadData> metadata);
|
||||||
|
static void linkedSourceFetchingVisitor(shared_ptr<Instance> descendant, shared_ptr<ContentProvider> cp,
|
||||||
|
AsyncHttpQueue::ResultJob jobType, shared_ptr<LinkedScriptLoadData> metadata);
|
||||||
|
|
||||||
|
ContentId scriptId;
|
||||||
|
ProtectedString cachedRemoteSource;
|
||||||
|
RemoteSourceLoadState cachedRemoteSourceLoadState;
|
||||||
|
weak_ptr<Instance> currentEditor;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if (defined(_WIN32) || (defined(__APPLE__) && !defined(RBX_PLATFORM_IOS))) && !defined(RBX_STUDIO_BUILD)
|
||||||
|
#define RBX_SECURE_DOUBLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define RBX_ALIGN(s) _declspec(align(s))
|
||||||
|
#else
|
||||||
|
#define RBX_ALIGN(s) __attribute__((__aligned__(s)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <boost/unordered_map.hpp>
|
||||||
|
#include <string>
|
||||||
|
#if defined(RBX_SECURE_DOUBLE)
|
||||||
|
#include <emmintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RBX_STUDIO_BUILD
|
||||||
|
#define LUAVM_SECURE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Utilities for shuffling fields and enum values
|
||||||
|
#define LUAVM_SHUFFLE_COMMA ,
|
||||||
|
|
||||||
|
#ifdef LUAVM_SECURE
|
||||||
|
#define LUAVM_SHUFFLE2(sep,a0,a1) a1 sep a0
|
||||||
|
#define LUAVM_SHUFFLE3(sep,a0,a1,a2) a1 sep a2 sep a0
|
||||||
|
#define LUAVM_SHUFFLE4(sep,a0,a1,a2,a3) a3 sep a1 sep a0 sep a2
|
||||||
|
#define LUAVM_SHUFFLE5(sep,a0,a1,a2,a3,a4) a4 sep a0 sep a2 sep a1 sep a3
|
||||||
|
#define LUAVM_SHUFFLE6(sep,a0,a1,a2,a3,a4,a5) a3 sep a5 sep a2 sep a0 sep a1 sep a4
|
||||||
|
#define LUAVM_SHUFFLE7(sep,a0,a1,a2,a3,a4,a5,a6) a2 sep a3 sep a0 sep a4 sep a6 sep a1 sep a5
|
||||||
|
#define LUAVM_SHUFFLE8(sep,a0,a1,a2,a3,a4,a5,a6,a7) a7 sep a0 sep a5 sep a6 sep a3 sep a1 sep a2 sep a4
|
||||||
|
#define LUAVM_SHUFFLE9(sep,a0,a1,a2,a3,a4,a5,a6,a7,a8) a2 sep a6 sep a4 sep a7 sep a1 sep a8 sep a0 sep a3 sep a5
|
||||||
|
#else
|
||||||
|
#define LUAVM_SHUFFLE2(sep,a0,a1) a0 sep a1
|
||||||
|
#define LUAVM_SHUFFLE3(sep,a0,a1,a2) a0 sep a1 sep a2
|
||||||
|
#define LUAVM_SHUFFLE4(sep,a0,a1,a2,a3) a0 sep a1 sep a2 sep a3
|
||||||
|
#define LUAVM_SHUFFLE5(sep,a0,a1,a2,a3,a4) a0 sep a1 sep a2 sep a3 sep a4
|
||||||
|
#define LUAVM_SHUFFLE6(sep,a0,a1,a2,a3,a4,a5) a0 sep a1 sep a2 sep a3 sep a4 sep a5
|
||||||
|
#define LUAVM_SHUFFLE7(sep,a0,a1,a2,a3,a4,a5,a6) a0 sep a1 sep a2 sep a3 sep a4 sep a5 sep a6
|
||||||
|
#define LUAVM_SHUFFLE8(sep,a0,a1,a2,a3,a4,a5,a6,a7) a0 sep a1 sep a2 sep a3 sep a4 sep a5 sep a6 sep a7
|
||||||
|
#define LUAVM_SHUFFLE9(sep,a0,a1,a2,a3,a4,a5,a6,a7,a8) a0 sep a1 sep a2 sep a3 sep a4 sep a5 sep a6 sep a7 sep a8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Utility class for obfuscating fields of primitive types
|
||||||
|
// WARNING: this will give incorrect results if T = float.
|
||||||
|
template <typename T> class LuaVMValue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
operator const T() const
|
||||||
|
{
|
||||||
|
#ifdef LUAVM_SECURE
|
||||||
|
return (T)((uintptr_t)storage + reinterpret_cast<uintptr_t>(this));
|
||||||
|
#else
|
||||||
|
return storage;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(const T& value)
|
||||||
|
{
|
||||||
|
#ifdef LUAVM_SECURE
|
||||||
|
storage = (T)((uintptr_t)value - reinterpret_cast<uintptr_t>(this));
|
||||||
|
#else
|
||||||
|
storage = value;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const T operator->() const
|
||||||
|
{
|
||||||
|
return operator const T();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T storage;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Encoding/decoding lineinfo
|
||||||
|
#if defined(LUAVM_SECURE)
|
||||||
|
#define LUAVM_ENCODELINE(line, pc) ((line) ^ ((pc) << 8))
|
||||||
|
#define LUAVM_DECODELINE(line, pc) ((line) ^ ((pc) << 8))
|
||||||
|
#else
|
||||||
|
#define LUAVM_ENCODELINE(line, pc) (line)
|
||||||
|
#define LUAVM_DECODELINE(line, pc) (line)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Encoding/decoding instructions
|
||||||
|
#if defined(LUAVM_SECURE)
|
||||||
|
#define LUAVM_ENCODEINSN(insn, key) ((insn) * key)
|
||||||
|
#define LUAVM_DECODEINSN(insn, key) ((insn).v * key)
|
||||||
|
#else
|
||||||
|
#define LUAVM_ENCODEINSN(insn, key) (insn)
|
||||||
|
#define LUAVM_DECODEINSN(insn, key) (insn).v
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef unsigned int (*RbxOpEncoder)(unsigned int i, int pc, unsigned key);
|
||||||
|
|
||||||
|
// Utility class
|
||||||
|
struct lua_State;
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
class ProtectedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Core scripts have a fixed key
|
||||||
|
// Don't use these except in LuaVM*.cpp!
|
||||||
|
// These are defines to make sure they don't end up in an executable by complete accident
|
||||||
|
#define LUAVM_INTERNAL_CORE_ENCODE_KEY 641
|
||||||
|
#define LUAVM_INTERNAL_CORE_DECODE_KEY 6700417
|
||||||
|
|
||||||
|
// Constants for key values
|
||||||
|
#define LUAVM_KEY_DUMMY 1
|
||||||
|
#define LUAVM_KEY_INVALID 0
|
||||||
|
#define LUAVM_MODKEY_DUMMY 1
|
||||||
|
|
||||||
|
namespace LuaVM
|
||||||
|
{
|
||||||
|
// Utilities for working with regular scripts
|
||||||
|
std::string compile(const std::string& source);
|
||||||
|
|
||||||
|
std::string compileLegacy(const std::string& source);
|
||||||
|
|
||||||
|
int load(lua_State* L, const RBX::ProtectedString& source, const char* chunkname, unsigned int modkey = 1);
|
||||||
|
|
||||||
|
unsigned int getKey();
|
||||||
|
|
||||||
|
// Utilities for working with core scripts
|
||||||
|
std::string compileCore(const std::string& source);
|
||||||
|
|
||||||
|
unsigned int getKeyCore();
|
||||||
|
unsigned int getModKeyCore();
|
||||||
|
|
||||||
|
// Controls whether replication uses bytecode or source code
|
||||||
|
bool useSecureReplication();
|
||||||
|
|
||||||
|
// Controls whether scripts can be compiled from source code
|
||||||
|
bool canCompileScripts();
|
||||||
|
|
||||||
|
// Gets embedded bytecode for core scripts/libraries
|
||||||
|
std::string getBytecodeCore(const std::string& name);
|
||||||
|
|
||||||
|
//const ref
|
||||||
|
boost::unordered_map<std::string, std::string> getBytecodeCoreModules();
|
||||||
|
|
||||||
|
// Old Encoding Scheme
|
||||||
|
unsigned int rbxOldEncode(unsigned int i, int pc, unsigned int key);
|
||||||
|
|
||||||
|
// Dual-Affine-Xor Encoding
|
||||||
|
unsigned int rbxDaxEncode(unsigned int i, int pc, unsigned int key);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(RBX_SECURE_DOUBLE)
|
||||||
|
// Note that users who can find a value can still change magnitude or sign easily.
|
||||||
|
|
||||||
|
// sse2+ only
|
||||||
|
class LuaSecureDouble
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
double storage;
|
||||||
|
public:
|
||||||
|
static RBX_ALIGN(16) int luaXorMask[4];
|
||||||
|
|
||||||
|
operator const double() const
|
||||||
|
{
|
||||||
|
__m128d xmmKey = _mm_load_pd((double*)(luaXorMask));
|
||||||
|
__m128d xmmData = _mm_load_sd(&storage);
|
||||||
|
__m128d xmmResult = _mm_xor_pd(xmmData, xmmKey );
|
||||||
|
return _mm_cvtsd_f64(xmmResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(const double& value)
|
||||||
|
{
|
||||||
|
__m128d xmmKey = _mm_load_pd((double*)(luaXorMask));
|
||||||
|
__m128d xmmData = _mm_load_sd(&value);
|
||||||
|
__m128d xmmResult = _mm_xor_pd(xmmData, xmmKey );
|
||||||
|
storage = _mm_cvtsd_f64(xmmResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void initDouble();
|
||||||
|
|
||||||
|
};
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Reflection/reflection.h"
|
||||||
|
#include "Script/ThreadRef.h"
|
||||||
|
#include "Script/LuaSourceContainer.h"
|
||||||
|
#include "Util/ProtectedString.h"
|
||||||
|
#include "V8Tree/Instance.h"
|
||||||
|
|
||||||
|
#include <boost/intrusive_ptr.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
|
||||||
|
extern const char* const sModuleScript;
|
||||||
|
class ModuleScript
|
||||||
|
: public DescribedCreatable<ModuleScript, LuaSourceContainer, sModuleScript>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const Reflection::PropDescriptor<ModuleScript, ProtectedString> prop_Source;
|
||||||
|
|
||||||
|
enum ScriptSetupState
|
||||||
|
{
|
||||||
|
NotRunYet = 0,
|
||||||
|
Running = 1,
|
||||||
|
CompletedError = 2,
|
||||||
|
CompletedSuccess = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
class PerVMState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PerVMState();
|
||||||
|
virtual ~PerVMState();
|
||||||
|
|
||||||
|
int getResultRegistryIndex() const;
|
||||||
|
|
||||||
|
// Destroy the current result index and replace it with index.
|
||||||
|
void reassignResultRegistryIndex(int newIndex);
|
||||||
|
|
||||||
|
void setRunning(boost::intrusive_ptr<Lua::WeakThreadRef::Node> node);
|
||||||
|
void setCompletedError();
|
||||||
|
void setCompletedSuccess(lua_State* globalStateContainingResult, int resultRegistryIndex);
|
||||||
|
ScriptSetupState getCurrentState() const;
|
||||||
|
|
||||||
|
void addYieldedImporter(Lua::WeakThreadRef L);
|
||||||
|
void getAndClearYieldedImporters(std::vector<Lua::WeakThreadRef>* out);
|
||||||
|
|
||||||
|
void cleanupAndResetState();
|
||||||
|
void resetState();
|
||||||
|
private:
|
||||||
|
ScriptSetupState scriptLoadingState;
|
||||||
|
boost::intrusive_ptr<Lua::WeakThreadRef::Node> node;
|
||||||
|
lua_State* globalStateContainingResult;
|
||||||
|
int resultRegistryIndex;
|
||||||
|
std::vector<Lua::WeakThreadRef> yieldedImporters;
|
||||||
|
|
||||||
|
void releaseReferenceIfCompletedSuccessfully();
|
||||||
|
void releaseScriptNodeIfPresent();
|
||||||
|
};
|
||||||
|
|
||||||
|
ModuleScript();
|
||||||
|
|
||||||
|
// Instance
|
||||||
|
bool askSetParent(const Instance* instance) const override { return true; }
|
||||||
|
|
||||||
|
ProtectedString getSource() const;
|
||||||
|
void setSource(const ProtectedString& newText);
|
||||||
|
|
||||||
|
std::string requestHash() const;
|
||||||
|
|
||||||
|
PerVMState& vmState(lua_State* vm);
|
||||||
|
|
||||||
|
// Try to get rid of this method once new play button is launched.
|
||||||
|
static void cleanupAndResetState(const weak_ptr<ModuleScript> module);
|
||||||
|
|
||||||
|
// Reset the state of the module script without destroying its result index.
|
||||||
|
void resetState();
|
||||||
|
|
||||||
|
void setReloadRequested(bool reload) { reloadRequested = reload; }
|
||||||
|
bool getReloadRequested() const { return reloadRequested; }
|
||||||
|
|
||||||
|
void fireSourceChanged() override;
|
||||||
|
|
||||||
|
rbx::signal<void(lua_State*)> starting;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void onScriptIdChanged() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ProtectedString source;
|
||||||
|
bool reloadRequested;
|
||||||
|
typedef boost::unordered_map<lua_State*, PerVMState> VMStateMap;
|
||||||
|
VMStateMap stateMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct lua_State;
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
class DataModel;
|
||||||
|
class Instance;
|
||||||
|
|
||||||
|
namespace ScriptAnalyzer
|
||||||
|
{
|
||||||
|
// Don't change codes for the existing warnings - they have a corresponding wiki anchor tag in http://wiki.watrbx.wtf/index.php?title=Script_Analysis
|
||||||
|
enum WarningCode
|
||||||
|
{
|
||||||
|
Warning_Unknown = 0,
|
||||||
|
|
||||||
|
Warning_UnknownGlobal = 1,
|
||||||
|
Warning_DeprecatedGlobal = 2,
|
||||||
|
Warning_GlobalUsedAsLocal = 3,
|
||||||
|
Warning_LocalShadow = 4,
|
||||||
|
Warning_SameLineStatement = 5,
|
||||||
|
Warning_MultiLineStatement = 6,
|
||||||
|
Warning_UnknownType = 7,
|
||||||
|
Warning_DotCall = 8,
|
||||||
|
Warning_UnknownMember = 9,
|
||||||
|
Warning_BuiltinGlobalWrite = 10,
|
||||||
|
Warning_Placeholder = 11,
|
||||||
|
|
||||||
|
Warning_Internal
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Position
|
||||||
|
{
|
||||||
|
unsigned int line, column;
|
||||||
|
|
||||||
|
Position(unsigned int line, unsigned int column)
|
||||||
|
: line(line)
|
||||||
|
, column(column)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Location
|
||||||
|
{
|
||||||
|
Position begin, end;
|
||||||
|
|
||||||
|
Location()
|
||||||
|
: begin(0, 0)
|
||||||
|
, end(0, 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Location(const Position& begin, const Position& end)
|
||||||
|
: begin(begin)
|
||||||
|
, end(end)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Location(const Position& begin, unsigned int length)
|
||||||
|
: begin(begin)
|
||||||
|
, end(begin.line, begin.column + length)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Location(const Location& begin, const Location& end)
|
||||||
|
: begin(begin.begin)
|
||||||
|
, end(end.end)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Error
|
||||||
|
{
|
||||||
|
Location location;
|
||||||
|
std::string text;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Warning
|
||||||
|
{
|
||||||
|
WarningCode code;
|
||||||
|
Location location;
|
||||||
|
std::string text;
|
||||||
|
|
||||||
|
Warning (WarningCode code, Location location, std::string text)
|
||||||
|
: code(code)
|
||||||
|
, location(location)
|
||||||
|
, text(text)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IntellesenseResult
|
||||||
|
{
|
||||||
|
IntellesenseResult()
|
||||||
|
: name("")
|
||||||
|
, isLocal(false)
|
||||||
|
, isFunction(false)
|
||||||
|
, location(Position(0,0) , Position(0,0))
|
||||||
|
{}
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
bool isLocal;
|
||||||
|
bool isFunction;
|
||||||
|
Location location;
|
||||||
|
std::vector<IntellesenseResult> children;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Result
|
||||||
|
{
|
||||||
|
boost::optional<Error> error;
|
||||||
|
std::vector<Warning> warnings;
|
||||||
|
std::vector<IntellesenseResult> intellesenseAnalysis;
|
||||||
|
};
|
||||||
|
|
||||||
|
Result analyze(DataModel* dm, shared_ptr<Instance> script, const std::string& code);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,466 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "V8Tree/Service.h"
|
||||||
|
#include "Util/ProtectedString.h"
|
||||||
|
#include "util/runstateowner.h"
|
||||||
|
#include "Script/IScriptFilter.h"
|
||||||
|
#include "script/ThreadRef.h"
|
||||||
|
#include "script/ExitHandlers.h"
|
||||||
|
#include "Security/SecurityContext.h"
|
||||||
|
#include "Util/AsyncHttpQueue.h"
|
||||||
|
#include "util/RunningAverage.h"
|
||||||
|
#include "rbx/RunningAverage.h"
|
||||||
|
|
||||||
|
#define BOOST_DATE_TIME_NO_LIB
|
||||||
|
#include "boost/date_time/posix_time/posix_time.hpp"
|
||||||
|
|
||||||
|
struct lua_State;
|
||||||
|
struct lua_Debug;
|
||||||
|
|
||||||
|
LOGGROUP(ScriptContext)
|
||||||
|
LOGGROUP(ScriptContextRemove)
|
||||||
|
LOGGROUP(ScriptContextAdd)
|
||||||
|
LOGGROUP(ScriptContextClose)
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
class LuaSourceContainer;
|
||||||
|
class LuaAllocator;
|
||||||
|
class LibraryService;
|
||||||
|
class ModuleScript;
|
||||||
|
class ModelInstance;
|
||||||
|
namespace Stats
|
||||||
|
{
|
||||||
|
class Item;
|
||||||
|
}
|
||||||
|
namespace Lua
|
||||||
|
{
|
||||||
|
class YieldingThreads;
|
||||||
|
class WeakFunctionRef;
|
||||||
|
}
|
||||||
|
namespace Network
|
||||||
|
{
|
||||||
|
class Player;
|
||||||
|
}
|
||||||
|
class BaseScript;
|
||||||
|
class CoreScript;
|
||||||
|
class ScriptStats;
|
||||||
|
class LuaStatsItem;
|
||||||
|
|
||||||
|
void registerScriptDescriptors();
|
||||||
|
|
||||||
|
extern const char* const sScriptContext;
|
||||||
|
class ScriptContext
|
||||||
|
: public DescribedCreatable<ScriptContext, Instance, sScriptContext, Reflection::ClassDescriptor::INTERNAL_LOCAL>
|
||||||
|
, public Service
|
||||||
|
, public IScriptFilter
|
||||||
|
{
|
||||||
|
friend class LuaStatsItem;
|
||||||
|
friend class GcJob;
|
||||||
|
friend class WaitingScriptsJob;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const int hookCount;
|
||||||
|
|
||||||
|
struct ScriptStartOptions
|
||||||
|
{
|
||||||
|
struct LuaSyntaxError : std::runtime_error
|
||||||
|
{
|
||||||
|
LuaSyntaxError(int lineNumber, std::exception& source)
|
||||||
|
:std::runtime_error(source.what())
|
||||||
|
,lineNumber(lineNumber)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
int lineNumber;
|
||||||
|
};
|
||||||
|
|
||||||
|
RBX::Security::Identities identity;
|
||||||
|
Scripts::Continuations continuations;
|
||||||
|
boost::function<std::string(const std::string&)> filter; // may throw a LuaSyntaxError
|
||||||
|
|
||||||
|
ScriptStartOptions():identity(RBX::Security::GameScript_)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef DescribedCreatable<ScriptContext, Instance, sScriptContext, Reflection::ClassDescriptor::INTERNAL_LOCAL> Super;
|
||||||
|
|
||||||
|
class ScriptImpersonator : public RBX::Security::Impersonator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ScriptImpersonator(lua_State *thread);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GlobalState
|
||||||
|
{
|
||||||
|
GlobalState()
|
||||||
|
: state(0)
|
||||||
|
, gcCount(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_State* state;
|
||||||
|
|
||||||
|
RunningAverage<double> gcAllocAvg; // average lua memory allocation per luaGcFrequency in KB
|
||||||
|
int gcCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef boost::array<GlobalState, RBX::Security::COUNT_VM_Classes> GlobalStates; // separate Lua top-level states
|
||||||
|
GlobalStates globalStates;
|
||||||
|
Lua::WeakThreadRef commandLineSandbox;
|
||||||
|
std::set<BaseScript*> scripts;
|
||||||
|
RBX::Time nextPendingScripts;
|
||||||
|
struct ScriptStart
|
||||||
|
{
|
||||||
|
shared_ptr<BaseScript> script;
|
||||||
|
ScriptStartOptions options;
|
||||||
|
};
|
||||||
|
std::vector<ScriptStart> pendingScripts; // scripts waiting to be executed
|
||||||
|
std::vector<ScriptStart> loadingScripts; // scripts waiting to be executed
|
||||||
|
|
||||||
|
// An obfuscated pointer to a location near where the object was created.
|
||||||
|
// copying the object becomes detectable.
|
||||||
|
// https://en.wikipedia.org/wiki/Feistel_cipher
|
||||||
|
// the "update" method might be targeted even if it is obfuscated.
|
||||||
|
struct SecurityAnchor
|
||||||
|
{
|
||||||
|
size_t value[2];
|
||||||
|
FORCEINLINE void update(const void* ptr)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
size_t localValue[2] = {reinterpret_cast<size_t>(ptr), ~reinterpret_cast<size_t>(ptr)};
|
||||||
|
localValue[0] ^= localValue[1]*RBX_BUILDSEED | 20151112;
|
||||||
|
localValue[1] ^= localValue[0]*20151112 | RBX_BUILDSEED;
|
||||||
|
value[0] = localValue[0];
|
||||||
|
value[1] = localValue[1];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCEINLINE bool checkAnchor(const void* ptr) const
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
size_t localValue[2] = {value[0], value[1]};
|
||||||
|
localValue[1] ^= localValue[0]*20151112 | RBX_BUILDSEED;
|
||||||
|
localValue[0] ^= localValue[1]*RBX_BUILDSEED | 20151112;
|
||||||
|
return !((reinterpret_cast<size_t>(ptr)+localValue[1])
|
||||||
|
^ (~reinterpret_cast<size_t>(ptr)+localValue[0]));
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
SecurityAnchor securityAnchor;
|
||||||
|
|
||||||
|
shared_ptr<RunService> runService;
|
||||||
|
|
||||||
|
boost::scoped_ptr<Lua::YieldingThreads> yieldEvent; // collects all threads that have yielded, and periodically resumes them
|
||||||
|
|
||||||
|
struct WaitingThread
|
||||||
|
{
|
||||||
|
Lua::ThreadRef thread;
|
||||||
|
shared_ptr<const Reflection::Tuple> arguments;
|
||||||
|
};
|
||||||
|
rbx::safe_queue<WaitingThread> waitingThreads;
|
||||||
|
|
||||||
|
bool robloxPlace;
|
||||||
|
bool scriptsDisabled; // == don't run the scripts contained in BaseScript objects
|
||||||
|
bool preventNewConnection;
|
||||||
|
|
||||||
|
shared_ptr<LuaStatsItem> statsItem;
|
||||||
|
bool collectScriptStats;
|
||||||
|
shared_ptr<ScriptStats> scriptStats;
|
||||||
|
std::set<weak_ptr<ModuleScript> > loadedModules;
|
||||||
|
|
||||||
|
int startScriptReentrancy;
|
||||||
|
|
||||||
|
rbx::atomic<int> timedoutCount;
|
||||||
|
Time::Interval timoutSpan; // The time that is allowed per heartbeat before scripts stop running (0 means no timeouts)
|
||||||
|
Time timoutTime; // The system time when we should time-out scripts
|
||||||
|
rbx::atomic<int> timedout; // == scripts should stop running
|
||||||
|
boost::scoped_ptr<boost::thread> timeoutThread;
|
||||||
|
boost::mutex timeoutMutex;
|
||||||
|
volatile bool endTimoutThread;
|
||||||
|
CEvent checkTimeout;
|
||||||
|
|
||||||
|
struct AssetModuleInfo
|
||||||
|
{
|
||||||
|
enum State
|
||||||
|
{
|
||||||
|
NotFetchedYet = 0,
|
||||||
|
Fetching,
|
||||||
|
Fetched,
|
||||||
|
Failed
|
||||||
|
};
|
||||||
|
State state;
|
||||||
|
std::vector<Lua::WeakThreadRef> yieldedImporters;
|
||||||
|
shared_ptr<ModuleScript> module;
|
||||||
|
shared_ptr<ModelInstance> root;
|
||||||
|
AssetModuleInfo()
|
||||||
|
: state(NotFetchedYet)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
typedef boost::unordered_map<int, AssetModuleInfo> LoadedAssetModules;
|
||||||
|
LoadedAssetModules loadedAssetModules;
|
||||||
|
|
||||||
|
Time luaGcStartTime;
|
||||||
|
RunningAverage<double> avgLuaGcInterval; // in msec
|
||||||
|
RunningAverage<double> avgLuaGcTime; // in msec
|
||||||
|
|
||||||
|
RunningAverageTimeInterval<> resumedThreads;
|
||||||
|
RunningAverage<> throttlingThreads; // 1 if threads are being deffered
|
||||||
|
|
||||||
|
bool statesClosed;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ScriptContext();
|
||||||
|
virtual ~ScriptContext();
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
// IScriptFilter
|
||||||
|
/*override*/ virtual bool scriptShouldRun(BaseScript* script);
|
||||||
|
|
||||||
|
static void setAdminScriptPath(const std::string& newPath);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
// Reflection API
|
||||||
|
static Reflection::BoundProp<bool> propScriptsDisabled;
|
||||||
|
static Reflection::BoundProp<int> propLuaGcLimit;
|
||||||
|
static Reflection::BoundProp<int> propLuaGcFrequency;
|
||||||
|
static Reflection::BoundProp<int> propLuaGcStepSize;
|
||||||
|
void setTimeout(double seconds);
|
||||||
|
void setCollectScriptStats(bool);
|
||||||
|
// Core & Starter Scripts
|
||||||
|
void addStarterScript(int assetId);
|
||||||
|
void addCoreScript(int assetId, shared_ptr<Instance> parent, std::string name);
|
||||||
|
void addCoreScriptLocal(std::string scriptName, shared_ptr<Instance> parent);
|
||||||
|
// Experimental error signal for catching errors server-side
|
||||||
|
rbx::signal<void(std::string, std::string, shared_ptr<Instance>)> errorSignal;
|
||||||
|
// A temporary signals used for diagnostic purposes
|
||||||
|
rbx::signal<void(shared_ptr<Instance>, std::string, shared_ptr<Instance>)> camelCaseViolation;
|
||||||
|
rbx::signal<void(lua_State*)> scriptErrorDetected;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
// Configuration
|
||||||
|
void setRobloxPlace(bool robloxPlace);
|
||||||
|
void initializeLuaStateSandbox(Lua::WeakThreadRef& threadRef, lua_State* parentState, Security::Identities identity);
|
||||||
|
void setKeys(unsigned int scriptKey, unsigned int coreScriptModKey);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////
|
||||||
|
// Helpers and utilities
|
||||||
|
Reflection::Variant evaluateStudioCommandItem(const char* itemToEvaluate, shared_ptr<RBX::LuaSourceContainer> script);
|
||||||
|
static bool checkSyntax(const std::string& code, int& line, std::string& errorMessage);
|
||||||
|
static lua_State* getGlobalState(lua_State* thread);
|
||||||
|
static ScriptContext& getContext(lua_State* thread);
|
||||||
|
static void printCallStack(lua_State* thread, std::string* output = NULL, bool dontPrint = false);
|
||||||
|
static std::string extractCallStack(lua_State* thread, shared_ptr<BaseScript>& source, int& line);
|
||||||
|
// Shutdown helpers
|
||||||
|
bool shouldPreventNewConnections() { return preventNewConnection; }
|
||||||
|
void setPreventNewConnections() { preventNewConnection = true; }
|
||||||
|
void closeStates(bool resettingSimulation); // Closes down all threads
|
||||||
|
bool haveStatesClosed() { return statesClosed; }
|
||||||
|
void cleanupModules();
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
// Script Instance API
|
||||||
|
// Called by IScriptOwner implementers
|
||||||
|
void addScript(weak_ptr<BaseScript> script, ScriptStartOptions startOptions = ScriptStartOptions()); // checks pointer validity
|
||||||
|
void removeScript(weak_ptr<BaseScript> script);
|
||||||
|
size_t numScripts() {return scripts.size();}
|
||||||
|
bool hasScript(BaseScript* script) {return (scripts.find(script) != scripts.end());}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
// Calls that make lua run/resume
|
||||||
|
void executeInNewThread(RBX::Security::Identities identity, const ProtectedString& script, const char* name);
|
||||||
|
std::auto_ptr<Reflection::Tuple> executeInNewThread(RBX::Security::Identities identity, const ProtectedString& script, const char* name, const Reflection::Tuple& arguments);
|
||||||
|
void executeInNewThreadWithExtraGlobals(RBX::Security::Identities identity,
|
||||||
|
const ProtectedString& script, const char* name,
|
||||||
|
const std::map<std::string, shared_ptr<Instance> >& extraGlobals);
|
||||||
|
|
||||||
|
// Calls a function
|
||||||
|
Reflection::Tuple callInNewThread(Lua::WeakFunctionRef& function, const Reflection::Tuple& arguments);
|
||||||
|
|
||||||
|
// Thread-safe call:
|
||||||
|
void scheduleResume(Lua::ThreadRef thread, shared_ptr<const Reflection::Tuple> arguments);
|
||||||
|
typedef enum { Success, Yield, Error } Result;
|
||||||
|
// Resumes the thread. Reports errors and queues yielding threads for later execution
|
||||||
|
// NOTE: The caller is reponsible for balancing the stack
|
||||||
|
Result resume(RBX::Lua::ThreadRef thread, int narg);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////
|
||||||
|
// Stats
|
||||||
|
void scriptResumedFromEvent() { resumedThreads.sample(); }
|
||||||
|
|
||||||
|
size_t getThreadCount() const;
|
||||||
|
shared_ptr<const Reflection::Tuple> getHeapStats(bool clearHighwaterMark);
|
||||||
|
shared_ptr<const Reflection::Tuple> getScriptStats(); // deprecated. Don't use it anymore
|
||||||
|
shared_ptr<const Reflection::ValueArray> getScriptStatsNew();
|
||||||
|
|
||||||
|
struct ScriptStat
|
||||||
|
{
|
||||||
|
std::string hash;
|
||||||
|
std::string name;
|
||||||
|
Instances scripts;
|
||||||
|
double activity;
|
||||||
|
unsigned int invocationCount;
|
||||||
|
};
|
||||||
|
void getScriptStatsTyped(std::vector<ScriptStat>& result);
|
||||||
|
|
||||||
|
double getAvgLuaGcTime() { return avgLuaGcTime.value(); }
|
||||||
|
double getAvgLuaGcInterval() { return avgLuaGcInterval.value(); }
|
||||||
|
|
||||||
|
void reloadModuleScript(shared_ptr<ModuleScript> moduleScript);
|
||||||
|
|
||||||
|
bool checkSecurityAnchorValid() const
|
||||||
|
{
|
||||||
|
return securityAnchor.checkAnchor(&this->securityAnchor);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/*override*/ void onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider);
|
||||||
|
private:
|
||||||
|
rbx::signals::scoped_connection heartbeatConnection;
|
||||||
|
|
||||||
|
boost::scoped_ptr<LuaAllocator> allocator;
|
||||||
|
|
||||||
|
shared_ptr<TaskScheduler::Job> gcJob;
|
||||||
|
shared_ptr<TaskScheduler::Job> waitingScriptsJob;
|
||||||
|
void onHeartbeat(const Heartbeat& heartbeat);
|
||||||
|
void stepGc();
|
||||||
|
void resumeWaitingScripts(Time expirationTime);
|
||||||
|
|
||||||
|
static void sandboxThread(lua_State* thread);
|
||||||
|
static void setThreadIdentityAndSandbox(lua_State* thread, RBX::Security::Identities identity, shared_ptr<BaseScript> script);
|
||||||
|
static RBX::Security::Identities getThreadIdentity(lua_State* thread);
|
||||||
|
|
||||||
|
// Executes a script, throws an std::exception on error
|
||||||
|
// The script is spawned from the global root thread, but it is "sandboxed" to the extent that global declarations
|
||||||
|
// don't affect other threads
|
||||||
|
// If globalStateToExecuteIn is NULL we get the global state to execute in by our current identity, which is the first arg to this function
|
||||||
|
void executeInNewThread(RBX::Security::Identities identity, const ProtectedString& script, const char* name,
|
||||||
|
boost::function1<size_t, lua_State*> pushArguments,
|
||||||
|
boost::function2<void, lua_State*, size_t> readImmediateResults,
|
||||||
|
Scripts::Continuations continuations,
|
||||||
|
lua_State* globalStateToExecuteIn = NULL,
|
||||||
|
const std::map<std::string, shared_ptr<Instance> >* extraGlobals = NULL,
|
||||||
|
unsigned int modkey = 1);
|
||||||
|
|
||||||
|
// Resumes the thread (expects the top of the stack to contain a function)
|
||||||
|
// Throws an std::exception if the thread throws a error
|
||||||
|
void resumeWithArgs(Lua::ThreadRef thread, shared_ptr<const Reflection::Tuple> arguments);
|
||||||
|
void resume(Lua::ThreadRef thread, boost::function1<size_t, lua_State*> pushArguments, boost::function2<void, lua_State*, size_t> readResults);
|
||||||
|
|
||||||
|
void onChangedScriptEnabled(const Reflection::PropertyDescriptor&);
|
||||||
|
void onCheckTimeout();
|
||||||
|
void onHook(lua_State *L, lua_Debug *ar);
|
||||||
|
|
||||||
|
struct ScriptStatInformation
|
||||||
|
{
|
||||||
|
ScriptStatInformation()
|
||||||
|
{}
|
||||||
|
std::string name;
|
||||||
|
Instances scripts;
|
||||||
|
};
|
||||||
|
std::map<std::string, ScriptStatInformation> scriptHashInfo;
|
||||||
|
|
||||||
|
// Functions exposed in the Lua environment:
|
||||||
|
public:
|
||||||
|
static void hook(lua_State *L, lua_Debug *ar);
|
||||||
|
void reportError(lua_State* thread);
|
||||||
|
|
||||||
|
lua_State* getGlobalState(RBX::Security::Identities identity);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int print(lua_State *L);
|
||||||
|
static int doPrint(lua_State *thread, const MessageType& messageType = MESSAGE_OUTPUT);
|
||||||
|
static int crash(lua_State *L);
|
||||||
|
static int tick(lua_State* thread);
|
||||||
|
static int rbxTime(lua_State* thread);
|
||||||
|
static int time(lua_State* thread);
|
||||||
|
static int wait(lua_State* thread);
|
||||||
|
static int delay(lua_State* thread);
|
||||||
|
static int ypcall(lua_State* thread);
|
||||||
|
void on_ypcall_success(Lua::WeakThreadRef caller, lua_State* functor);
|
||||||
|
void on_ypcall_failure(Lua::WeakThreadRef caller, lua_State* functor);
|
||||||
|
static int spawn(lua_State* thread);
|
||||||
|
static int printidentity(lua_State* thread);
|
||||||
|
static int loadfile(lua_State* thread);
|
||||||
|
static int loadstring(lua_State* thread);
|
||||||
|
static int notImplemented(lua_State* thread);
|
||||||
|
static int dofile(lua_State* thread);
|
||||||
|
static int settings(lua_State* thread);
|
||||||
|
static int usersettings(lua_State* thread);
|
||||||
|
static int pluginmanager(lua_State* thread);
|
||||||
|
static int debuggermanager(lua_State *thread);
|
||||||
|
static int loadLibrary(lua_State* L);
|
||||||
|
static int loadRobloxLibrary(lua_State* L);
|
||||||
|
static int requireModuleScript(lua_State* L);
|
||||||
|
static int stats(lua_State* thread);
|
||||||
|
static int version(lua_State* thread);
|
||||||
|
static int statsitemvalue(lua_State* thread);
|
||||||
|
|
||||||
|
static int requireModuleScriptFromInstance(lua_State* L, shared_ptr<ModuleScript> moduleScript);
|
||||||
|
static int requireModuleScriptFromAssetId(lua_State* L, int assetId);
|
||||||
|
static void moduleContentLoaded(AsyncHttpQueue::RequestResult result, shared_ptr<Instances> instances,
|
||||||
|
ScriptContext& sc, Security::Identities identity, lua_State* globalState, AssetModuleInfo* info);
|
||||||
|
static void moduleContentLinkedSourcesResolved(shared_ptr<Instances> instances,
|
||||||
|
shared_ptr<ModuleScript> foundModuleScript, ScriptContext& sc, Security::Identities identity,
|
||||||
|
lua_State* globalState, AssetModuleInfo* info);
|
||||||
|
void startRunningModuleScript(Security::Identities identity, lua_State* globalState, shared_ptr<ModuleScript> moduleScript);
|
||||||
|
static void requireModuleScriptSuccessContinuation(shared_ptr<ModuleScript> moduleScript,
|
||||||
|
lua_State* threadRunningModuleCode);
|
||||||
|
static void requireModuleScriptErrorContinuation(shared_ptr<ModuleScript> moduleScript,
|
||||||
|
lua_State* threadRunningModuleCode);
|
||||||
|
|
||||||
|
static void reloadModuleScriptInternal(lua_State* globalState, shared_ptr<ModuleScript> moduleScript);
|
||||||
|
|
||||||
|
static void reloadModuleScriptSuccessContinuation(shared_ptr<ModuleScript> moduleScript,
|
||||||
|
lua_State* reloadThread,
|
||||||
|
int oldResultRegistryIndex);
|
||||||
|
|
||||||
|
static void reloadModuleScriptErrorContinuation(shared_ptr<ModuleScript> moduleScript,
|
||||||
|
lua_State* reloadThread);
|
||||||
|
|
||||||
|
static int warn(lua_State *L);
|
||||||
|
static void validateThreadAccess(lua_State* L);
|
||||||
|
static int resumeImpl(lua_State* L, int nargs);
|
||||||
|
|
||||||
|
int camelCaseViolationCount;
|
||||||
|
rbx::signals::connection camelCaseViolationConnection;
|
||||||
|
void onCamelCaseViolation(shared_ptr<Instance> object, std::string memberName, shared_ptr<Instance> script);
|
||||||
|
|
||||||
|
friend class BaseScript;
|
||||||
|
void disassociateState(BaseScript* script);
|
||||||
|
|
||||||
|
bool openState(size_t idx);
|
||||||
|
void closeState(lua_State* globalState);
|
||||||
|
|
||||||
|
void startScript(ScriptStart scriptStart);
|
||||||
|
static void eraseScript(std::vector<ScriptContext::ScriptStart>& container, BaseScript* script);
|
||||||
|
void startPendingScripts();
|
||||||
|
|
||||||
|
unsigned int coreScriptModKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
class StackBalanceCheck
|
||||||
|
{
|
||||||
|
const int oldTop;
|
||||||
|
lua_State *thread;
|
||||||
|
bool cancelled;
|
||||||
|
public:
|
||||||
|
StackBalanceCheck(lua_State *thread);
|
||||||
|
~StackBalanceCheck();
|
||||||
|
void cancel() { cancelled = true; }
|
||||||
|
};
|
||||||
|
#define RBXASSERT_BALLANCED_LUA_STACK(L) StackBalanceCheck stackBalanceCheck(L)
|
||||||
|
#define RBXASSERT_BALLANCED_LUA_STACK2(L) StackBalanceCheck stackBalanceCheck2(L)
|
||||||
|
#define CANCEL_BALLANCED_LUA_STACK_CHECK() stackBalanceCheck.cancel()
|
||||||
|
#define CANCEL_BALLANCED_LUA_STACK_CHECK2() stackBalanceCheck2.cancel()
|
||||||
|
#else
|
||||||
|
#define RBXASSERT_BALLANCED_LUA_STACK(L) ((void)0)
|
||||||
|
#define RBXASSERT_BALLANCED_LUA_STACK2(L) ((void)0)
|
||||||
|
#define CANCEL_BALLANCED_LUA_STACK_CHECK() ((void)0)
|
||||||
|
#define CANCEL_BALLANCED_LUA_STACK_CHECK2() ((void)0)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
|
||||||
|
#include "util/runstateowner.h"
|
||||||
|
#include "g3d/Array.h"
|
||||||
|
#include "boost/any.hpp"
|
||||||
|
#include "boost/shared_ptr.hpp"
|
||||||
|
#include "lua/luabridge.h"
|
||||||
|
#include "script/threadref.h"
|
||||||
|
#include <boost/thread/mutex.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct lua_State;
|
||||||
|
class ThreadInfo;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
class Instance;
|
||||||
|
class ScriptContext;
|
||||||
|
|
||||||
|
namespace Lua {
|
||||||
|
|
||||||
|
class YieldingThreads
|
||||||
|
{
|
||||||
|
ScriptContext* context;
|
||||||
|
|
||||||
|
struct WaitingThread
|
||||||
|
{
|
||||||
|
boost::intrusive_ptr<WeakThreadRef> thread;
|
||||||
|
RBX::Time waitTime;
|
||||||
|
RBX::Time resumeTime;
|
||||||
|
WaitingThread(lua_State *L, RBX::Time::Interval requestedDelay)
|
||||||
|
:thread(new WeakThreadRef(L)),
|
||||||
|
waitTime(RBX::Time::now<RBX::Time::Precise>())
|
||||||
|
{
|
||||||
|
resumeTime = waitTime + requestedDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator <(const WaitingThread& other) const
|
||||||
|
{
|
||||||
|
return this->resumeTime > other.resumeTime;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
typedef std::priority_queue< WaitingThread > WaitThreadRefs;
|
||||||
|
|
||||||
|
// Lua refs to threads that are waiting on the event
|
||||||
|
WaitThreadRefs waitingThreads;
|
||||||
|
|
||||||
|
public:
|
||||||
|
YieldingThreads(ScriptContext* context);
|
||||||
|
|
||||||
|
// Hooking up consumers:
|
||||||
|
void queueWaiter(lua_State *L);
|
||||||
|
void queueWaiter(lua_State *L, LUA_NUMBER delay);
|
||||||
|
|
||||||
|
void resume(double wallTime, Time expirationTime, bool& throttling);
|
||||||
|
|
||||||
|
std::size_t waiterCount() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class ScriptContext;
|
||||||
|
void clearAllSinks();
|
||||||
|
};
|
||||||
|
|
||||||
|
// specialization
|
||||||
|
template<>
|
||||||
|
int Bridge<rbx::signals::connection>::on_tostring(const rbx::signals::connection& object, lua_State *L);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
int Bridge<boost::intrusive_ptr<class WeakThreadRef::Node> >::on_tostring(const boost::intrusive_ptr<class WeakThreadRef::Node>& object, lua_State *L);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
int Bridge< shared_ptr<GenericFunction> >::on_tostring(const shared_ptr<GenericFunction>& object, lua_State *L);
|
||||||
|
|
||||||
|
template<>
|
||||||
|
int Bridge< shared_ptr<GenericAsyncFunction> >::on_tostring(const shared_ptr<GenericAsyncFunction>& object, lua_State *L);
|
||||||
|
|
||||||
|
} }
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "rbx/RunningAverage.h"
|
||||||
|
#include "boost/weak_ptr.hpp"
|
||||||
|
#include "util/Utilities.h"
|
||||||
|
#include "V8DataModel/Stats.h"
|
||||||
|
#include "script/ScriptContext.h"
|
||||||
|
#include <stack>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
|
||||||
|
class ScriptStats
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct StatCollection
|
||||||
|
{
|
||||||
|
boost::shared_ptr<ActivityMeter<2> > activity;
|
||||||
|
boost::shared_ptr<InvocationMeter<2> > invocations;
|
||||||
|
};
|
||||||
|
typedef std::map<std::string, StatCollection> ScriptActivityMeterMap;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ScriptActivityMeterMap scriptActivityMap;
|
||||||
|
|
||||||
|
std::stack<std::string> scriptStack;
|
||||||
|
|
||||||
|
void stopCollection(const std::string& scriptHash);
|
||||||
|
void startCollection(const std::string& scriptHash, bool firstTime);
|
||||||
|
public:
|
||||||
|
|
||||||
|
ScriptStats();
|
||||||
|
|
||||||
|
void scriptResumeStarted(const std::string& scriptHash);
|
||||||
|
void scriptResumeStopped(const std::string& scriptHash);
|
||||||
|
|
||||||
|
const ScriptActivityMeterMap& getScriptActivityMap() const { return scriptActivityMap; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class LuaStatsItem : public Stats::Item
|
||||||
|
{
|
||||||
|
ScriptContext* scriptContext;
|
||||||
|
Stats::Item* averageGcInterval;
|
||||||
|
Stats::Item* averageGcTime;
|
||||||
|
Stats::Item* resumedThreads;
|
||||||
|
Stats::Item* deferredThreads;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LuaStatsItem(ScriptContext* context) : scriptContext(context)
|
||||||
|
{
|
||||||
|
setName("Lua");
|
||||||
|
}
|
||||||
|
|
||||||
|
static shared_ptr<LuaStatsItem> create(ScriptContext* context)
|
||||||
|
{
|
||||||
|
shared_ptr<LuaStatsItem> result = Creatable<Instance>::create<LuaStatsItem>(context);
|
||||||
|
result->init();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
virtual void update();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,185 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "rbx/intrusive_ptr_target.h"
|
||||||
|
#include "boost/intrusive_ptr.hpp"
|
||||||
|
#include "rbx/boost.hpp"
|
||||||
|
#include "rbx/threadsafe.h"
|
||||||
|
#include "reflection/type.h"
|
||||||
|
|
||||||
|
struct lua_State;
|
||||||
|
|
||||||
|
using boost::shared_ptr;
|
||||||
|
|
||||||
|
LOGGROUP(WeakThreadRef)
|
||||||
|
|
||||||
|
namespace RBX {
|
||||||
|
|
||||||
|
namespace Lua {
|
||||||
|
|
||||||
|
void dumpThreadRefCounts();
|
||||||
|
|
||||||
|
// Used internally
|
||||||
|
namespace detail {
|
||||||
|
class LiveThreadRef
|
||||||
|
: public rbx::quick_intrusive_ptr_target<LiveThreadRef>
|
||||||
|
, public Diagnostics::Countable<LiveThreadRef>
|
||||||
|
, boost::noncopyable
|
||||||
|
{
|
||||||
|
lua_State* L;
|
||||||
|
int threadId;
|
||||||
|
friend class WeakThreadRef;
|
||||||
|
friend class ThreadRef;
|
||||||
|
public:
|
||||||
|
// Do not create this. It is an internal class
|
||||||
|
LiveThreadRef (lua_State* thread);
|
||||||
|
~LiveThreadRef();
|
||||||
|
bool empty() const {
|
||||||
|
return L == NULL;
|
||||||
|
}
|
||||||
|
lua_State* thread() const {
|
||||||
|
return L;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// You get this by calling lock() on WeakThreadRef
|
||||||
|
class ThreadRef
|
||||||
|
: public Diagnostics::Countable<ThreadRef>
|
||||||
|
{
|
||||||
|
boost::intrusive_ptr<detail::LiveThreadRef> liveThreadRef;
|
||||||
|
friend class WeakThreadRef;
|
||||||
|
ThreadRef (detail::LiveThreadRef* liveThreadRef):liveThreadRef(liveThreadRef) {}
|
||||||
|
public:
|
||||||
|
ThreadRef() {}
|
||||||
|
ThreadRef(lua_State* thread)
|
||||||
|
:liveThreadRef(new detail::LiveThreadRef(thread)) {}
|
||||||
|
lua_State* get() const {
|
||||||
|
return liveThreadRef ? liveThreadRef->thread() : NULL;
|
||||||
|
}
|
||||||
|
operator lua_State*() const
|
||||||
|
{
|
||||||
|
return get();
|
||||||
|
}
|
||||||
|
bool empty() const {
|
||||||
|
return liveThreadRef && liveThreadRef->thread() != NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Registers a weak reference to a thread, ensuring that it isn't collected (sometimes)
|
||||||
|
class WeakThreadRef
|
||||||
|
: public rbx::quick_intrusive_ptr_target<WeakThreadRef>
|
||||||
|
, boost::noncopyable
|
||||||
|
, public Diagnostics::Countable<WeakThreadRef>
|
||||||
|
{
|
||||||
|
// TODO: boost::mutex would be safer
|
||||||
|
typedef rbx::spin_mutex Mutex;
|
||||||
|
static Mutex sync;
|
||||||
|
public:
|
||||||
|
class Node
|
||||||
|
: public rbx::quick_intrusive_ptr_target<Node>
|
||||||
|
, boost::noncopyable
|
||||||
|
{
|
||||||
|
friend class WeakThreadRef;
|
||||||
|
WeakThreadRef* first;
|
||||||
|
public:
|
||||||
|
Node():first(0) {}
|
||||||
|
~Node();
|
||||||
|
static boost::intrusive_ptr<Node> create(lua_State* thread);
|
||||||
|
static Node* get(lua_State* thread);
|
||||||
|
|
||||||
|
// Clear all refs to thread and its children
|
||||||
|
void eraseAllRefs();
|
||||||
|
|
||||||
|
template<class Func>
|
||||||
|
void forEachRefs(Func func)
|
||||||
|
{
|
||||||
|
for (WeakThreadRef* ref = first; ref!=NULL; ref = ref->next)
|
||||||
|
{
|
||||||
|
func(ref->lock());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
friend class Node;
|
||||||
|
private:
|
||||||
|
WeakThreadRef* previous;
|
||||||
|
WeakThreadRef* next;
|
||||||
|
boost::intrusive_ptr<detail::LiveThreadRef> liveThreadRef;
|
||||||
|
void addRef(lua_State* L);
|
||||||
|
void addToNode();
|
||||||
|
void removeFromNode();
|
||||||
|
protected:
|
||||||
|
Node* node;
|
||||||
|
virtual void removeRef();
|
||||||
|
lua_State* thread() const {
|
||||||
|
return threadDangerous();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
WeakThreadRef():node(0), previous(0), next(0) {}
|
||||||
|
WeakThreadRef(lua_State* thread);
|
||||||
|
WeakThreadRef(const WeakThreadRef& other);
|
||||||
|
WeakThreadRef& operator=(const WeakThreadRef& other);
|
||||||
|
virtual ~WeakThreadRef();
|
||||||
|
|
||||||
|
bool operator==(const WeakThreadRef& other) const;
|
||||||
|
bool operator!=(const WeakThreadRef& other) const;
|
||||||
|
void reset();
|
||||||
|
bool empty() const {
|
||||||
|
return liveThreadRef ? liveThreadRef->thread()==0 : true;
|
||||||
|
}
|
||||||
|
ThreadRef lock()
|
||||||
|
{
|
||||||
|
return ThreadRef(liveThreadRef.get());
|
||||||
|
}
|
||||||
|
lua_State* threadDangerous() const {
|
||||||
|
return liveThreadRef ? liveThreadRef->thread() : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// A function that takes any number of arguments and returns a tuple
|
||||||
|
typedef boost::function<shared_ptr<const Reflection::Tuple>(shared_ptr<const Reflection::Tuple>)> GenericFunction;
|
||||||
|
|
||||||
|
class IAsyncResult
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// This may throw
|
||||||
|
virtual boost::shared_ptr<const Reflection::Tuple> getValue() = 0;
|
||||||
|
virtual ~IAsyncResult() {}
|
||||||
|
};
|
||||||
|
// A function that takes any number of arguments and returns the result through a callback
|
||||||
|
typedef boost::function<void(shared_ptr<const Reflection::Tuple>, boost::function<void(IAsyncResult*)>)> GenericAsyncFunction;
|
||||||
|
|
||||||
|
class WeakFunctionRef : public WeakThreadRef
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
int functionId;
|
||||||
|
typedef WeakThreadRef Super;
|
||||||
|
public:
|
||||||
|
WeakFunctionRef():functionId(0) {}
|
||||||
|
|
||||||
|
WeakFunctionRef(lua_State* thread, int index); // Constructs a FunctionRef from the Lua stack
|
||||||
|
|
||||||
|
virtual ~WeakFunctionRef();
|
||||||
|
|
||||||
|
// Copy:
|
||||||
|
WeakFunctionRef(const WeakFunctionRef& other);
|
||||||
|
WeakFunctionRef& operator=(const WeakFunctionRef& other);
|
||||||
|
|
||||||
|
// Query:
|
||||||
|
bool operator==(const WeakFunctionRef& other) const;
|
||||||
|
bool operator!=(const WeakFunctionRef& other) const;
|
||||||
|
|
||||||
|
friend WeakFunctionRef lua_tofunction(lua_State* L);
|
||||||
|
friend void lua_pushfunction(lua_State* L, const WeakFunctionRef& function);
|
||||||
|
protected:
|
||||||
|
virtual void removeRef();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Operations with Lua
|
||||||
|
WeakFunctionRef lua_tofunction(lua_State* L, int index);
|
||||||
|
void lua_pushfunction(lua_State* L, const WeakFunctionRef& function);
|
||||||
|
void lua_pushfunction(lua_State* L, shared_ptr<GenericFunction> function);
|
||||||
|
void lua_pushfunction(lua_State* L, shared_ptr<GenericAsyncFunction> function);
|
||||||
|
|
||||||
|
} }
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "V8Tree/Instance.h"
|
||||||
|
#include "Script/ThreadRef.h"
|
||||||
|
#include "Util/ScriptInformationProvider.h"
|
||||||
|
#include "Util/ProtectedString.h"
|
||||||
|
#include "script/LuaSourceContainer.h"
|
||||||
|
#include "rbx/atomic.h"
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
#include <boost/flyweight.hpp>
|
||||||
|
|
||||||
|
struct lua_State;
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
class IScriptOwner;
|
||||||
|
class ScriptContext;
|
||||||
|
class RuntimeScriptService;
|
||||||
|
class ScriptInformationProvider;
|
||||||
|
class ContentProvider;
|
||||||
|
|
||||||
|
namespace Network
|
||||||
|
{
|
||||||
|
class Player;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef ContentId ScriptId;
|
||||||
|
extern const char* const sBaseScript;
|
||||||
|
class BaseScript
|
||||||
|
: public DescribedNonCreatable<BaseScript, LuaSourceContainer, sBaseScript>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef DescribedNonCreatable<BaseScript, LuaSourceContainer, sBaseScript> Super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
class Slot;
|
||||||
|
|
||||||
|
// Used for development only. It allows you to load CoreScripts from your local disk
|
||||||
|
static std::string adminScriptsPath;
|
||||||
|
static bool hasCoreScriptReplacements();
|
||||||
|
|
||||||
|
void restartScript();
|
||||||
|
protected:
|
||||||
|
RuntimeScriptService* workspace;
|
||||||
|
|
||||||
|
///////////////////////////////////
|
||||||
|
// Instance
|
||||||
|
/*override*/ void onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider);
|
||||||
|
/*override*/ void onAncestorChanged(const AncestorChanged& event);
|
||||||
|
/*override*/ void onScriptIdChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const std::string emptyString;
|
||||||
|
|
||||||
|
weak_ptr<RBX::Network::Player> localPlayer;
|
||||||
|
|
||||||
|
bool disabled;
|
||||||
|
bool badLinkedScript;
|
||||||
|
|
||||||
|
RuntimeScriptService* computeNewWorkspace();
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct Code
|
||||||
|
{
|
||||||
|
bool loaded;
|
||||||
|
boost::flyweight<ProtectedString> script;
|
||||||
|
|
||||||
|
Code()
|
||||||
|
:loaded(false)
|
||||||
|
{}
|
||||||
|
Code(const boost::flyweight<ProtectedString>& script)
|
||||||
|
:loaded(true)
|
||||||
|
,script(script)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
BaseScript();
|
||||||
|
~BaseScript();
|
||||||
|
|
||||||
|
|
||||||
|
static const Reflection::PropDescriptor<BaseScript, ScriptId> prop_SourceCodeId;
|
||||||
|
|
||||||
|
weak_ptr<RBX::Network::Player> getLocalPlayer() { return localPlayer; }
|
||||||
|
void setLocalPlayer(const shared_ptr<RBX::Network::Player>& localPlayer) { this->localPlayer = localPlayer; }
|
||||||
|
|
||||||
|
// Thread management
|
||||||
|
boost::intrusive_ptr<Lua::WeakThreadRef::Node> threadNode;
|
||||||
|
rbx::signal<void(lua_State*)> starting;
|
||||||
|
rbx::signal<void()> stopped;
|
||||||
|
|
||||||
|
bool isDisabled() const { return disabled; }
|
||||||
|
static const Reflection::PropDescriptor<BaseScript, bool> prop_Disabled;
|
||||||
|
|
||||||
|
virtual Code requestCode(ScriptInformationProvider* scriptInfoProvider=NULL);
|
||||||
|
|
||||||
|
virtual void extraErrorReporting(lua_State *thread) {}
|
||||||
|
|
||||||
|
//Properties
|
||||||
|
bool getDisabled() const { return disabled; }
|
||||||
|
void setDisabled(bool value);
|
||||||
|
|
||||||
|
virtual const std::string& requestHash() const;
|
||||||
|
};
|
||||||
|
// A BaseScript is started when a containing IScriptOwner sends it to the ScriptContext service
|
||||||
|
extern const char* const sScript;
|
||||||
|
class Script
|
||||||
|
: public DescribedCreatable<Script, BaseScript, sScript>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
typedef DescribedCreatable<Script, BaseScript, sScript> Super;
|
||||||
|
|
||||||
|
private:
|
||||||
|
boost::flyweight<ProtectedString> embeddedSource;
|
||||||
|
std::string embeddedSourceHash;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Script();
|
||||||
|
~Script();
|
||||||
|
|
||||||
|
static const Reflection::PropDescriptor<Script, ProtectedString> prop_EmbeddedSourceCode;
|
||||||
|
|
||||||
|
/*override*/ XmlElement* writeXml(const boost::function<bool(Instance*)>& isInScope, RBX::CreatorRole creatorRole)
|
||||||
|
{
|
||||||
|
return Super::writeXml(isInScope, creatorRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*override*/ bool askSetParent(const Instance* instance) const
|
||||||
|
{
|
||||||
|
// Scripts can be anywhere
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isCodeEmbedded() const { return getScriptId().isNull(); }
|
||||||
|
|
||||||
|
/*override*/ Code requestCode(ScriptInformationProvider* scriptInfoProvider=NULL);
|
||||||
|
|
||||||
|
/*override*/ const std::string& requestHash() const;
|
||||||
|
|
||||||
|
void setEmbeddedCode(const ProtectedString& value);
|
||||||
|
const boost::flyweight<ProtectedString>& getEmbeddedCode() const;
|
||||||
|
const ProtectedString& getEmbeddedCodeSafe() const;
|
||||||
|
/*override*/ int getPersistentDataCost() const;
|
||||||
|
/*override*/ void fireSourceChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string getHash() { return requestHash(); }
|
||||||
|
|
||||||
|
static const Reflection::BoundFuncDesc<Script, std::string()> func_GetHash;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Only runs on a local machine if either
|
||||||
|
// a) Inside a tool which is inside a local character
|
||||||
|
// b) Inside the local backpack
|
||||||
|
|
||||||
|
// Local scripts have the full power of a normal script, but can also interact with the Mouse.
|
||||||
|
// While they are currently run client side, this is a large security hole that will have to be addressed.
|
||||||
|
// The plan is to have them execute server side, but with an adapter taking the place of the "Mouse" object and abstracting it per-user
|
||||||
|
//
|
||||||
|
// A better name would be GuiScript or UserScript, if we could redo this work.
|
||||||
|
extern const char* const sLocalScript;
|
||||||
|
class LocalScript
|
||||||
|
: public DescribedCreatable<LocalScript, Script, sLocalScript>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
LocalScript();
|
||||||
|
~LocalScript() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class BaseScript::Slot
|
||||||
|
{
|
||||||
|
rbx::signals::connection connection;
|
||||||
|
public:
|
||||||
|
// A Slot must keep a reference to its connection, because it
|
||||||
|
// must be capable of disconnecting itself.
|
||||||
|
void assignConnection(const rbx::signals::connection& connection)
|
||||||
|
{
|
||||||
|
this->connection = connection;
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
Slot()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
~Slot()
|
||||||
|
{
|
||||||
|
// TODO: Disconnect here???
|
||||||
|
}
|
||||||
|
void disconnect()
|
||||||
|
{
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,377 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "Security/FuzzyTokens.h"
|
||||||
|
#include "Security/RandomConstant.h"
|
||||||
|
|
||||||
|
#if defined(RBX_PLATFORM_DURANGO)
|
||||||
|
#define NOINLINE __declspec(noinline)
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#include <windows.h>
|
||||||
|
#include <winternl.h>
|
||||||
|
#undef min
|
||||||
|
|
||||||
|
#define FORCEINLINE __forceinline
|
||||||
|
#define NOINLINE __declspec(noinline)
|
||||||
|
|
||||||
|
// All of the .text
|
||||||
|
namespace RBX{ namespace Security {
|
||||||
|
extern volatile const uintptr_t rbxTextBase;
|
||||||
|
extern volatile const size_t rbxTextSize;
|
||||||
|
extern volatile const uintptr_t rbxTextEndNeg;
|
||||||
|
extern volatile const size_t rbxTextSizeNeg;
|
||||||
|
extern volatile const uintptr_t rbxVmpBase;
|
||||||
|
extern volatile const size_t rbxVmpSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define FORCEINLINE inline __attribute__((always_inline))
|
||||||
|
#define NOINLINE __attribute__((noinline))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// This file defines some secure caller function to prevent key functions
|
||||||
|
// from being called from a dll.
|
||||||
|
//
|
||||||
|
// For many functions, this is actually intractable. With just a return address
|
||||||
|
// check, someone can simply push the location of a "C3" byte (ret) in our code
|
||||||
|
// and then jump to our function. The return address will appear to be in our code.
|
||||||
|
//
|
||||||
|
// When the check becomes stronger, it is a simple matter to find the target
|
||||||
|
// function called from another function in our code. From this point it is easy
|
||||||
|
// to call (into) that function. Even if the result isn't directly returned, it
|
||||||
|
// will typically be on the stack.
|
||||||
|
//
|
||||||
|
// callbacks are problematic. On one hand, we can check callbacks before setting
|
||||||
|
// and before calling them. However, callbacks could be set to "CC" bytes (int 3) in
|
||||||
|
// our code, which would throw an exception that could be handled.
|
||||||
|
//
|
||||||
|
// Secure calling in this file almost certainly will not work within a VM protected
|
||||||
|
// section as the registers and stack will be nonstandard.
|
||||||
|
//
|
||||||
|
// It will be trivial to find where these checks are done as well, as they all
|
||||||
|
// modify the same global values.
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
FORCEINLINE static bool isRbxTextAddr(const void* const ptr)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) && !defined(RBX_PLATFORM_DURANGO) && !defined(RBX_STUDIO_BUILD)
|
||||||
|
return (reinterpret_cast<uintptr_t>(ptr) - RBX::Security::rbxTextBase < RBX::Security::rbxTextSize);
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template<unsigned int value> FORCEINLINE void callCheckSetBasicFlag(unsigned int flags)
|
||||||
|
{
|
||||||
|
Tokens::sendStatsToken.addFlagFast(value);
|
||||||
|
Tokens::simpleToken |= value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 33222222222 2 1 111 11111100 000 0 0 000
|
||||||
|
// 10987654321 0 9 876 54321098 765 4 3 210
|
||||||
|
// rsvd cpy pi veh ntapi cs locked name
|
||||||
|
static const unsigned int kNameApiOffset = 0;
|
||||||
|
static const unsigned int kRbxLockedApiOffset = 3;
|
||||||
|
static const unsigned int kChangeStateApiOffset = 4;
|
||||||
|
static const unsigned int kNtApiNoNtdll = (1<<8);
|
||||||
|
static const unsigned int kNtApiNoText = (1<<9);
|
||||||
|
static const unsigned int kNtApiNoApi = (1<<10);
|
||||||
|
static const unsigned int kNtApiNoSyscall = (1<<11);
|
||||||
|
static const unsigned int kNtApiNoTemplate = (1<<12);
|
||||||
|
static const unsigned int kNtApiEarly = (1<<13);
|
||||||
|
static const unsigned int kNtApiHash = (1<<14);
|
||||||
|
static const unsigned int kNtApiNoCall = (1<<15);
|
||||||
|
static const unsigned int kVehWpmFail = (1<<16);
|
||||||
|
static const unsigned int kVehPrologFail = (1<<17);
|
||||||
|
static const unsigned int kVehNoNtdll = (1<<18);
|
||||||
|
static const unsigned int kPingItem = (1<<19);
|
||||||
|
static const unsigned int kScriptContextCopy = (1<<20);
|
||||||
|
static const unsigned int kLuaHooked = (1<<21);
|
||||||
|
|
||||||
|
|
||||||
|
template<unsigned int offset> FORCEINLINE void callCheckSetApiFlag(unsigned int flags)
|
||||||
|
{
|
||||||
|
Tokens::apiToken.addFlagSafe(flags << offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
FORCEINLINE void callCheckNop(unsigned int flags)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// This checks that the return address:
|
||||||
|
// 1) is within the .text section
|
||||||
|
// 2) calling instruction has a correct relative offset. (must be call imm32)
|
||||||
|
// 3) caller of calling function is within our .text section
|
||||||
|
// Disabled in NoOpt because this won't be inlined.
|
||||||
|
static const int kCallCheckCodeOnly = 1;
|
||||||
|
static const int kCallCheckCallArg = 2;
|
||||||
|
static const int kCallCheckCallersCode = 3;
|
||||||
|
static const int kCallCheckRegCall = 4;
|
||||||
|
|
||||||
|
template<int level, void(*action)(unsigned int)>
|
||||||
|
FORCEINLINE static unsigned int checkRbxCaller(const void* const funcAddress)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) && !defined(_NOOPT) && !defined(LOVE_ALL_ACCESS) && !defined(RBX_STUDIO_BUILD) && !defined(RBX_PLATFORM_DURANGO)
|
||||||
|
unsigned int flags = 0;
|
||||||
|
|
||||||
|
void* returnAddress = _ReturnAddress();
|
||||||
|
flags |= isRbxTextAddr(returnAddress) ? 0 : (1<<0);
|
||||||
|
if (!flags)
|
||||||
|
{
|
||||||
|
switch(level)
|
||||||
|
{
|
||||||
|
case kCallCheckCallersCode:
|
||||||
|
{
|
||||||
|
void* aora = _AddressOfReturnAddress();
|
||||||
|
void* secondReturnAddress = (*((void***)(aora)-1))[1];
|
||||||
|
flags |= isRbxTextAddr(secondReturnAddress) ? 0 : (1<<2);
|
||||||
|
}
|
||||||
|
// continue
|
||||||
|
case kCallCheckCallArg:
|
||||||
|
{
|
||||||
|
unsigned int offset = *((unsigned int*)(returnAddress) - 1);
|
||||||
|
flags |= (offset == ((unsigned int)(funcAddress)
|
||||||
|
- (unsigned int)(returnAddress))) ? 0 : (1<<1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case kCallCheckRegCall:
|
||||||
|
{
|
||||||
|
// this is a weaker check. call r32 is a prefixed 2 byte instruction.
|
||||||
|
// because the register may have changed before this is called, there
|
||||||
|
// isn't much point in checking it.
|
||||||
|
static const unsigned short kX86RegCall = 0xD7FF; // due to little endian
|
||||||
|
unsigned short opcode = *((unsigned short*)(returnAddress) - 1);
|
||||||
|
flags |= ((opcode|0x0700) == kX86RegCall) ? 0 : (1<<3);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flags)
|
||||||
|
{
|
||||||
|
action(flags);
|
||||||
|
}
|
||||||
|
return flags;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Security{
|
||||||
|
static const unsigned int kCheckDefault = 0;
|
||||||
|
static const unsigned int kCheckReturnAddr = 1;
|
||||||
|
static const unsigned int kCheckNoThreadInit = 2;
|
||||||
|
static const unsigned int kAllowVmpAll = 4; // I'm not sure if I only need to look at mutant, mutant+plain, etc...
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only supporting ntdll for now.
|
||||||
|
#if defined(_WIN32) && !defined(RBX_PLATFORM_DURANGO)
|
||||||
|
|
||||||
|
inline const WCHAR* getUnicodeDllName(const UNICODE_STRING& str)
|
||||||
|
{
|
||||||
|
USHORT idx;
|
||||||
|
for (idx = str.Length/sizeof(WCHAR); idx != 0; --idx)
|
||||||
|
{
|
||||||
|
if (str.Buffer[idx] == L'\\')
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str.Buffer + idx + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This gets the location of ntdll using the documented parts of the PE format.
|
||||||
|
// The intent is to make it harder for anyone who wants to hook GetModuleHandle.
|
||||||
|
// This is not foolproof as the PEB or PEB pointer could be modified.
|
||||||
|
inline HMODULE rbxGetNtdll()
|
||||||
|
{
|
||||||
|
const WCHAR* kNtDll = L"ntdll.dll";
|
||||||
|
PEB* peb = reinterpret_cast<PEB*>(__readfsdword(0x30));
|
||||||
|
PEB_LDR_DATA* pebLdrData = peb->Ldr;
|
||||||
|
LIST_ENTRY imoListBase = pebLdrData->InMemoryOrderModuleList;
|
||||||
|
LIST_ENTRY* imoListWalk = &imoListBase;
|
||||||
|
int moduleLimit = 256;
|
||||||
|
while ((imoListWalk->Flink != imoListBase.Blink) && --moduleLimit)
|
||||||
|
{
|
||||||
|
imoListWalk = imoListWalk->Flink;
|
||||||
|
LDR_DATA_TABLE_ENTRY* thisPe = reinterpret_cast<LDR_DATA_TABLE_ENTRY*>(reinterpret_cast<BYTE*>(imoListWalk) - 8);
|
||||||
|
const WCHAR* dllName = getUnicodeDllName(thisPe->FullDllName);
|
||||||
|
const int dllNameLen = (thisPe->FullDllName.Length - (dllName - thisPe->FullDllName.Buffer))/sizeof(WCHAR);
|
||||||
|
|
||||||
|
//filter here
|
||||||
|
unsigned int dest = ((unsigned int)(kNtDll) + RBX_BUILDSEED);
|
||||||
|
volatile unsigned int tmp = dest;
|
||||||
|
const WCHAR* const ntdllName = (const WCHAR* const)(tmp - RBX_BUILDSEED);
|
||||||
|
if (_wcsnicmp(dllName, ntdllName, std::min(dllNameLen, 9)) == 0)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<HMODULE>(thisPe->DllBase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Find the location of the function matched by "filter" within ntdll's export table.
|
||||||
|
// Doesn't directly expose the name of the function that has been matched.
|
||||||
|
inline void* rbxNtdllProcAddress(HMODULE module, bool filter(const char*) )
|
||||||
|
{
|
||||||
|
DWORD* loc = 0;
|
||||||
|
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)module;
|
||||||
|
PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS)(pDosHeader->e_lfanew + (char *)pDosHeader);
|
||||||
|
IMAGE_DATA_DIRECTORY* imageDataDir = pNTHeader->OptionalHeader.DataDirectory;
|
||||||
|
DWORD exportVa = imageDataDir[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress;
|
||||||
|
DWORD base = reinterpret_cast<DWORD>(module);
|
||||||
|
PIMAGE_EXPORT_DIRECTORY pExport = reinterpret_cast<PIMAGE_EXPORT_DIRECTORY>(base + exportVa);
|
||||||
|
DWORD* pAddressOfNames = reinterpret_cast<DWORD*>(pExport->AddressOfNames + base);
|
||||||
|
DWORD* pAddressOfFuncs = reinterpret_cast<DWORD*>(pExport->AddressOfFunctions + base);
|
||||||
|
WORD* pAddressOfOrds = reinterpret_cast<WORD*> (pExport->AddressOfNameOrdinals + base);
|
||||||
|
for (DWORD i = 0; i < pExport->NumberOfNames; ++i)
|
||||||
|
{
|
||||||
|
if (filter(reinterpret_cast<const char*>(base + pAddressOfNames[i])))
|
||||||
|
{
|
||||||
|
return reinterpret_cast<DWORD*>(base + pAddressOfFuncs[pAddressOfOrds[i]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct CallChainInfo
|
||||||
|
{
|
||||||
|
uint32_t handler;
|
||||||
|
uint32_t ret;
|
||||||
|
CallChainInfo() : handler(0), ret(0) {}
|
||||||
|
CallChainInfo(uint32_t handler, uint32_t ret) : handler(handler), ret(ret) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(RBX_STUDIO_BUILD) && !defined(RBX_RCC_SECURITY) && !defined(RBX_PLATFORM_DURANGO)
|
||||||
|
// Call Stack, function with:
|
||||||
|
//
|
||||||
|
// == C++ Exceptions == | == SEH3 Exceptions ==
|
||||||
|
// +1C locals | +20 locals
|
||||||
|
// ... | ...
|
||||||
|
// +10 GS Cookie | +10 *nextHandler()
|
||||||
|
// + C *nextHandler | + C *handler()
|
||||||
|
// + 8 *handler() | + 8 scopeTable
|
||||||
|
// + 4 state | + 4 tryLevel
|
||||||
|
// +00 saved ebp | +00 saved ebp
|
||||||
|
// - 4 return address | - 4 return address
|
||||||
|
// - 8 first arg | - 8 first arg
|
||||||
|
// -xx last arg | -xx last arg
|
||||||
|
//
|
||||||
|
// This will get generated in some functions that don't have try-catch blocks. Basically
|
||||||
|
// if something could throw, objects might need to be destroyed.
|
||||||
|
//
|
||||||
|
// fs:[0] also contains a pointer to nextHandler, but is out of place in the middle of a
|
||||||
|
// function.
|
||||||
|
//
|
||||||
|
// The list will always have a size of at least 2 -- the entry in ntdll and the entry we
|
||||||
|
// started with.
|
||||||
|
//
|
||||||
|
// There is a case with boost::threads, as these get created with msvcr's threadstartex
|
||||||
|
// (after ntdll rtlInitThread). However, boost::threads will have three exception handlers
|
||||||
|
// in the boost code before getting into msvcr.
|
||||||
|
|
||||||
|
template<size_t kMaxDepth> FORCEINLINE uint32_t detectDllByExceptionChain(void* addrOfChain, unsigned int kFlags)
|
||||||
|
{
|
||||||
|
static const size_t kStackNextIdx = 0;
|
||||||
|
static const size_t kStackHandlerIdx = 1;
|
||||||
|
static const size_t kStackReturnIdx = 4;
|
||||||
|
static const size_t kStackEndingArgIdx = 6;
|
||||||
|
DWORD* stkPtr = reinterpret_cast<DWORD*>(addrOfChain);
|
||||||
|
uintptr_t textEndNeg = RBX::Security::rbxTextEndNeg;
|
||||||
|
size_t textSizeNeg = RBX::Security::rbxTextSizeNeg;
|
||||||
|
uintptr_t vmpBase = RBX::Security::rbxVmpBase;
|
||||||
|
size_t vmpSize = RBX::Security::rbxVmpSize;
|
||||||
|
uint32_t result = 0;
|
||||||
|
for (size_t i = 0; i < kMaxDepth; ++i)
|
||||||
|
{
|
||||||
|
// check for end of chain in ntdll.
|
||||||
|
if (!(kFlags & Security::kCheckNoThreadInit) && (stkPtr[0] == 0xFFFFFFFF))
|
||||||
|
{
|
||||||
|
// check if handler chain init in roblox. (equivalent to "addr - base >= size")
|
||||||
|
if ((stkPtr[kStackEndingArgIdx] + textEndNeg ) <= textSizeNeg)
|
||||||
|
{
|
||||||
|
result |= 1 << (i*3);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// check if handler in roblox code. (equivalent to "addr - base >= size")
|
||||||
|
if ((stkPtr[kStackHandlerIdx] + textEndNeg ) <= textSizeNeg)
|
||||||
|
{
|
||||||
|
result |= 1 << (i*3 + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( (kFlags & Security::kCheckReturnAddr) // check return enabled
|
||||||
|
&& (stkPtr[kStackReturnIdx] + textEndNeg ) <= textSizeNeg) // not in .text
|
||||||
|
{
|
||||||
|
if (!((kFlags&Security::kAllowVmpAll) // allow vmp
|
||||||
|
&& (stkPtr[kStackReturnIdx] - vmpBase ) > vmpSize)) // not in vmp
|
||||||
|
{
|
||||||
|
result |= 1 << (i*3 + 2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// follow next
|
||||||
|
stkPtr = reinterpret_cast<DWORD*>(stkPtr[kStackNextIdx]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t kMaxDepth> FORCEINLINE void generateCallInfo(void* addrOfFirstArg, std::vector<CallChainInfo>& info)
|
||||||
|
{
|
||||||
|
static const size_t kStackNextIdx = 0;
|
||||||
|
static const size_t kStackHandlerIdx = 1;
|
||||||
|
static const size_t kStackReturnIdx = 4;
|
||||||
|
static const size_t kStackEndingArgIdx = 6;
|
||||||
|
static const size_t kStackFirstArgToNextHandler = 5;
|
||||||
|
DWORD* stkPtr = reinterpret_cast<DWORD*>(addrOfFirstArg) - kStackFirstArgToNextHandler;
|
||||||
|
for (size_t i = 0; i < kMaxDepth; ++i)
|
||||||
|
{
|
||||||
|
info.push_back(CallChainInfo(stkPtr[kStackHandlerIdx],stkPtr[kStackReturnIdx]));
|
||||||
|
// check for end of chain in ntdll.
|
||||||
|
if (stkPtr[0] == 0xFFFFFFFF)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// follow next
|
||||||
|
stkPtr = reinterpret_cast<DWORD*>(stkPtr[kStackNextIdx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t kMaxDepth> FORCEINLINE uint32_t detectDllByExceptionChainStack(void* addrOfFirstArg, unsigned int kFlags)
|
||||||
|
{
|
||||||
|
static const size_t kStackFirstArgToNextHandler = 5;
|
||||||
|
DWORD* stkPtr = reinterpret_cast<DWORD*>(addrOfFirstArg) - kStackFirstArgToNextHandler;
|
||||||
|
return detectDllByExceptionChain<kMaxDepth>(stkPtr, kFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// not all functions add an exception handler to the chain, so the stack based method doesn't
|
||||||
|
// always work.
|
||||||
|
template<size_t kMaxDepth> FORCEINLINE uint32_t detectDllByExceptionChainTeb(unsigned int kFlags)
|
||||||
|
{
|
||||||
|
return detectDllByExceptionChain<kMaxDepth>(reinterpret_cast<void*>(__readfsdword(0)), kFlags );
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
template<size_t kMaxDepth> FORCEINLINE uint32_t detectDllByExceptionChainTeb(unsigned int kFlags)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
template<size_t kMaxDepth> FORCEINLINE uint32_t detectDllByExceptionChainStack(void* addrOfFirstArg, unsigned int kFlags)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t kMaxDepth> FORCEINLINE void generateCallInfo(void* addrOfFirstArg, std::vector<CallChainInfo>& info)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "boost/thread/mutex.hpp"
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
// This is designed to be an anti-tamper security reporting mechanism.
|
||||||
|
// Add flag is based on the number of bits in the flag, and succeeds
|
||||||
|
// with probability 1 - 0.5**N per transmitted packet. This might
|
||||||
|
// seem like an issue, but most of the checks will re-trigger an addition
|
||||||
|
// meaning an exploiter is unlikely to be in the game for more than 30
|
||||||
|
// seconds. Attempts to modify the packet are very likely to fail.
|
||||||
|
|
||||||
|
namespace Security
|
||||||
|
{
|
||||||
|
unsigned long long teaDecrypt(unsigned long long inTag);
|
||||||
|
unsigned long long teaEncrypt(unsigned long long inTag);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Tokens
|
||||||
|
{
|
||||||
|
union binaryTag
|
||||||
|
{
|
||||||
|
unsigned int asHalf[2];
|
||||||
|
unsigned long long asFull;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClientFuzzySecurityToken
|
||||||
|
{
|
||||||
|
Tokens::binaryTag tag;
|
||||||
|
Tokens::binaryTag prevTag;
|
||||||
|
Tokens::binaryTag savedTag;
|
||||||
|
boost::mutex tokenMutex;
|
||||||
|
public:
|
||||||
|
ClientFuzzySecurityToken(unsigned long long inTag);
|
||||||
|
void set(unsigned long long inTag);
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
__forceinline
|
||||||
|
#else
|
||||||
|
inline
|
||||||
|
#endif
|
||||||
|
void addFlagFast(unsigned long long flags)
|
||||||
|
{
|
||||||
|
tag.asFull |= flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
__forceinline
|
||||||
|
#else
|
||||||
|
inline
|
||||||
|
#endif
|
||||||
|
void addFlagSafe(unsigned long long flags)
|
||||||
|
{
|
||||||
|
boost::mutex::scoped_lock lock(tokenMutex);
|
||||||
|
tag.asFull |= flags;
|
||||||
|
}
|
||||||
|
unsigned long long crypt();
|
||||||
|
unsigned long long getPrev()
|
||||||
|
{
|
||||||
|
return prevTag.asFull;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// The server can check this. Each '1' transmitted from the client has
|
||||||
|
// a 50% chance of being a '0' here, thus it it fuzzy.
|
||||||
|
class ServerFuzzySecurityToken
|
||||||
|
{
|
||||||
|
Tokens::binaryTag lastTag;
|
||||||
|
Tokens::binaryTag tag;
|
||||||
|
unsigned int ignoreFlags;
|
||||||
|
public:
|
||||||
|
ServerFuzzySecurityToken(unsigned long long inTag, unsigned int ignoreFlags = 0);
|
||||||
|
void setLastTag(unsigned long long tag) { lastTag.asFull = tag;}
|
||||||
|
unsigned long long decrypt(unsigned long long inTag);
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Tokens
|
||||||
|
{
|
||||||
|
extern ClientFuzzySecurityToken sendStatsToken;
|
||||||
|
extern unsigned int simpleToken;
|
||||||
|
extern ClientFuzzySecurityToken apiToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(_WIN32) && !defined(RBX_STUDIO_BUILD) && !defined(RBX_PLATFORM_DURANGO)
|
||||||
|
#include "Security/RandomConstant.h"
|
||||||
|
|
||||||
|
// This is junk code generation. All of this is intended to be inlined
|
||||||
|
// and generally do nothing.
|
||||||
|
|
||||||
|
// there are 15*17 different seeds from this.
|
||||||
|
// (RBX_BUILDSEED%15 + 1) is between 1 and 16, and is coprime to 17.
|
||||||
|
#define RBX_JUNK (junk< ((RBX_BUILDSEED%15 + 1)*__LINE__ + RBX_BUILDSEED) % 17>())
|
||||||
|
|
||||||
|
template <int N> inline void junk() {}
|
||||||
|
|
||||||
|
#define RBX_NOP0 __asm _emit 0x0f __asm _emit 0x1f __asm _emit 0x00
|
||||||
|
#define RBX_NOP1 __asm _emit 0x8d __asm _emit 0x76 __asm _emit 0x00
|
||||||
|
#define RBX_NOP2 __asm _emit 0x0f __asm _emit 0x1f __asm _emit 0x40 __asm _emit 0x00
|
||||||
|
#define RBX_NOP3 __asm _emit 0x8d __asm _emit 0x74 __asm _emit 0x26 __asm _emit 0x00
|
||||||
|
#define RBX_NOP4 __asm _emit 0x90 __asm _emit 0x8d __asm _emit 0x74 __asm _emit 0x26 __asm _emit 0x00
|
||||||
|
#define RBX_NOP5 __asm _emit 0x66 __asm _emit 0x0f __asm _emit 0x1f __asm _emit 0x44 __asm _emit 0x00 __asm _emit 0x00
|
||||||
|
#define RBX_NOP6 __asm _emit 0x8d __asm _emit 0xb6 __asm _emit 0x00 __asm _emit 0x00 __asm _emit 0x00 __asm _emit 0x00
|
||||||
|
template<> inline void junk<0>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<> inline void junk<1>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline void junk<2>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline void junk<3>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline void junk<4>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline void junk<5>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline void junk<6>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline void junk<7>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP0;
|
||||||
|
RBX_NOP1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline void junk<8>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP1;
|
||||||
|
RBX_NOP2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline void junk<9>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP1;
|
||||||
|
RBX_NOP3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline void junk<10>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP4;
|
||||||
|
RBX_NOP0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline void junk<11>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP3;
|
||||||
|
RBX_NOP5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline void junk<12>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP2;
|
||||||
|
RBX_NOP5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline void junk<13>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP6;
|
||||||
|
RBX_NOP0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline void junk<14>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP2;
|
||||||
|
RBX_NOP1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline void junk<15>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP4;
|
||||||
|
RBX_NOP5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline void junk<16>()
|
||||||
|
{
|
||||||
|
_asm
|
||||||
|
{
|
||||||
|
RBX_NOP3;
|
||||||
|
RBX_NOP2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define RBX_JUNK
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#pragma once
|
||||||
|
#define RBX_BUILDSEED 3942749
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "rbxformat.h"
|
||||||
|
#include "rbx/boost.hpp"
|
||||||
|
#include "g3d/format.h"
|
||||||
|
|
||||||
|
namespace boost
|
||||||
|
{
|
||||||
|
template<typename T> class thread_specific_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
namespace Security
|
||||||
|
{
|
||||||
|
typedef enum {
|
||||||
|
Anonymous = 0,
|
||||||
|
LocalGUI_, // Any action initiated by Roblox Studio or the mouse
|
||||||
|
GameScript_, // Execution of a BaseScript object inside any DataModel
|
||||||
|
GameScriptInRobloxPlace_, // Execution of a BaseScript object inside any DataModel, if the place was authored by Roblox
|
||||||
|
RobloxGameScript_, // Execution of a BaseScript object written by Roblox inside any DataModel
|
||||||
|
CmdLine_, // Any script executed from the Studio command line
|
||||||
|
#if defined(RBX_STUDIO_BUILD)
|
||||||
|
StudioPlugin, // Any Studio plug-in script
|
||||||
|
#endif
|
||||||
|
COM, // Scripts executed via the COM API (usually comes from watrbx.wtf)
|
||||||
|
WebService, // Scripts executed via the Web Service API (usually comes from watrbx.wtf)
|
||||||
|
Replicator_, // Receiving data via replication
|
||||||
|
COUNT_Identities // Not a true identity. Used for enumeration
|
||||||
|
} Identities;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
None =0, // Any identity can access this feature, including in-game scripts
|
||||||
|
Plugin =1, // Second-lowest access level, just above in-game script
|
||||||
|
RobloxPlace =2, // A Roblox place that we own. Therefore scripts are more trusted and we allow
|
||||||
|
// preliminary features
|
||||||
|
LocalUser =3, // non-game permission. Usually for IDE
|
||||||
|
WritePlayer =4, // Permissions for changing player name, userId, etc.
|
||||||
|
RobloxScript =5, // A script, such as a CoreScript, that we run inside a game
|
||||||
|
Roblox =6, // Highest level of permission
|
||||||
|
|
||||||
|
#ifdef RBX_TEST_BUILD
|
||||||
|
TestLocalUser =None, //For exposing Lua functions to the ReleaseTest build
|
||||||
|
#else
|
||||||
|
TestLocalUser =LocalUser,
|
||||||
|
#endif
|
||||||
|
} Permissions;
|
||||||
|
|
||||||
|
// different classes of VM that derive from the permission level
|
||||||
|
typedef enum {
|
||||||
|
VM_Default = 0, // most scripts go here
|
||||||
|
#if defined(RBX_STUDIO_BUILD)
|
||||||
|
VM_StudioPlugin, // Sandbox for studio plugin scripts
|
||||||
|
#endif
|
||||||
|
VM_RobloxScriptPlus, // scripts with the permission level of RobloxScript or higher go here
|
||||||
|
COUNT_VM_Classes
|
||||||
|
} VMClasses;
|
||||||
|
|
||||||
|
class Impersonator;
|
||||||
|
|
||||||
|
class Context
|
||||||
|
{
|
||||||
|
friend class Impersonator;
|
||||||
|
|
||||||
|
public:
|
||||||
|
const Identities identity;
|
||||||
|
static Context& current();
|
||||||
|
|
||||||
|
// Throws an exception if the current thread's Context doesn't have the requested Role
|
||||||
|
void requirePermission(Permissions permission, const char* operation = 0) const
|
||||||
|
{
|
||||||
|
if (!isInRole(identity, permission)) {
|
||||||
|
#ifndef _DEBUG
|
||||||
|
// obfuscate error string
|
||||||
|
// TODO: Can we obfuscate the code without obfuscating the error?
|
||||||
|
// Daniel: NO
|
||||||
|
//if (operation)
|
||||||
|
// throw RBX::runtime_error("s %s", operation);
|
||||||
|
//else
|
||||||
|
// throw RBX::runtime_error("s");
|
||||||
|
throw std::runtime_error("");
|
||||||
|
#else
|
||||||
|
if (operation) {
|
||||||
|
throw RBX::runtime_error("The current identity (%d) cannot %s (requires %d)", identity, operation, permission);
|
||||||
|
} else {
|
||||||
|
throw RBX::runtime_error("The current identity (%d) cannot perform the requested operation (requires %d)", identity, permission);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasPermission(Permissions permission)
|
||||||
|
{
|
||||||
|
return isInRole(identity, permission);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isInRole(Identities identity, Permissions permission);
|
||||||
|
|
||||||
|
static void tssCleanup(Context*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Context(Identities identity):identity(identity) {}
|
||||||
|
static boost::thread_specific_ptr<Context>& ptr();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Impersonates an identity for the lifetime of the object
|
||||||
|
class Impersonator
|
||||||
|
{
|
||||||
|
Context current;
|
||||||
|
Context* previous;
|
||||||
|
public:
|
||||||
|
Impersonator(Identities identity);
|
||||||
|
~Impersonator();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,682 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "solver/SolverConfig.h"
|
||||||
|
#include "solver/ConstraintJacobian.h"
|
||||||
|
#include "solver/SolverBody.h"
|
||||||
|
#include "v8kernel/SimBody.h"
|
||||||
|
#include "v8world/RotateJoint.h"
|
||||||
|
|
||||||
|
#include "simd/simd.h"
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
|
||||||
|
class PGSSolver;
|
||||||
|
class DebugSerializer;
|
||||||
|
|
||||||
|
//
|
||||||
|
// ConstraintVariables: inputs to the solver, initialized by the constraint interface
|
||||||
|
//
|
||||||
|
class ConstraintVariables
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void serialize( DebugSerializer& s ) const;
|
||||||
|
|
||||||
|
static RBX_SIMD_INLINE void setReaction( ConstraintVariables* _vars, const Vector3& _r )
|
||||||
|
{
|
||||||
|
_vars[0].reaction = _r.x;
|
||||||
|
_vars[1].reaction = _r.y;
|
||||||
|
_vars[2].reaction = _r.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RBX_SIMD_INLINE void setReaction( ConstraintVariables* _vars, float x, float y )
|
||||||
|
{
|
||||||
|
_vars[0].reaction = x;
|
||||||
|
_vars[1].reaction = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RBX_SIMD_INLINE void setImpulse( ConstraintVariables* _vars, const Vector3& _i )
|
||||||
|
{
|
||||||
|
_vars[0].impulse = _i.x;
|
||||||
|
_vars[1].impulse = _i.y;
|
||||||
|
_vars[2].impulse = _i.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RBX_SIMD_INLINE void setImpulse( ConstraintVariables* _vars, float x, float y )
|
||||||
|
{
|
||||||
|
_vars[0].impulse = x;
|
||||||
|
_vars[1].impulse = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RBX_SIMD_INLINE void setMinImpulses( ConstraintVariables* _vars, const Vector3& _min )
|
||||||
|
{
|
||||||
|
_vars[0].minImpulseValue = _min.x;
|
||||||
|
_vars[1].minImpulseValue = _min.y;
|
||||||
|
_vars[2].minImpulseValue = _min.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RBX_SIMD_INLINE void setMinImpulses( ConstraintVariables* _vars, float x, float y )
|
||||||
|
{
|
||||||
|
_vars[0].minImpulseValue = x;
|
||||||
|
_vars[1].minImpulseValue = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RBX_SIMD_INLINE void setMaxImpulses( ConstraintVariables* _vars, const Vector3& _max )
|
||||||
|
{
|
||||||
|
_vars[0].maxImpulseValue = _max.x;
|
||||||
|
_vars[1].maxImpulseValue = _max.y;
|
||||||
|
_vars[2].maxImpulseValue = _max.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RBX_SIMD_INLINE void setMaxImpulses( ConstraintVariables* _vars, float x, float y )
|
||||||
|
{
|
||||||
|
_vars[0].maxImpulseValue = x;
|
||||||
|
_vars[1].maxImpulseValue = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static RBX_SIMD_INLINE void gatherComponents( simd::v4f& _impulses, simd::v4f& _reactions, simd::v4f& _min, simd::v4f& _max, const ConstraintVariables& _vars0 )
|
||||||
|
{
|
||||||
|
_min = simd::splat< 0 >( simd::v4f( _vars0.v ) );
|
||||||
|
_max = simd::splat< 1 >( simd::v4f( _vars0.v ) );
|
||||||
|
_reactions = simd::splat< 2 >( simd::v4f( _vars0.v ) );
|
||||||
|
_impulses = simd::splat< 3 >( simd::v4f( _vars0.v ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static RBX_SIMD_INLINE void gatherComponents( simd::v4f& _impulses, simd::v4f& _reactions, simd::v4f& _min, simd::v4f& _max, const ConstraintVariables& _vars0, const ConstraintVariables& _vars1 )
|
||||||
|
{
|
||||||
|
transpose2x4( _min, _max, _reactions, _impulses, simd::v4f(_vars0.v), simd::v4f(_vars1.v) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static RBX_SIMD_INLINE void gatherComponents( simd::v4f& _impulses, simd::v4f& _reactions, simd::v4f& _min, simd::v4f& _max, const ConstraintVariables& _vars0, const ConstraintVariables& _vars1, const ConstraintVariables& _vars2 )
|
||||||
|
{
|
||||||
|
transpose3x4( _min, _max, _reactions, _impulses, (simd::v4f)_vars0.v, (simd::v4f)_vars1.v, (simd::v4f)_vars2.v );
|
||||||
|
}
|
||||||
|
|
||||||
|
static RBX_SIMD_INLINE void gatherComponents( simd::v4f& _impulses, simd::v4f& _reactions, simd::v4f& _min, simd::v4f& _max, const ConstraintVariables& _vars0, const ConstraintVariables& _vars1, const ConstraintVariables& _vars2, const ConstraintVariables& _vars3 )
|
||||||
|
{
|
||||||
|
transpose( _min, _max, _reactions, _impulses, (simd::v4f)_vars0.v, (simd::v4f)_vars1.v, (simd::v4f)_vars2.v, (simd::v4f)_vars3.v );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Values that must be set by the Constraint::buildEquation
|
||||||
|
// Inputs expected by the solver
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
float minImpulseValue;
|
||||||
|
float maxImpulseValue;
|
||||||
|
|
||||||
|
// Constraint must set this to the desired reaction
|
||||||
|
float reaction;
|
||||||
|
|
||||||
|
// The Constraint must set this to the impulse computed in the previous frame or 0.0f if it is not available.
|
||||||
|
// This will contain the result.
|
||||||
|
float impulse;
|
||||||
|
};
|
||||||
|
simd::v4f_pod v;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// MovingRegression: Fit best 2nd degree curve to the last few data points
|
||||||
|
//
|
||||||
|
class MovingRegression
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MovingRegression()
|
||||||
|
{
|
||||||
|
lastPoint = 0.0f;
|
||||||
|
lastTangent = 0.0f;
|
||||||
|
lastCurvature = 0.0f;
|
||||||
|
confidence = 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float testFitNextDataPointZeroOrder( float y ) const
|
||||||
|
{
|
||||||
|
float predicted = lastPoint;
|
||||||
|
return confidence * std::abs( y - predicted ) / ( std::max( std::abs( y ), std::abs( predicted ) ) + 0.00001f ) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float testFitNextDataPointFirstOrder( float y ) const
|
||||||
|
{
|
||||||
|
float predicted = lastPoint + lastTangent;
|
||||||
|
return confidence * std::abs( y - predicted ) / ( std::max( std::abs( y ), std::abs( predicted ) ) + 0.00001f ) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline float testFitNextDataPointSecondOrder( float y ) const
|
||||||
|
{
|
||||||
|
float predicted = lastPoint + lastTangent + lastCurvature;
|
||||||
|
return confidence * std::abs( y - predicted ) / ( std::max( std::abs( y ), std::abs( predicted ) ) + 0.00001f ) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
float predict( ) const
|
||||||
|
{
|
||||||
|
return lastPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addDataPoint( float y, float weight )
|
||||||
|
{
|
||||||
|
float newTangent = y - lastPoint;
|
||||||
|
float newCurvature = newTangent - lastTangent;
|
||||||
|
lastCurvature = newCurvature;
|
||||||
|
lastTangent = newTangent;
|
||||||
|
lastPoint = y;
|
||||||
|
confidence += 0.1f * ( 1.0f - confidence );
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialize( DebugSerializer& s) const;
|
||||||
|
|
||||||
|
float confidence;
|
||||||
|
float lastPoint;
|
||||||
|
float lastTangent;
|
||||||
|
float lastCurvature;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Cached values for each constraint equation
|
||||||
|
//
|
||||||
|
class ConstraintCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConstraintCache():
|
||||||
|
velocityImpulse( 0.0f ),
|
||||||
|
velocityReaction( 0.0f ),
|
||||||
|
positionImpulse( 0.0f ),
|
||||||
|
positionReaction( 0.0f ),
|
||||||
|
// These need to be initialized to the values in SolverConfig!
|
||||||
|
velocitySor( 1.9f ),
|
||||||
|
positionSor( 1.9f ),
|
||||||
|
velocityCacheDamping( 1.0f ),
|
||||||
|
positionCacheDamping( 1.0f ) { }
|
||||||
|
|
||||||
|
void cache( const ConstraintVariables& _velocityStage, const ConstraintVariables& _positionStage, float _sorVel, float _sorPos, bool _isCollision, const SolverConfig& config );
|
||||||
|
|
||||||
|
inline void readCache( ConstraintVariables& _velocityStage, ConstraintVariables& _positionStage, float& _sorVel, float& _sorPos ) const
|
||||||
|
{
|
||||||
|
_velocityStage.impulse = velocityImpulse;
|
||||||
|
_sorVel = velocitySor;
|
||||||
|
_velocityStage.reaction = velocityReaction;
|
||||||
|
_positionStage.impulse = positionImpulse;
|
||||||
|
_sorPos = positionSor;
|
||||||
|
_positionStage.reaction = positionReaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialize( DebugSerializer& s ) const;
|
||||||
|
|
||||||
|
float velocityImpulse;
|
||||||
|
float velocityReaction;
|
||||||
|
float velocitySor;
|
||||||
|
float velocityCacheDamping;
|
||||||
|
float positionImpulse;
|
||||||
|
float positionReaction;
|
||||||
|
float positionSor;
|
||||||
|
float positionCacheDamping;
|
||||||
|
|
||||||
|
MovingRegression velocityImpulseRegression;
|
||||||
|
MovingRegression positionImpulseRegression;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Constraint definition: Base class for all constraints and collision classes
|
||||||
|
//
|
||||||
|
class Constraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Types
|
||||||
|
{
|
||||||
|
Types_Collision, // Special constraint type: only generated inside the solver from ContactConnectors
|
||||||
|
Types_Align2Axes,
|
||||||
|
Types_BallInSocket,
|
||||||
|
Types_AngularVelocity,
|
||||||
|
Types_LinearVelocity,
|
||||||
|
Types_AchievePosition,
|
||||||
|
Types_BodyAngularVelocity,
|
||||||
|
Types_LinearSpring,
|
||||||
|
Types_LegacyBreakableBallInSocket,
|
||||||
|
Types_LegacyAngularVelocity,
|
||||||
|
Types_Count
|
||||||
|
};
|
||||||
|
|
||||||
|
// Number of degrees of freedom constrained
|
||||||
|
inline unsigned getDimension() const { return dimensions; }
|
||||||
|
|
||||||
|
inline bool isBroken() const { return broken; }
|
||||||
|
|
||||||
|
// Read from the constraint cache, and call the overloaded build equation
|
||||||
|
// This should only be called by the solver
|
||||||
|
inline void restoreCacheAndBuildEquation(
|
||||||
|
ConstraintJacobianPair* _jacobian,
|
||||||
|
ConstraintVariables* _velocityStage,
|
||||||
|
ConstraintVariables* _positionStage,
|
||||||
|
float* _sorVel,
|
||||||
|
float* _sorPos,
|
||||||
|
boost::uint8_t* _useBlock,
|
||||||
|
const SolverBodyDynamicProperties& _bodyA,
|
||||||
|
const SolverBodyDynamicProperties& _bodyB,
|
||||||
|
const SolverConfig& _solverConfig,
|
||||||
|
float _dt );
|
||||||
|
|
||||||
|
// Write into the constraint cache
|
||||||
|
// This should only be called by the solver
|
||||||
|
inline void cache(
|
||||||
|
const ConstraintVariables* _velocityStage,
|
||||||
|
const ConstraintVariables* _positionStage,
|
||||||
|
const float* _sorVel, const float* _sorPos,
|
||||||
|
const SolverConfig& _config );
|
||||||
|
|
||||||
|
// Each breakable constraint will need to implement this, and return /true/ if the constraint changes state to broken
|
||||||
|
// This should only be called by the solver
|
||||||
|
inline void updateBrokenState(
|
||||||
|
const ConstraintVariables* _velocityStage,
|
||||||
|
const ConstraintVariables* _positionStage,
|
||||||
|
const SolverConfig& _config );
|
||||||
|
|
||||||
|
void setBodyA( Body* _a ) { bodyA = _a; }
|
||||||
|
void setBodyB( Body* _b ) { bodyB = _b; }
|
||||||
|
const Body* getBodyA() const { return bodyA; }
|
||||||
|
const Body* getBodyB() const { return bodyB; }
|
||||||
|
Body* getBodyA() { return bodyA; }
|
||||||
|
Body* getBodyB() { return bodyB; }
|
||||||
|
Types getType() const { return type; }
|
||||||
|
|
||||||
|
virtual ~Constraint();
|
||||||
|
|
||||||
|
void setUID( boost::uint64_t _index ) { uid = _index; }
|
||||||
|
bool hasValidUID() const { return uid != 0; }
|
||||||
|
boost::uint64_t getUID() const { return uid; }
|
||||||
|
|
||||||
|
// After the PGS has updated all i ts iterations, the last iteration reaction delta is passed in as parameter
|
||||||
|
enum Convergence
|
||||||
|
{
|
||||||
|
Convergence_Converges,
|
||||||
|
Convergence_Diverges,
|
||||||
|
Convergence_Undetermined
|
||||||
|
};
|
||||||
|
virtual Convergence testPGSConvergence( const float* _disp, const float* _residuals, const float* _deltaResiduals, const SolverConfig& _solverConfig ) { return Convergence_Converges; }
|
||||||
|
|
||||||
|
virtual void serialize( DebugSerializer& s ) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const ConstraintCache& getCache( unsigned d ) const { return cacheData[ d ]; }
|
||||||
|
ConstraintCache& getCache( unsigned d ) { return cacheData[ d ]; }
|
||||||
|
|
||||||
|
inline Constraint( Types _type, Body* _bodyA, Body* _bodyB, uint8_t _dimensions );
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Main constraint interface to the solver
|
||||||
|
// Initializes the Jacobian and ConstraintVariables for the two stages
|
||||||
|
virtual void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) = 0;
|
||||||
|
|
||||||
|
// Each breakable constraint will need to implement this, and return /true/ if the constraint changes state to broken
|
||||||
|
virtual bool computeBrokenState(
|
||||||
|
const ConstraintVariables* _velocityStage,
|
||||||
|
const ConstraintVariables* _positionStage,
|
||||||
|
const SolverConfig& _config ) const { return false; }
|
||||||
|
|
||||||
|
// Disable copy constructs
|
||||||
|
Constraint( const Constraint& );
|
||||||
|
Constraint& operator=( const Constraint& );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t dimensions;
|
||||||
|
Types type : 8;
|
||||||
|
bool broken : 1;
|
||||||
|
private:
|
||||||
|
Body* bodyA;
|
||||||
|
Body* bodyB;
|
||||||
|
ConstraintCache* cacheData;
|
||||||
|
boost::uint64_t uid; // Current index if registered in the solver
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Constraint: inline implementation
|
||||||
|
//
|
||||||
|
inline Constraint::Constraint( Types _type, Body* _bodyA, Body* _bodyB, uint8_t _dimensions ): type( _type ), dimensions( _dimensions ), bodyA( _bodyA ), bodyB( _bodyB ), uid( 0 ), broken( false )
|
||||||
|
{
|
||||||
|
RBXASSERT( _bodyA != NULL );
|
||||||
|
cacheData = new ConstraintCache[ dimensions ];
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __RBX_NOT_RELEASE
|
||||||
|
static inline void checkConstraintVariables( const ConstraintVariables& _vars )
|
||||||
|
{
|
||||||
|
RBXASSERT( !RBX::Math::isNanInf( _vars.impulse ) );
|
||||||
|
RBXASSERT( !RBX::Math::isNanInf( _vars.reaction ) );
|
||||||
|
RBXASSERT( !RBX::Math::isNan( _vars.minImpulseValue ) );
|
||||||
|
RBXASSERT( !RBX::Math::isNan( _vars.maxImpulseValue ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void checkJacobian( const ConstraintJacobianPair& _j )
|
||||||
|
{
|
||||||
|
RBXASSERT( !RBX::Math::isNanInfVector3( _j.a.lin ) );
|
||||||
|
RBXASSERT( !RBX::Math::isNanInfVector3( _j.b.lin ) );
|
||||||
|
RBXASSERT( !RBX::Math::isNanInfVector3( _j.a.ang ) );
|
||||||
|
RBXASSERT( !RBX::Math::isNanInfVector3( _j.b.ang ) );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE void Constraint::restoreCacheAndBuildEquation(
|
||||||
|
ConstraintJacobianPair* __restrict _jacobian,
|
||||||
|
ConstraintVariables* __restrict _varsVel,
|
||||||
|
ConstraintVariables* __restrict _varsPos,
|
||||||
|
float* __restrict _sorVel,
|
||||||
|
float* __restrict _sorPos,
|
||||||
|
boost::uint8_t* _useBlock,
|
||||||
|
const SolverBodyDynamicProperties& _bodyA,
|
||||||
|
const SolverBodyDynamicProperties& _bodyB,
|
||||||
|
const SolverConfig& _solverConfig,
|
||||||
|
float _dt )
|
||||||
|
{
|
||||||
|
for( unsigned i = 0; i < dimensions; i++ )
|
||||||
|
{
|
||||||
|
// Initialize to some reasonable default values
|
||||||
|
_varsVel[i].minImpulseValue = -std::numeric_limits<float>::infinity();
|
||||||
|
_varsVel[i].maxImpulseValue = std::numeric_limits<float>::infinity();
|
||||||
|
|
||||||
|
_varsPos[i].minImpulseValue = -std::numeric_limits<float>::infinity();
|
||||||
|
_varsPos[i].maxImpulseValue = std::numeric_limits<float>::infinity();
|
||||||
|
|
||||||
|
_jacobian[i].reset();
|
||||||
|
|
||||||
|
// Unless specified by the constraint, use the entire constraint as a Block in the Gauss-Seidel
|
||||||
|
_useBlock[i] = _solverConfig.blockPGSEnabled;
|
||||||
|
|
||||||
|
// Read previous frame impulse/SOR/reaction values
|
||||||
|
getCache(i).readCache(_varsVel[i],_varsPos[i], _sorVel[i], _sorPos[i]);
|
||||||
|
|
||||||
|
// Optionally disable the cache
|
||||||
|
_varsVel[i].impulse = _solverConfig.velCacheDamping * _varsVel[i].impulse;
|
||||||
|
_varsPos[i].impulse = _solverConfig.posCacheDamping * _varsPos[i].impulse;
|
||||||
|
}
|
||||||
|
|
||||||
|
buildEquation( _jacobian, _useBlock, _varsVel, _varsPos, _bodyA, _bodyB, _solverConfig, _dt );
|
||||||
|
|
||||||
|
// Run some sanity checks
|
||||||
|
#ifdef __RBX_NOT_RELEASE
|
||||||
|
for( unsigned i = 0; i < dimensions; i++ )
|
||||||
|
{
|
||||||
|
checkConstraintVariables( _varsVel[ i ] );
|
||||||
|
checkConstraintVariables( _varsPos[ i ] );
|
||||||
|
checkJacobian( _jacobian[ i ] );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE void Constraint::updateBrokenState(
|
||||||
|
const ConstraintVariables* _velocityStage,
|
||||||
|
const ConstraintVariables* _positionStage,
|
||||||
|
const SolverConfig& _config )
|
||||||
|
{
|
||||||
|
if( !broken )
|
||||||
|
{
|
||||||
|
broken = computeBrokenState(_velocityStage, _positionStage, _config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Constraint::cache( const ConstraintVariables* _velocityStage, const ConstraintVariables* _positionStage, const float* _sorVel, const float* _sorPos, const SolverConfig& _config )
|
||||||
|
{
|
||||||
|
// Cache Constraint base class data
|
||||||
|
for( unsigned i = 0; i < dimensions; i++ )
|
||||||
|
{
|
||||||
|
cacheData[ i ].cache( _velocityStage[ i ], _positionStage[ i ], _sorVel[ i ], _sorPos[ i ], getType() == Types_Collision, _config );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ConstraintBallInSocket
|
||||||
|
//
|
||||||
|
class ConstraintBallInSocket: public Constraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConstraintBallInSocket( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_BallInSocket, _bodyA, _bodyB, 3 ) { }
|
||||||
|
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||||
|
|
||||||
|
inline void setPivotA( const Vector3& _pivotA ) { pointA = _pivotA; }
|
||||||
|
inline void setPivotB( const Vector3& _pivotB ) { pointB = _pivotB; }
|
||||||
|
|
||||||
|
Convergence testPGSConvergence( const float* _disp, const float* _residuals, const float* _deltaResiduals, const SolverConfig& _solverConfig ) override;
|
||||||
|
void serialize( DebugSerializer& s ) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Points on object A and B in object space, relative to center of mass
|
||||||
|
Vector3 pointA;
|
||||||
|
Vector3 pointB;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// ConstraintLegacyBreakableBallInSocket
|
||||||
|
//
|
||||||
|
class ConstraintLegacyBreakableBallInSocket: public Constraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConstraintLegacyBreakableBallInSocket( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_LegacyBreakableBallInSocket, _bodyA, _bodyB, 3 ), pointA(0.0f), pointB(0.0f), broken( false ), maxNormalForce( std::numeric_limits<float>::infinity() )
|
||||||
|
{
|
||||||
|
setNormalOnA( Vector3(1.0f, 0.0f, 0.0f ) );
|
||||||
|
}
|
||||||
|
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||||
|
|
||||||
|
void setPivotA( const Vector3& _pivotA ) { pointA = _pivotA; }
|
||||||
|
void setPivotB( const Vector3& _pivotB ) { pointB = _pivotB; }
|
||||||
|
void setNormalOnA( const Vector3& _normal );
|
||||||
|
void setMaxNormalForce( float _maxForce ) { maxNormalForce = _maxForce; }
|
||||||
|
bool computeBrokenState(
|
||||||
|
const ConstraintVariables* _velocityStage,
|
||||||
|
const ConstraintVariables* _positionStage,
|
||||||
|
const SolverConfig& _config ) const override;
|
||||||
|
|
||||||
|
void serialize( DebugSerializer& s ) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Points on object A and B in object space, relative to center of mass
|
||||||
|
Vector3 pointA;
|
||||||
|
Vector3 pointB;
|
||||||
|
Vector3 normalA;
|
||||||
|
Vector3 tangentA1;
|
||||||
|
Vector3 tangentA2;
|
||||||
|
float maxNormalForce;
|
||||||
|
bool broken;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// ConstraintAlign2Axes
|
||||||
|
//
|
||||||
|
class ConstraintAlign2Axes: public Constraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConstraintAlign2Axes( Body* _bodyA, Body* _bodyB );
|
||||||
|
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||||
|
|
||||||
|
void setAxisA( const Vector3& a );
|
||||||
|
void setAxisB( const Vector3& b );
|
||||||
|
Vector3 getAxisA() const { return axisA; }
|
||||||
|
Vector3 getAxisB() const { return axisB; }
|
||||||
|
|
||||||
|
Convergence testPGSConvergence( const float* _disp, const float* _residuals, const float* _deltaResiduals, const SolverConfig& _solverConfig ) override;
|
||||||
|
void serialize( DebugSerializer& s ) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Axis on body A in object space
|
||||||
|
Vector3 axisA;
|
||||||
|
|
||||||
|
// 2 normal axes to the axis on body B
|
||||||
|
// In object space
|
||||||
|
Vector3 axisB;
|
||||||
|
Vector3 orthogonalAxisB1;
|
||||||
|
Vector3 orthogonalAxisB2;
|
||||||
|
|
||||||
|
// Cache
|
||||||
|
Vector3 worldSpaceOrthogonalB1;
|
||||||
|
Vector3 worldSpaceOrthogonalB2;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// ConstraintAngularVelocity
|
||||||
|
//
|
||||||
|
class ConstraintAngularVelocity: public Constraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConstraintAngularVelocity( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_AngularVelocity, _bodyA, _bodyB, 1 ),
|
||||||
|
maxForce( 0.0f ),
|
||||||
|
desiredAngularVelocity( 0.0f ) { }
|
||||||
|
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||||
|
|
||||||
|
void setAxisA( const Vector3& a ) { axisA = a; }
|
||||||
|
void setAxisB( const Vector3& b ) { axisB = b; }
|
||||||
|
void setDesiredAngularVelocity( float _v ) { desiredAngularVelocity = _v; }
|
||||||
|
void setMaxForce( float _f ) { maxForce = _f; }
|
||||||
|
|
||||||
|
void serialize( DebugSerializer& s ) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3 axisA;
|
||||||
|
Vector3 axisB;
|
||||||
|
float maxForce;
|
||||||
|
float desiredAngularVelocity;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// ConstraintLinearVelocity
|
||||||
|
//
|
||||||
|
class ConstraintLinearVelocity: public Constraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConstraintLinearVelocity( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_LinearVelocity, _bodyA, _bodyB, 3 ), maxForce(0.0f), desiredVelocity(0.0f, 0.0f, 0.0f) { }
|
||||||
|
|
||||||
|
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||||
|
|
||||||
|
void setDesiredVelocity( const Vector3& _v ) { desiredVelocity = _v; }
|
||||||
|
void setMaxForce( const Vector3& _f ) { maxForce = _f; }
|
||||||
|
|
||||||
|
void serialize( DebugSerializer& s ) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3 maxForce;
|
||||||
|
Vector3 desiredVelocity;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConstraintLinearSpring: public Constraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConstraintLinearSpring( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_LinearSpring, _bodyA, _bodyB, 3 ), pivotA(0.0f), pivotB(0.0f), maxForce(0.0f), p(0.0f), d(0.0f) { }
|
||||||
|
|
||||||
|
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||||
|
|
||||||
|
void setPivotA( const Vector3& _pivotA ) { pivotA = _pivotA; }
|
||||||
|
void setPivotB( const Vector3& _pivotB ) { pivotB = _pivotB; }
|
||||||
|
void setMaxForce( const Vector3& _f ) { maxForce = _f; }
|
||||||
|
void setPD( float _p, float _d ) { p = _p; d = _d; }
|
||||||
|
|
||||||
|
void serialize( DebugSerializer& s ) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3 pivotA;
|
||||||
|
Vector3 pivotB;
|
||||||
|
Vector3 maxForce;
|
||||||
|
float p, d;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConstraintAchievePosition: public Constraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConstraintAchievePosition( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_AchievePosition, _bodyA, _bodyB, 3 ), maxForce( 0.0f ), targetVelocity( 0.0f ) { }
|
||||||
|
|
||||||
|
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||||
|
|
||||||
|
void setPivotA( const Vector3& _pivotA ) { pivotA = _pivotA; }
|
||||||
|
void setPivotB( const Vector3& _pivotB ) { pivotB = _pivotB; }
|
||||||
|
void setTargetVelocity( const Vector3& _v ) { targetVelocity = _v; }
|
||||||
|
void setMaxForce( const Vector3& _f ) { maxForce = _f; }
|
||||||
|
void setMinForce( const Vector3& _f ) { minForce = _f; }
|
||||||
|
|
||||||
|
void serialize( DebugSerializer& s ) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3 pivotA;
|
||||||
|
Vector3 pivotB;
|
||||||
|
Vector3 maxForce;
|
||||||
|
Vector3 minForce;
|
||||||
|
Vector3 targetVelocity;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConstraintBodyAngularVelocity: public Constraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConstraintBodyAngularVelocity( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_BodyAngularVelocity, _bodyA, _bodyB, 3 ), targetAngularVelocity( 0.0f ), maxTorque( 0.0f ), minTorque( 0.0f ), useIntegratedVelocities( false ) { }
|
||||||
|
|
||||||
|
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||||
|
|
||||||
|
void serialize( DebugSerializer& s ) const override;
|
||||||
|
|
||||||
|
// The vector values need to be provided in object space of body A
|
||||||
|
void setTarget( const Vector3& v ) { targetAngularVelocity = v; }
|
||||||
|
void setMaxTorque( const Vector3& v ) { maxTorque = v; }
|
||||||
|
void setMinTorque( const Vector3& v ) { minTorque = v; }
|
||||||
|
void setUseIntegratedVelocities( bool flag ) { useIntegratedVelocities = flag; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3 targetAngularVelocity;
|
||||||
|
Vector3 maxTorque;
|
||||||
|
Vector3 minTorque;
|
||||||
|
bool useIntegratedVelocities;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConstraintLegacyAngularVelocity: public Constraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConstraintLegacyAngularVelocity( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_LegacyAngularVelocity, _bodyA, _bodyB, 3 ), targetAngularVelocity( 0.0f ), maxTorque( 0.0f ), minTorque( 0.0f ), useIntegratedVelocities( false ) { }
|
||||||
|
|
||||||
|
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||||
|
|
||||||
|
void serialize( DebugSerializer& s ) const override;
|
||||||
|
|
||||||
|
// The vector values need to be provided in object space of body A
|
||||||
|
void setTarget( const Vector3& v ) { targetAngularVelocity = v; }
|
||||||
|
void setMaxTorque( const Vector3& v ) { maxTorque = v; }
|
||||||
|
void setMinTorque( const Vector3& v ) { minTorque = v; }
|
||||||
|
void setUseIntegratedVelocities( bool flag ) { useIntegratedVelocities = flag; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector3 targetAngularVelocity;
|
||||||
|
Vector3 maxTorque;
|
||||||
|
Vector3 minTorque;
|
||||||
|
bool useIntegratedVelocities;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// ConstraintCollision
|
||||||
|
//
|
||||||
|
class ConstraintCollision: public Constraint
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConstraintCollision( Body* _bodyA, Body* _bodyB ): Constraint( Constraint::Types_Collision, _bodyA, _bodyB, 3 )
|
||||||
|
{
|
||||||
|
cachedTangent1 = Vector3( 1.0f, 0.0f, 0.0f );
|
||||||
|
getCache(0).positionSor = 1.0f;
|
||||||
|
getCache(0).velocitySor = 1.0f;
|
||||||
|
getCache(1).positionSor = 1.0f;
|
||||||
|
getCache(1).velocitySor = 1.0f;
|
||||||
|
getCache(2).positionSor = 1.0f;
|
||||||
|
getCache(2).velocitySor = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void buildEquation( ConstraintJacobianPair* _jacobian, boost::uint8_t* _useBlock, ConstraintVariables* _velocityStage, ConstraintVariables* _positionStage, const SolverBodyDynamicProperties& _bodyA, const SolverBodyDynamicProperties& _bodyB, const SolverConfig& _config, float _dt ) override;
|
||||||
|
void setNormal( const Vector3& _normal ) { normal = _normal; }
|
||||||
|
void setPointA( const Vector3& _pointA ) { pointA = _pointA; }
|
||||||
|
void setDepth( float _d ) { depth = _d; }
|
||||||
|
void setFriction( float _f ) { friction = _f; }
|
||||||
|
void setResititution( float _r ) { restitution = _r; }
|
||||||
|
|
||||||
|
Convergence testPGSConvergence( const float* _disp, const float* _residuals, const float* _deltaResiduals, const SolverConfig& _solverConfig ) override;
|
||||||
|
void serialize( DebugSerializer& s ) const override;
|
||||||
|
private:
|
||||||
|
Vector3 normal;
|
||||||
|
Vector3 pointA;
|
||||||
|
float depth;
|
||||||
|
float friction;
|
||||||
|
float restitution;
|
||||||
|
|
||||||
|
// Cache
|
||||||
|
Vector3 cachedTangent1;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,274 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "solver/SolverConfig.h"
|
||||||
|
#include "solver/SolverContainers.h"
|
||||||
|
#include "G3D/Vector3.h"
|
||||||
|
|
||||||
|
#include "boost/limits.hpp"
|
||||||
|
#include "boost/math/constants/constants.hpp"
|
||||||
|
#include "boost/container/vector.hpp"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "simd/simd.h"
|
||||||
|
#include "rbx/ArrayDynamic.h"
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
|
||||||
|
class DebugSerializer;
|
||||||
|
class ConstraintJacobianPair;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Use class definition rather than typedef so we can forward declare
|
||||||
|
//
|
||||||
|
class BodyPairIndices: public std::pair< int, int >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
inline BodyPairIndices() { }
|
||||||
|
inline BodyPairIndices( int a, int b ): std::pair< int, int >( a, b ) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// VirtualDisplacement: http://en.wikipedia.org/wiki/Virtual_displacement
|
||||||
|
// A 6-dimensional vector with a linear part and angular part
|
||||||
|
//
|
||||||
|
|
||||||
|
// This is a version that allows conversion from non-simd to simd types.
|
||||||
|
// The non-simd is still used by integration.
|
||||||
|
class VirtualDisplacementPOD
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void serialize( DebugSerializer& s ) const;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
simd::v4f_pod linV4;
|
||||||
|
Vector3Pod lin;
|
||||||
|
};
|
||||||
|
union
|
||||||
|
{
|
||||||
|
simd::v4f_pod angV4;
|
||||||
|
Vector3Pod ang;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is a version that can be worked with in simd
|
||||||
|
// It's only ever used on the stack
|
||||||
|
class VirtualDisplacement
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RBX_SIMD_INLINE VirtualDisplacement( ){ }
|
||||||
|
RBX_SIMD_INLINE VirtualDisplacement( const simd::v4f& linear, const simd::v4f& angular ): lin( linear ), ang( angular ) { }
|
||||||
|
RBX_SIMD_INLINE VirtualDisplacement( const VirtualDisplacementPOD& _v ): lin( _v.linV4 ), ang( _v.angV4 ) { }
|
||||||
|
RBX_SIMD_INLINE operator VirtualDisplacementPOD()
|
||||||
|
{
|
||||||
|
VirtualDisplacementPOD r;
|
||||||
|
r.linV4 = lin;
|
||||||
|
r.angV4 = ang;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE void reset()
|
||||||
|
{
|
||||||
|
lin = simd::zerof();
|
||||||
|
ang = simd::zerof();
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE simd::v4f getLin() const { return lin; }
|
||||||
|
RBX_SIMD_INLINE simd::v4f getAng() const { return ang; }
|
||||||
|
|
||||||
|
void serialize( DebugSerializer& s ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
simd::v4f lin;
|
||||||
|
simd::v4f ang;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Array of virtual displacements
|
||||||
|
//
|
||||||
|
class VirtualDisplacementArray
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RBX_SIMD_INLINE VirtualDisplacementArray( size_t _size, size_t alignment ): size( _size ), data( _size, ArrayNoInit(), alignment )
|
||||||
|
{ }
|
||||||
|
|
||||||
|
inline void reset()
|
||||||
|
{
|
||||||
|
VirtualDisplacement z( simd::zerof(), simd::zerof() );
|
||||||
|
for( size_t i = 0; i < size; i++ )
|
||||||
|
{
|
||||||
|
data[ i ] = z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const VirtualDisplacementPOD* getData() const { return data.data(); }
|
||||||
|
VirtualDisplacementPOD* getData() { return data.data(); }
|
||||||
|
RBX_SIMD_INLINE size_t getSize() const { return size; }
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE VirtualDisplacementPOD operator[]( int i ) const
|
||||||
|
{
|
||||||
|
RBXASSERT_VERY_FAST( (size_t)i < size );
|
||||||
|
return data[ i ];
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE VirtualDisplacementPOD& operator[]( int i )
|
||||||
|
{
|
||||||
|
RBXASSERT_VERY_FAST( (size_t)i < size );
|
||||||
|
return data[ i ];
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialize( DebugSerializer& s ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t size;
|
||||||
|
ArrayDynamic< VirtualDisplacementPOD > data;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Effective mass vectors: inverse mass matrix * jacobian
|
||||||
|
//
|
||||||
|
class EffectiveMass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RBX_SIMD_INLINE EffectiveMass() { }
|
||||||
|
RBX_SIMD_INLINE EffectiveMass( const simd::v4f& linear, const simd::v4f& angular ): lin( linear ), ang( angular ) { }
|
||||||
|
RBX_SIMD_INLINE void applyMultiplier( const simd::v4f& m )
|
||||||
|
{
|
||||||
|
lin = m * lin;
|
||||||
|
ang = m * ang;
|
||||||
|
}
|
||||||
|
RBX_SIMD_INLINE void reset()
|
||||||
|
{
|
||||||
|
lin = simd::zerof();
|
||||||
|
ang = simd::zerof();
|
||||||
|
}
|
||||||
|
RBX_SIMD_INLINE simd::v4f getLin() const { return lin; }
|
||||||
|
RBX_SIMD_INLINE simd::v4f getAng() const { return ang; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
simd::v4f lin;
|
||||||
|
simd::v4f ang;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EffectiveMassPair
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RBX_SIMD_INLINE EffectiveMassPair( const EffectiveMass& _a, const EffectiveMass& _b ): a( _a ), b( _b ) { }
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE EffectiveMassPair( ) { }
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE void reset()
|
||||||
|
{
|
||||||
|
a.reset();
|
||||||
|
b.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE void applyMultipliers( const simd::v4f& mA, const simd::v4f& mB )
|
||||||
|
{
|
||||||
|
a.applyMultiplier( mA );
|
||||||
|
b.applyMultiplier( mB );
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE simd::v4f getLinA() const { return a.getLin(); }
|
||||||
|
RBX_SIMD_INLINE simd::v4f getLinB() const { return b.getLin(); }
|
||||||
|
RBX_SIMD_INLINE simd::v4f getAngA() const { return a.getAng(); }
|
||||||
|
RBX_SIMD_INLINE simd::v4f getAngB() const { return b.getAng(); }
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE EffectiveMass getPartA() const { return a; }
|
||||||
|
RBX_SIMD_INLINE EffectiveMass getPartB() const { return b; }
|
||||||
|
|
||||||
|
void serialize( DebugSerializer& s ) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
EffectiveMass a;
|
||||||
|
EffectiveMass b;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Jacobian of a binary constraint
|
||||||
|
//
|
||||||
|
class ConstraintJacobian
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RBX_SIMD_INLINE void reset()
|
||||||
|
{
|
||||||
|
linV4 = simd::zerof();
|
||||||
|
angV4 = simd::zerof();
|
||||||
|
}
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
Vector3Pod lin;
|
||||||
|
simd::v4f_pod linV4;
|
||||||
|
};
|
||||||
|
union
|
||||||
|
{
|
||||||
|
Vector3Pod ang;
|
||||||
|
simd::v4f_pod angV4;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConstraintJacobianPair
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class LinA;
|
||||||
|
class LinB;
|
||||||
|
class AngA;
|
||||||
|
class AngB;
|
||||||
|
|
||||||
|
template< class PartSelect >
|
||||||
|
RBX_SIMD_INLINE simd::v4f get() const;
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE simd::v4f getLinA() const { return a.linV4; }
|
||||||
|
RBX_SIMD_INLINE simd::v4f getLinB() const { return b.linV4; }
|
||||||
|
RBX_SIMD_INLINE simd::v4f getAngA() const { return a.angV4; }
|
||||||
|
RBX_SIMD_INLINE simd::v4f getAngB() const { return b.angV4; }
|
||||||
|
|
||||||
|
template< class PartSelect >
|
||||||
|
RBX_SIMD_INLINE void set( const simd::v4f& v );
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE void setLinA( const simd::v4f& v ) { a.linV4 = v; }
|
||||||
|
RBX_SIMD_INLINE void setLinB( const simd::v4f& v ) { b.linV4 = v; }
|
||||||
|
RBX_SIMD_INLINE void setAngA( const simd::v4f& v ) { a.angV4 = v; }
|
||||||
|
RBX_SIMD_INLINE void setAngB( const simd::v4f& v ) { b.angV4 = v; }
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE void reset()
|
||||||
|
{
|
||||||
|
a.reset();
|
||||||
|
b.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE simd::v4f dot( const EffectiveMassPair& _v ) const
|
||||||
|
{
|
||||||
|
simd::v4f partA = getLinA() * _v.getLinA() + getAngA() * _v.getAngA();
|
||||||
|
simd::v4f partB = getLinB() * _v.getLinB() + getAngB() * _v.getAngB();
|
||||||
|
simd::v4f r = partA + partB;
|
||||||
|
return simd::splat<0>(r) + simd::splat<1>(r) + simd::splat<2>(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialize( DebugSerializer& s ) const;
|
||||||
|
|
||||||
|
ConstraintJacobian a;
|
||||||
|
ConstraintJacobian b;
|
||||||
|
};
|
||||||
|
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f ConstraintJacobianPair::get< ConstraintJacobianPair::LinA >() const { return a.linV4; }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f ConstraintJacobianPair::get< ConstraintJacobianPair::LinB >() const { return b.linV4; }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f ConstraintJacobianPair::get< ConstraintJacobianPair::AngA >() const { return a.angV4; }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f ConstraintJacobianPair::get< ConstraintJacobianPair::AngB >() const { return b.angV4; }
|
||||||
|
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE void ConstraintJacobianPair::set< ConstraintJacobianPair::LinA >( const simd::v4f& v ) { a.linV4 = v; }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE void ConstraintJacobianPair::set< ConstraintJacobianPair::LinB >( const simd::v4f& v ) { b.linV4 = v; }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE void ConstraintJacobianPair::set< ConstraintJacobianPair::AngA >( const simd::v4f& v ) { a.angV4 = v; }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE void ConstraintJacobianPair::set< ConstraintJacobianPair::AngB >( const simd::v4f& v ) { b.angV4 = v; }
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "util/G3DCore.h"
|
||||||
|
#include "util/Quaternion.h"
|
||||||
|
|
||||||
|
#include "boost/type_traits.hpp"
|
||||||
|
#include "boost/utility.hpp"
|
||||||
|
#include "boost/cstdint.hpp"
|
||||||
|
#include "boost/container/map.hpp"
|
||||||
|
|
||||||
|
#include "simd/simd.h"
|
||||||
|
#include "rbx/ArrayDynamic.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
|
||||||
|
class DebugSerializer;
|
||||||
|
|
||||||
|
// Compile time 'Has X Method' implementation using 'Substitution Failure is not an Error'
|
||||||
|
template< typename T >
|
||||||
|
struct HasSerializeMethod
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
template<typename U, void (U::*)( DebugSerializer& ) const> struct SFINAE {};
|
||||||
|
template<typename U> static char Test(SFINAE<U, &U::serialize>*);
|
||||||
|
template<typename U> static int Test(...);
|
||||||
|
public:
|
||||||
|
static const bool value = sizeof(Test<T>(0)) == sizeof(char);
|
||||||
|
};
|
||||||
|
|
||||||
|
class DebugSerializerScope
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DebugSerializerScope( DebugSerializer& s );
|
||||||
|
~DebugSerializerScope();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DebugSerializer& serializer;
|
||||||
|
size_t reservedBufferIndex;
|
||||||
|
size_t currentSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DebugSerializer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class T >
|
||||||
|
typename boost::enable_if< boost::is_arithmetic< T >, DebugSerializer >::type& storeAt( const T& t, size_t index )
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
T t;
|
||||||
|
char bytes[ sizeof( T ) ];
|
||||||
|
} u;
|
||||||
|
u.t = t;
|
||||||
|
for( size_t i = 0; i < sizeof( T ); i++ )
|
||||||
|
{
|
||||||
|
data[ index + i ] = u.bytes[ i ];
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class T >
|
||||||
|
typename boost::enable_if< boost::is_arithmetic< T >, DebugSerializer >::type& operator&( const T& t )
|
||||||
|
{
|
||||||
|
size_t index = data.size();
|
||||||
|
data.resize( data.size() + sizeof( T ) );
|
||||||
|
storeAt( t, index );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class T >
|
||||||
|
typename boost::enable_if< boost::is_enum< T >, DebugSerializer >::type& operator&( const T& t )
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
T t;
|
||||||
|
boost::uint8_t bytes[ sizeof( T ) ];
|
||||||
|
} u;
|
||||||
|
u.t = t;
|
||||||
|
for( size_t i = 0; i < sizeof( T ); i++ )
|
||||||
|
{
|
||||||
|
data.push_back( u.bytes[ i ] );
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugSerializer& operator&( const Vector3& v )
|
||||||
|
{
|
||||||
|
*this & v.x & v.y & v.z;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugSerializer& operator&( const Quaternion& q )
|
||||||
|
{
|
||||||
|
*this & q.x & q.y & q.z & q.w;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugSerializer& operator&( const Matrix3& m )
|
||||||
|
{
|
||||||
|
*this & m.row( 0 ) & m.row( 1 ) & m.row( 2 );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugSerializer& operator&( const simd::v4f& v )
|
||||||
|
{
|
||||||
|
*this & simd::extractSlow( v, 0 ) & simd::extractSlow( v, 1 ) & simd::extractSlow( v, 2 ) & simd::extractSlow( v, 3 );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class T, class U >
|
||||||
|
DebugSerializer& operator&( const std::pair< T, U >& p )
|
||||||
|
{
|
||||||
|
*this & p.first & p.second;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class T >
|
||||||
|
DebugSerializer& operator&( const ArrayBase<T>& v )
|
||||||
|
{
|
||||||
|
*this & boost::uint32_t( v.size() );
|
||||||
|
for( const auto& e : v )
|
||||||
|
{
|
||||||
|
*this & e;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class T >
|
||||||
|
DebugSerializer& operator&( const std::vector<T>& v )
|
||||||
|
{
|
||||||
|
*this & boost::uint32_t( v.size() );
|
||||||
|
for( const auto& e : v )
|
||||||
|
{
|
||||||
|
*this & e;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class T >
|
||||||
|
typename boost::enable_if_c< HasSerializeMethod< T >::value && !boost::is_pointer< T >::value, DebugSerializer >::type& operator&( const T& t )
|
||||||
|
{
|
||||||
|
t.serialize( *this );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class T >
|
||||||
|
typename boost::enable_if_c< HasSerializeMethod< T >::value, DebugSerializer >::type& operator&( const T* const t )
|
||||||
|
{
|
||||||
|
t->serialize( *this );
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugSerializer& tag( const char* name )
|
||||||
|
{
|
||||||
|
boost::uint8_t length = strlen(name);
|
||||||
|
*this & length;
|
||||||
|
for( boost::uint8_t i = 0; i < length; i++ )
|
||||||
|
{
|
||||||
|
*this & name[ i ];
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector< char > data;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline DebugSerializerScope::DebugSerializerScope( DebugSerializer& s ): serializer( s )
|
||||||
|
{
|
||||||
|
reservedBufferIndex = s.data.size();
|
||||||
|
size_t size = 0;
|
||||||
|
s & size;
|
||||||
|
// size_t checkSum = 0;
|
||||||
|
// s & checkSum;
|
||||||
|
currentSize = s.data.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DebugSerializerScope::~DebugSerializerScope()
|
||||||
|
{
|
||||||
|
size_t size = serializer.data.size() - currentSize;
|
||||||
|
serializer.storeAt( size, reservedBufferIndex );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "solver/SolverConfig.h"
|
||||||
|
#include "solver/Constraint.h"
|
||||||
|
#include "solver/SolverContainers.h"
|
||||||
|
#include "solver/SolverProfiler.h"
|
||||||
|
#include "solver/SolverSerializer.h"
|
||||||
|
|
||||||
|
#include "v8kernel/SimBody.h"
|
||||||
|
|
||||||
|
#include "boost/unordered/unordered_map.hpp"
|
||||||
|
#include "boost/unordered/unordered_set.hpp"
|
||||||
|
#include "boost/container/vector.hpp"
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
|
||||||
|
class ContactConnector;
|
||||||
|
class RotateJoint;
|
||||||
|
class ContactManifold;
|
||||||
|
class Body;
|
||||||
|
|
||||||
|
typedef std::pair< boost::uint64_t, boost::uint64_t > BodyUIDPair;
|
||||||
|
|
||||||
|
class InconsistentBodyPair
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool operator<( const InconsistentBodyPair& pair ) const
|
||||||
|
{
|
||||||
|
return bodyPair < pair.bodyPair;
|
||||||
|
}
|
||||||
|
|
||||||
|
Body* bodyA;
|
||||||
|
Body* bodyB;
|
||||||
|
BodyUIDPair bodyPair;
|
||||||
|
Constraint::Convergence convergence;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OrderedConnector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ContactConnector* connector;
|
||||||
|
bool swap;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BadConnector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Vector3 position;
|
||||||
|
Constraint::Convergence convergence;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PGSSolver
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PGSSolver();
|
||||||
|
|
||||||
|
// Add/remove SimBodies
|
||||||
|
// High priority bodies will be simulated even if throttled
|
||||||
|
void addSimBody( SimBody* body, bool highPriority );
|
||||||
|
void removeSimBody( SimBody* body );
|
||||||
|
|
||||||
|
// Add/remove constraints
|
||||||
|
void addConstraint( Constraint* _constraint );
|
||||||
|
void removeConstraint( Constraint* _constraint );
|
||||||
|
|
||||||
|
// Solver
|
||||||
|
// If throttled is set to true, only high priority bodies will be simulated.
|
||||||
|
void solve( const std::vector< ContactConnector* >& connectors, float dt, boost::uint64_t debugTime, bool throttled );
|
||||||
|
void solvePositions( const std::vector< ContactConnector* >& _contactConnectors );
|
||||||
|
// Exactly like it was before the physics analyzer (sleeping islands) were submitted
|
||||||
|
void solveLegacy( const std::vector< ContactConnector* >& _contactConnectors, float _dt, boost::uint64_t debugTime, bool _throttled );
|
||||||
|
|
||||||
|
// Create and delete contact manifolds
|
||||||
|
// The parameters are uid's of both Object instances.
|
||||||
|
void addContactManifold( boost::uint64_t _uidA, boost::uint64_t _uidB );
|
||||||
|
void removeContactManifold( boost::uint64_t _uidA, boost::uint64_t _uidB );
|
||||||
|
|
||||||
|
// Clear body cache
|
||||||
|
void clearBodyCache( boost::uint64_t _uid );
|
||||||
|
|
||||||
|
// Switch inconsistent constraint detector
|
||||||
|
void setInconsistentConstraintDetectorEnabled( bool value ) { inconsistentConstraintDetectorEnabled = value; }
|
||||||
|
void setPhysicsAnalyzerBreakOnIssue( bool value ) { physicsAnalyzerBreakOnIssue = value; }
|
||||||
|
bool getPhysicsAnalyzerBreakOnIssue( ) const { return physicsAnalyzerBreakOnIssue; }
|
||||||
|
|
||||||
|
const ArrayBase< InconsistentBodyPair >& getInconsistentBodyPairs() const { return inconsistentBodyPairs; }
|
||||||
|
const ArrayBase< ArrayDynamic< boost::uint64_t > >& getInconsistentBodies() const { return inconsistentBodies; }
|
||||||
|
|
||||||
|
void dumpLog( bool enable );
|
||||||
|
void setUserId( int id ) { userId = id; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void solveInternal( const std::vector< ContactConnector* >& connectors, float dt, boost::uint64_t debugTime, bool throttled, const SolverConfig& _solverConfig );
|
||||||
|
void solveIsland( const ArrayDynamic< Constraint* >& constraints, const ArrayDynamic< SimBody* >& selectedSimBodies,
|
||||||
|
float _dt, const SolverConfig& _solverConfig );
|
||||||
|
ContactManifold* updateContactManifold( const BodyUIDPair& _pairId, const ArrayBase< OrderedConnector >& _manifold );
|
||||||
|
size_t addContactConnectors( ArrayDynamic< ContactManifold* >& _activeManifolds, const std::vector< ContactConnector* >& _connectors, const boost::unordered_set< SimBody* >& _simBodies );
|
||||||
|
void initAnchoredObjects(
|
||||||
|
ArrayDynamic< SolverBodyDynamicProperties >& _bodyVariableData,
|
||||||
|
ArrayDynamic< SolverBodyStaticProperties >& _bodyStaticData,
|
||||||
|
ArrayDynamic< SolverBodyMassAndInertia >& _massAndInertia,
|
||||||
|
ArrayDynamic< float >& _effectiveMassMultipliers,
|
||||||
|
VirtualDisplacementArray& _velocityDeltas,
|
||||||
|
VirtualDisplacementArray& _positionDeltas,
|
||||||
|
int offsetToAnchoredObjects,
|
||||||
|
const ArrayBase< SimBody* >& _anchoredBodyList,
|
||||||
|
const SolverConfig& _config ) const;
|
||||||
|
void integratePositionsAndUpdateSimBodies(
|
||||||
|
SimBody* const * _simBodies,
|
||||||
|
SolverBodyDynamicProperties* const _bodyVariableData,
|
||||||
|
const SolverBodyStaticProperties* const _bodyStaticData,
|
||||||
|
size_t _simBodyCount,
|
||||||
|
const VirtualDisplacementArray& _velocityDeltas,
|
||||||
|
const VirtualDisplacementArray& _positionDeltas,
|
||||||
|
float _dt );
|
||||||
|
void integratePositionsIgnoreVelocitiesAndUpdateSimBodies(
|
||||||
|
SimBody* const * _simBodies,
|
||||||
|
SolverBodyDynamicProperties* const _bodyVariableData,
|
||||||
|
const SolverBodyStaticProperties* const _bodyStaticData,
|
||||||
|
size_t _simBodyCount,
|
||||||
|
const VirtualDisplacementArray& _positionDeltas,
|
||||||
|
float _dt );
|
||||||
|
void detectInconsistentConstraints(
|
||||||
|
VirtualDisplacementArray& positionDeltasSIMD,
|
||||||
|
ArrayBase< ConstraintVariables >& positionStage,
|
||||||
|
const ArrayBase< ConstraintJacobianPair >& jacobians,
|
||||||
|
const ArrayBase< ConstraintJacobianPair >& preconditionedJacobiansPosStage,
|
||||||
|
const ArrayBase< EffectiveMassPair >& effectiveMassesPos,
|
||||||
|
const ArrayBase< float >& sorPos,
|
||||||
|
const ArrayBase< boost::uint8_t >& dimensions,
|
||||||
|
const ArrayBase< boost::uint32_t >& offsets,
|
||||||
|
const ArrayBase< BodyPairIndices >& simBodyPairs,
|
||||||
|
const ArrayBase< Constraint* >& constraints,
|
||||||
|
size_t collisionCount,
|
||||||
|
const SolverConfig& solverConfig );
|
||||||
|
|
||||||
|
|
||||||
|
boost::uint64_t constraintUIDGenerator;
|
||||||
|
// Pure constraints - not including the Collision constraints
|
||||||
|
SolverOrderedMap< boost::uint64_t, Constraint* >::Type pureConstraintSet;
|
||||||
|
|
||||||
|
SolverUnorderedMap< BodyUIDPair, ContactManifold* >::Type contactManifolds;
|
||||||
|
|
||||||
|
class SolverBodyCache
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void serialize( DebugSerializer& s ) const;
|
||||||
|
Vector3 virDPosStageLin;
|
||||||
|
Vector3 virDPosStageAng;
|
||||||
|
Vector3 virDVelStageLin;
|
||||||
|
Vector3 virDVelStageAng;
|
||||||
|
Vector3 linearVelocity;
|
||||||
|
Vector3 angularVelocity;
|
||||||
|
Vector3 integratedLinearVelocity;
|
||||||
|
Vector3 integratedAngularVelocity;
|
||||||
|
SimBody* simBodyDebug;
|
||||||
|
};
|
||||||
|
|
||||||
|
SolverUnorderedMap< boost::uint64_t, SolverBodyCache >::Type bodyCache;
|
||||||
|
boost::unordered_set< SimBody* > simBodies;
|
||||||
|
boost::unordered_set< SimBody* > highPrioritySimBodies;
|
||||||
|
|
||||||
|
// Inconsistent constraint detector
|
||||||
|
bool inconsistentConstraintDetectorEnabled;
|
||||||
|
bool physicsAnalyzerBreakOnIssue;
|
||||||
|
ArrayDynamic< InconsistentBodyPair > inconsistentBodyPairs;
|
||||||
|
ArrayDynamic< ArrayDynamic< boost::uint64_t > > inconsistentBodies;
|
||||||
|
|
||||||
|
// Serializer
|
||||||
|
SolverSerializer serializer;
|
||||||
|
|
||||||
|
// Profilers
|
||||||
|
SolverProfiler gatherCollisionsProfiler;
|
||||||
|
SolverProfiler islandSplitProfiler;
|
||||||
|
SolverProfiler integrateVelocitiesProfiler;
|
||||||
|
SolverProfiler initAnchoredBodiesProfiler;
|
||||||
|
SolverProfiler buildEquationsProfiler;
|
||||||
|
SolverProfiler computeEffectiveMassesProfiler;
|
||||||
|
SolverProfiler preconditioningProfiler;
|
||||||
|
SolverProfiler multiplyEffectiveMassMultipliersProfiler;
|
||||||
|
SolverProfiler initVirDProfiler;
|
||||||
|
SolverProfiler kernelProfiler;
|
||||||
|
SolverProfiler integratePositionsProfiler;
|
||||||
|
SolverProfiler writeCacheProfiler;
|
||||||
|
SolverProfiler solverProfiler;
|
||||||
|
|
||||||
|
bool dumpLogSwitch;
|
||||||
|
int userId;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,288 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "G3D/Vector3.h"
|
||||||
|
#include "simd/simd.h"
|
||||||
|
#include "solver/SolverContainers.h"
|
||||||
|
#include "solver/ConstraintJacobian.h"
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
class DebugSerializer;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Internal representation of dynamic properties of a body (for both simulated and anchored)
|
||||||
|
//
|
||||||
|
class SolverBodyDynamicProperties
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void serialize( DebugSerializer& s ) const;
|
||||||
|
|
||||||
|
Vector3 integratedLinearVelocity;
|
||||||
|
Vector3 integratedAngularVelocity;
|
||||||
|
Matrix3 orientation;
|
||||||
|
Vector3 position;
|
||||||
|
Vector3 linearVelocity;
|
||||||
|
Vector3 angularVelocity;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Symmetric matrix for use as inertia matrix
|
||||||
|
//
|
||||||
|
class SymmetricMatrix
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RBX_SIMD_INLINE Vector3 operator*( const Vector3& v ) const
|
||||||
|
{
|
||||||
|
Vector3 r;
|
||||||
|
r.x = diagonals.x * v.x + offDiagonals.x * v.y + offDiagonals.y * v.z;
|
||||||
|
r.y = offDiagonals.x * v.x + diagonals.y * v.y + offDiagonals.z * v.z;
|
||||||
|
r.z = offDiagonals.y * v.x + offDiagonals.z * v.y + diagonals.z * v.z;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE SymmetricMatrix operator*( float s ) const
|
||||||
|
{
|
||||||
|
SymmetricMatrix r;
|
||||||
|
r.diagonals = s * diagonals;
|
||||||
|
r.offDiagonals = s * offDiagonals;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialize( DebugSerializer& s ) const;
|
||||||
|
|
||||||
|
// [ d0 a b ]
|
||||||
|
// [ a d1 c ]
|
||||||
|
// [ b c d2]
|
||||||
|
Vector3Pod diagonals; // [d0, d1, d2]
|
||||||
|
Vector3Pod offDiagonals; // [a, b, c]
|
||||||
|
};
|
||||||
|
|
||||||
|
class SymmetricMatrixPOD
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
simd::v4f_pod diagonals;
|
||||||
|
simd::v4f_pod offDiagonals;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// SymmetricMatrixSIMD
|
||||||
|
//
|
||||||
|
class SymmetricMatrixSIMD
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RBX_SIMD_INLINE SymmetricMatrixSIMD( const float* _m )
|
||||||
|
{
|
||||||
|
diagonals = simd::load3( _m );
|
||||||
|
offDiagonals = simd::load3( _m + 3 );
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE SymmetricMatrixSIMD( const simd::v4f& _diagonal, const simd::v4f& _offDiagonal ): diagonals( _diagonal ), offDiagonals( _offDiagonal ) { }
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE SymmetricMatrixSIMD( const SymmetricMatrixPOD& _m ): diagonals( _m.diagonals ), offDiagonals( _m.offDiagonals ) { }
|
||||||
|
|
||||||
|
template< int row, int column >
|
||||||
|
RBX_SIMD_INLINE simd::v4f get() const;
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE simd::v4f operator*( const simd::v4f& v ) const
|
||||||
|
{
|
||||||
|
simd::v4f t0 = diagonals * v;
|
||||||
|
simd::v4f t1 = simd::permute<0, 2, 1, 3>( offDiagonals ) * simd::permute< 1, 2, 0, 3>( v );
|
||||||
|
simd::v4f t2 = simd::permute<1, 0, 2, 3>( offDiagonals ) * simd::permute< 2, 0, 1, 3>( v );
|
||||||
|
return t0 + t1 + t2;
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE void invert()
|
||||||
|
{
|
||||||
|
simd::v4f x00x00x02x01 = simd::shuffle< 0, 0, 1, 0 >( diagonals, offDiagonals );
|
||||||
|
simd::v4f x11x00x01x12 = simd::shuffle< 1, 0, 0, 2 >( diagonals, offDiagonals );
|
||||||
|
simd::v4f x22x00x12x02 = simd::shuffle< 2, 0, 2, 1 >( diagonals, offDiagonals );
|
||||||
|
|
||||||
|
simd::v4f x00x00x11x22 = simd::permute< 0, 0, 1, 2 >( diagonals );
|
||||||
|
simd::v4f x12x12x02x01 = simd::permute< 2, 2, 1, 0 >( offDiagonals );
|
||||||
|
|
||||||
|
simd::v4f r = x00x00x02x01 * x11x00x01x12 * x22x00x12x02 - x00x00x11x22 * x12x12x02x01 * x12x12x02x01;
|
||||||
|
simd::v4f d = simd::splat< 0 >( r ) + simd::splat< 2 >( r ) + simd::splat< 3 >( r );
|
||||||
|
simd::v4f dInv = ( simd::splat( 1.0f ) / d );
|
||||||
|
|
||||||
|
simd::v4f x11x22x00 = simd::permute< 1, 2, 0, 3 >( diagonals );
|
||||||
|
simd::v4f x22x00x11 = simd::permute< 2, 0, 1, 3 >( diagonals );
|
||||||
|
simd::v4f x12x02x01 = simd::permute< 2, 1, 0, 3 >( offDiagonals );
|
||||||
|
simd::v4f newDiagonals = dInv * ( x11x22x00 * x22x00x11 - x12x02x01 * x12x02x01 );
|
||||||
|
|
||||||
|
simd::v4f x12x01x02 = simd::permute< 2, 0, 1, 3 >( offDiagonals );
|
||||||
|
simd::v4f x02x12x01 = simd::permute< 1, 2, 0, 3 >( offDiagonals );
|
||||||
|
simd::v4f x01x02x12 = offDiagonals;
|
||||||
|
simd::v4f x22x11x00 = simd::permute< 2, 1, 0, 3 >( diagonals );
|
||||||
|
simd::v4f newOffdiagonals = dInv * ( x12x01x02 * x02x12x01 - x01x02x12 * x22x11x00 );
|
||||||
|
|
||||||
|
diagonals = newDiagonals;
|
||||||
|
offDiagonals = newOffdiagonals;
|
||||||
|
}
|
||||||
|
|
||||||
|
simd::v4f diagonals;
|
||||||
|
simd::v4f offDiagonals;
|
||||||
|
};
|
||||||
|
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<0,0>() const { return simd::splat<0>( diagonals ); }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<1,1>() const { return simd::splat<1>( diagonals ); }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<2,2>() const { return simd::splat<2>( diagonals ); }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<0,1>() const { return simd::splat<0>( offDiagonals ); }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<0,2>() const { return simd::splat<1>( offDiagonals ); }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<1,2>() const { return simd::splat<2>( offDiagonals ); }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<1,0>() const { return get<0,1>(); }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<2,0>() const { return get<0,2>(); }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f SymmetricMatrixSIMD::get<2,1>() const { return get<1,2>(); }
|
||||||
|
|
||||||
|
static RBX_SIMD_INLINE SymmetricMatrixSIMD operator*( const simd::v4f& s, const SymmetricMatrixSIMD& m )
|
||||||
|
{
|
||||||
|
return SymmetricMatrixSIMD( s * m.diagonals, s* m.offDiagonals );
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// SymmetricMatrix2SIMD
|
||||||
|
//
|
||||||
|
class SymmetricMatrix2SIMD
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RBX_SIMD_INLINE SymmetricMatrix2SIMD( ) { }
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE SymmetricMatrix2SIMD( const simd::v4f& d00, const simd::v4f& d11, const simd::v4f& d01 )
|
||||||
|
{
|
||||||
|
m = simd::gatherX( d00, d01, d01, d11 );
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE void load( const float* _m )
|
||||||
|
{
|
||||||
|
m = simd::form( _m[0], _m[2], _m[2], _m[1] );
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE void form( const simd::v4f& d00, const simd::v4f& d11, const simd::v4f& d01 )
|
||||||
|
{
|
||||||
|
m = simd::gatherX( d00, d01, d01, d11 );
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE simd::v4f operator*( const simd::v4f& v ) const
|
||||||
|
{
|
||||||
|
simd::v4f t0 = m * simd::permute< 0, 0, 1, 1 >( v );
|
||||||
|
simd::v4f t1 = simd::permute< 2, 3, 0, 1 >( t0 );
|
||||||
|
return t0 + t1;
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE void invert()
|
||||||
|
{
|
||||||
|
simd::v4f xt = simd::splat< 1 >( m );
|
||||||
|
simd::v4f det = simd::splat< 0 >( m ) * simd::splat< 3 >( m ) - xt * xt;
|
||||||
|
simd::v4f t = simd::select< 0, 1, 1, 0 >( simd::splat( 1.0f ), simd::splat( -1.0f ) ) * simd::permute< 3, 2, 1, 0 >( m );
|
||||||
|
m = ( t / det );
|
||||||
|
}
|
||||||
|
|
||||||
|
template< int row, int column >
|
||||||
|
RBX_SIMD_INLINE simd::v4f get() const;
|
||||||
|
|
||||||
|
simd::v4f m;
|
||||||
|
};
|
||||||
|
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f SymmetricMatrix2SIMD::get<0,0>() const { return simd::splat<0>( m ); }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f SymmetricMatrix2SIMD::get<1,0>() const { return simd::splat<1>( m ); }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f SymmetricMatrix2SIMD::get<0,1>() const { return simd::splat<1>( m ); }
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE simd::v4f SymmetricMatrix2SIMD::get<1,1>() const { return simd::splat<3>( m ); }
|
||||||
|
|
||||||
|
class SolverBodyMassAndInertia
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void serialize( DebugSerializer& s ) const;
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE SymmetricMatrixSIMD getInvInertiaVelStage() const
|
||||||
|
{
|
||||||
|
return inertiaSIMD;
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE SymmetricMatrixSIMD getInvInertiaPosStage( float scale ) const
|
||||||
|
{
|
||||||
|
simd::v4f inertiaScale = simd::splat( scale ) * simd::splat( posToVelMassRatio );
|
||||||
|
SymmetricMatrixSIMD r( inertiaSIMD );
|
||||||
|
return inertiaScale * r;
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE simd::v4f getInvMassVelStage() const
|
||||||
|
{
|
||||||
|
return simd::splat( massInvVelStage );
|
||||||
|
}
|
||||||
|
|
||||||
|
RBX_SIMD_INLINE simd::v4f getInvMassPosStage() const
|
||||||
|
{
|
||||||
|
return simd::splat( massInvVelStage * posToVelMassRatio );
|
||||||
|
}
|
||||||
|
|
||||||
|
class VelStage;
|
||||||
|
class PosStage;
|
||||||
|
|
||||||
|
template< class StageSelect >
|
||||||
|
RBX_SIMD_INLINE simd::v4f getInvMass() const;
|
||||||
|
|
||||||
|
template< class StageSelect >
|
||||||
|
RBX_SIMD_INLINE SymmetricMatrixSIMD getInvInertia( float scale ) const;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
Vector3Pod inertiaDiagonal;
|
||||||
|
float massInvVelStage;
|
||||||
|
Vector3Pod inertiaOffDiagonal;
|
||||||
|
float posToVelMassRatio;
|
||||||
|
};
|
||||||
|
SymmetricMatrixPOD inertiaSIMD;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
RBX_SIMD_INLINE simd::v4f SolverBodyMassAndInertia::getInvMass< SolverBodyMassAndInertia::VelStage >() const
|
||||||
|
{
|
||||||
|
return getInvMassVelStage();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
RBX_SIMD_INLINE simd::v4f SolverBodyMassAndInertia::getInvMass< SolverBodyMassAndInertia::PosStage >() const
|
||||||
|
{
|
||||||
|
return getInvMassPosStage();
|
||||||
|
}
|
||||||
|
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE SymmetricMatrixSIMD SolverBodyMassAndInertia::getInvInertia< SolverBodyMassAndInertia::VelStage >( float scale ) const
|
||||||
|
{
|
||||||
|
return getInvInertiaVelStage();
|
||||||
|
}
|
||||||
|
|
||||||
|
template< >
|
||||||
|
RBX_SIMD_INLINE SymmetricMatrixSIMD SolverBodyMassAndInertia::getInvInertia< SolverBodyMassAndInertia::PosStage >( float scale ) const
|
||||||
|
{
|
||||||
|
return getInvInertiaPosStage( scale );
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Static properties of a body
|
||||||
|
//
|
||||||
|
class SolverBodyStaticProperties
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void serialize( DebugSerializer& s ) const;
|
||||||
|
|
||||||
|
boost::uint64_t bodyUID;
|
||||||
|
boost::uint32_t guid;
|
||||||
|
bool isStatic;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define ENABLE_SOR_CONSTRAINTS
|
||||||
|
#define ENABLE_SOR_COLLISIONS
|
||||||
|
#define ENABLE_LOCAL_SOR_MODULATION
|
||||||
|
#define ENABLE_HINGE_FRICTION
|
||||||
|
#define ENABLE_IMPULSE_CACHE_DAMPING_PER_EQUATION
|
||||||
|
//#define ENABLE_SOLVER_PROFILER
|
||||||
|
#define ENABLE_SOLVER_DEBUG_SERIALIZER
|
||||||
|
//#define MIN_NORM_REPROJECT
|
||||||
|
//#define PGS_MIN_NORM
|
||||||
|
|
||||||
|
//#define DISABLE_ANGULAR_CONSTRAINTS
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
|
||||||
|
class SolverConfig
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
Type_Default,
|
||||||
|
Type_InconsistencyDetector,
|
||||||
|
Type_PositionalCorrection,
|
||||||
|
};
|
||||||
|
SolverConfig( Type type = Type_Default );
|
||||||
|
|
||||||
|
//
|
||||||
|
// Kernel
|
||||||
|
//
|
||||||
|
unsigned pgsIterations;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Collisions
|
||||||
|
//
|
||||||
|
|
||||||
|
// Minimum normal velocity for restitution to be applied
|
||||||
|
float collisionRestitutionThreshold;
|
||||||
|
|
||||||
|
// Ignore penetrations that are smaller than this parameter
|
||||||
|
float collisionPenetrationMargin;
|
||||||
|
|
||||||
|
// Params for variable penetration margin
|
||||||
|
float collisionPenetrationMarginMax;
|
||||||
|
float collisionPenetrationMarginMin;
|
||||||
|
|
||||||
|
// The max height of a bump that a rolling object (sphere) can have, in proportion to it's size, due to hitting an edge between two primitives.
|
||||||
|
float collisionPenetrationMarginMaxBumpProportions;
|
||||||
|
|
||||||
|
// Damping of the penetration resolution
|
||||||
|
float collisionPenetrationResolutionDamping;
|
||||||
|
|
||||||
|
// The velocity at which the penetration allowed will be minimum
|
||||||
|
float collisionPenetrationVelocityForMinMargin;
|
||||||
|
|
||||||
|
// Threshold tangential velocity between static and dynamic friction
|
||||||
|
float collisionFrictionStaticToDynamicThreshold;
|
||||||
|
|
||||||
|
// Tunning constant for static friction
|
||||||
|
float collisionFrictionStaticScale;
|
||||||
|
|
||||||
|
// Tunning constant for dynamic friction
|
||||||
|
float collisionFrictionDynamicScale;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Align2Axes Constraint
|
||||||
|
//
|
||||||
|
|
||||||
|
// Angular friction velocity stage
|
||||||
|
float align2AxesFrictionConstant;
|
||||||
|
|
||||||
|
// Angular friction position stage
|
||||||
|
float align2AxesPositionStageFrictionConstant;
|
||||||
|
|
||||||
|
// Maximum angle for angular correction in degrees
|
||||||
|
float align2AxesMaxCorrectiveAngle;
|
||||||
|
|
||||||
|
float align2AxesCorrectionDamping;
|
||||||
|
|
||||||
|
//
|
||||||
|
// BallInSocket
|
||||||
|
//
|
||||||
|
|
||||||
|
// Maximum corrective distance
|
||||||
|
float ballInSocketMaxCorrectionByStabilization;
|
||||||
|
|
||||||
|
float ballInSocketCorrectionDamping;
|
||||||
|
|
||||||
|
//
|
||||||
|
// SOR Modulation
|
||||||
|
//
|
||||||
|
|
||||||
|
// Create a common structure for these...
|
||||||
|
// Constraints
|
||||||
|
struct ModulationParams
|
||||||
|
{
|
||||||
|
float thresholdMax;
|
||||||
|
float thresholdMin;
|
||||||
|
float aggressiveValue;
|
||||||
|
float conservativeValue;
|
||||||
|
float easingUpToAggressive;
|
||||||
|
float easingDownToConservative;
|
||||||
|
};
|
||||||
|
|
||||||
|
ModulationParams sorConstraintsModulation;
|
||||||
|
ModulationParams sorCollisionsModulation;
|
||||||
|
ModulationParams cacheVStageModulation;
|
||||||
|
ModulationParams cachePStageModulation;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Stabilization
|
||||||
|
//
|
||||||
|
float stabilizationMassReductionPower;
|
||||||
|
float stabilizationInertiaScale;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Cache
|
||||||
|
//
|
||||||
|
float velCacheDamping;
|
||||||
|
float posCacheDamping;
|
||||||
|
bool constraintCachingEnabled;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Integration
|
||||||
|
//
|
||||||
|
float angularDamping;
|
||||||
|
bool updateSimBodies;
|
||||||
|
bool integrateOnlyPositions;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Block PGS
|
||||||
|
//
|
||||||
|
bool blockPGSEnabled;
|
||||||
|
|
||||||
|
//
|
||||||
|
// SOR
|
||||||
|
//
|
||||||
|
float velocityStageSOREnabled;
|
||||||
|
float positionStageSOREnabled;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Virtual masses
|
||||||
|
//
|
||||||
|
bool virtualMassesEnabled;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Use sim islands
|
||||||
|
//
|
||||||
|
bool useSimIslands;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Conflicting constraints detector
|
||||||
|
//
|
||||||
|
bool inconsistentConstraintDetectorEnabled;
|
||||||
|
unsigned inconsistentConstraintMaxIterations;
|
||||||
|
|
||||||
|
float inconsistentConstraintBallInSocketResidualThreshold;
|
||||||
|
float inconsistentConstraintDeltaThreshold;
|
||||||
|
float inconsistentConstraintAlign2AxesThreshold;
|
||||||
|
float inconsistentConstraintCollisionThreshold;
|
||||||
|
float inconsistentConstraintCollisionBaseThreshold;
|
||||||
|
bool printConvergenceDiagnostics;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "solver/SolverConfig.h"
|
||||||
|
#include "boost/unordered/unordered_map.hpp"
|
||||||
|
#include "boost/container/vector.hpp"
|
||||||
|
|
||||||
|
#include "rbx/DenseHash.h"
|
||||||
|
#include "util/G3DCore.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
|
||||||
|
class SimBody;
|
||||||
|
|
||||||
|
// If you want to have the map visible in the debugger, enable this
|
||||||
|
// #define SOLVER_DEBUG_MAP
|
||||||
|
|
||||||
|
template< class K, class T >
|
||||||
|
struct SolverUnorderedMap
|
||||||
|
{
|
||||||
|
#ifdef SOLVER_DEBUG_MAP
|
||||||
|
// Use a std map in non-release for easier debugger inspection
|
||||||
|
typedef std::map< K, T > Type;
|
||||||
|
#else
|
||||||
|
// This is faster than a std::map as it uses a hash table
|
||||||
|
typedef boost::unordered::unordered_map< K, T > Type;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
template< class K, class T >
|
||||||
|
struct SolverOrderedMap
|
||||||
|
{
|
||||||
|
typedef std::map< K, T > Type;
|
||||||
|
};
|
||||||
|
|
||||||
|
//typedef SolverUnorderedMap< const SimBody*, int >::Type BodyIndexation;
|
||||||
|
typedef DenseHashMap< const SimBody*, int > BodyIndexation;
|
||||||
|
|
||||||
|
// It's so that we can use a Vector3 in unions
|
||||||
|
class Vector3Pod
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void operator=( const Vector3& v )
|
||||||
|
{
|
||||||
|
x = v.x;
|
||||||
|
y = v.y;
|
||||||
|
z = v.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator Vector3() const
|
||||||
|
{
|
||||||
|
return Vector3(x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
float dot( const Vector3& v ) const
|
||||||
|
{
|
||||||
|
return x * v.x + y * v.y + z * v.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3Pod& operator+=( const Vector3& v )
|
||||||
|
{
|
||||||
|
x += v.x;
|
||||||
|
y += v.y;
|
||||||
|
z += v.z;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
float x, y, z;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline Vector3Pod operator*( float s, const Vector3Pod& v )
|
||||||
|
{
|
||||||
|
Vector3Pod r;
|
||||||
|
r.x = s * v.x;
|
||||||
|
r.y = s * v.y;
|
||||||
|
r.z = s * v.z;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Vector3Pod operator+( const Vector3Pod& u, const Vector3Pod& v )
|
||||||
|
{
|
||||||
|
Vector3Pod r;
|
||||||
|
r.x = u.x + v.x;
|
||||||
|
r.y = u.y + v.y;
|
||||||
|
r.z = u.z + v.z;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "solver/SolverConfig.h"
|
||||||
|
#include "boost/cstdint.hpp"
|
||||||
|
#include "rbx/ArrayDynamic.h"
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
|
||||||
|
class ConstraintJacobianPair;
|
||||||
|
class BodyPairIndices;
|
||||||
|
class SolverBodyStaticProperties;
|
||||||
|
class SolverBodyMassAndInertia;
|
||||||
|
class ConstraintVariables;
|
||||||
|
class VirtualDisplacementArray;
|
||||||
|
class VirtualDisplacementArray;
|
||||||
|
class EffectiveMassPair;
|
||||||
|
|
||||||
|
void PGSComputeEffectiveMasses(
|
||||||
|
EffectiveMassPair* _effectiveMassesVelStage,
|
||||||
|
EffectiveMassPair* _effectiveMassesPosStage,
|
||||||
|
size_t _constraintCount,
|
||||||
|
const boost::uint8_t* _dimensions,
|
||||||
|
const ConstraintJacobianPair* _jacobians,
|
||||||
|
const BodyPairIndices* _pairs,
|
||||||
|
const SolverBodyMassAndInertia* _massAndIntertia,
|
||||||
|
const SolverConfig& _config );
|
||||||
|
|
||||||
|
void PGSApplyEffectiveMassMultipliers(
|
||||||
|
EffectiveMassPair* _effectiveMassesVelStage,
|
||||||
|
EffectiveMassPair* _effectiveMassesPosStage,
|
||||||
|
size_t _constraintCount,
|
||||||
|
const boost::uint8_t* _dimensions,
|
||||||
|
const float* _multipliers,
|
||||||
|
const BodyPairIndices* _pairs,
|
||||||
|
const SolverConfig& _config );
|
||||||
|
|
||||||
|
void PGSPreconditionConstraintEquations(
|
||||||
|
ConstraintJacobianPair* _preconditionedJacobiansVelStage,
|
||||||
|
ConstraintJacobianPair* _preconditionedJacobiansPosStage,
|
||||||
|
ConstraintVariables* _velocityStageVariables,
|
||||||
|
ConstraintVariables* _positionStageVariables,
|
||||||
|
size_t _constraintCount,
|
||||||
|
const boost::uint8_t* _dimensions,
|
||||||
|
const boost::uint8_t* _useBlock,
|
||||||
|
const float* __restrict _sorVel,
|
||||||
|
const float* __restrict _sorPos,
|
||||||
|
const ConstraintJacobianPair* _jacobians,
|
||||||
|
const EffectiveMassPair* _effectiveMassesVelStage,
|
||||||
|
const EffectiveMassPair* _effectiveMassesPosStage );
|
||||||
|
|
||||||
|
void PGSInitVirtualDisplacements(
|
||||||
|
VirtualDisplacementArray& _virDVel,
|
||||||
|
VirtualDisplacementArray& _virDPos,
|
||||||
|
const EffectiveMassPair* _effectiveMassesVelStage,
|
||||||
|
const EffectiveMassPair* _effectiveMassesPosStage,
|
||||||
|
size_t _constraintCount,
|
||||||
|
const boost::uint8_t* _dimensions,
|
||||||
|
const ConstraintVariables* __restrict _velStage,
|
||||||
|
const ConstraintVariables* __restrict _posStage,
|
||||||
|
const BodyPairIndices* _pairs,
|
||||||
|
const SolverConfig& _config );
|
||||||
|
|
||||||
|
void PGSSolveKernel(
|
||||||
|
ConstraintVariables* __restrict _velStage,
|
||||||
|
ConstraintVariables* __restrict _posStage,
|
||||||
|
VirtualDisplacementArray& _virDVel,
|
||||||
|
VirtualDisplacementArray& _virDPos,
|
||||||
|
size_t _constraintCount,
|
||||||
|
size_t _collisionCount,
|
||||||
|
const boost::uint8_t* _dimensions,
|
||||||
|
const BodyPairIndices* _pairs,
|
||||||
|
const ConstraintJacobianPair* _preconditionedJacobiansVelStage,
|
||||||
|
const ConstraintJacobianPair* _preconditionedJacobiansPosStage,
|
||||||
|
const EffectiveMassPair* _effectiveMassesVelStage,
|
||||||
|
const EffectiveMassPair* _effectiveMassesPosStage,
|
||||||
|
const SolverConfig& _config );
|
||||||
|
|
||||||
|
void PGSSolveKernelComputeErrors(
|
||||||
|
ArrayBase< float >& _residuals,
|
||||||
|
ArrayBase< float >& _deltaResiduals,
|
||||||
|
ArrayBase< ConstraintVariables >& _vars,
|
||||||
|
VirtualDisplacementArray& _virD,
|
||||||
|
size_t _constraintCount,
|
||||||
|
size_t _collisionCount,
|
||||||
|
size_t _bodyCount,
|
||||||
|
const boost::uint8_t* _dimensions,
|
||||||
|
const BodyPairIndices* _pairs,
|
||||||
|
const ConstraintJacobianPair* _jacobians,
|
||||||
|
const ConstraintJacobianPair* _preconditionedJacobians,
|
||||||
|
const EffectiveMassPair* _effectiveMasses,
|
||||||
|
const SolverConfig& _config );
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "rbx/rbxTime.h"
|
||||||
|
#include "RbxAssert.h"
|
||||||
|
#include "util/standardout.h"
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
|
||||||
|
//
|
||||||
|
// Prints average timing after the given number of samples were taken
|
||||||
|
//
|
||||||
|
class SolverProfiler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SolverProfiler( int _samples, const char* _format ): maxSamples( _samples ), format( _format )
|
||||||
|
{
|
||||||
|
accumulator = Time::Interval::zero();
|
||||||
|
currentSamples = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start()
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_SOLVER_PROFILER
|
||||||
|
startTime = Time::now( Time::Precise );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void end()
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_SOLVER_PROFILER
|
||||||
|
Time::Interval total = Time::now( Time::Precise ) - startTime;
|
||||||
|
accumulator += total;
|
||||||
|
currentSamples++;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void printStats()
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_SOLVER_PROFILER
|
||||||
|
static bool enable = true;
|
||||||
|
if( currentSamples >= maxSamples && enable )
|
||||||
|
{
|
||||||
|
currentSamples = 0;
|
||||||
|
StandardOut::singleton()->printf( MESSAGE_OUTPUT, format, accumulator.msec() / maxSamples );
|
||||||
|
accumulator = Time::Interval::zero();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RBX::Time startTime;
|
||||||
|
Time::Interval accumulator;
|
||||||
|
const char* format;
|
||||||
|
int maxSamples;
|
||||||
|
int currentSamples;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "solver/SolverConfig.h"
|
||||||
|
#include "solver/SolverContainers.h"
|
||||||
|
#include "solver/DebugSerializer.h"
|
||||||
|
|
||||||
|
#include "util/standardout.h"
|
||||||
|
|
||||||
|
#include "boost/filesystem.hpp"
|
||||||
|
|
||||||
|
namespace RBX
|
||||||
|
{
|
||||||
|
|
||||||
|
class SolverSerializer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SolverSerializer(): enabled( false ), fileOpened( false ) { }
|
||||||
|
|
||||||
|
void update( bool _enabled, int userId, boost::uint64_t debugTime )
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_SOLVER_DEBUG_SERIALIZER
|
||||||
|
bool switchState = ( enabled != _enabled );
|
||||||
|
bool close = false;
|
||||||
|
if( switchState )
|
||||||
|
{
|
||||||
|
if( !enabled )
|
||||||
|
{
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
enabled = false;
|
||||||
|
close = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( !enabled )
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t bufferSize = 10 * 1024 * 1024;
|
||||||
|
|
||||||
|
if( !fileOpened )
|
||||||
|
{
|
||||||
|
debugSerializer.data.reserve( bufferSize + 1024 * 1024 );
|
||||||
|
boost::filesystem::path path = boost::filesystem::temp_directory_path();
|
||||||
|
path /= "ROBLOX";
|
||||||
|
path /= "SolverLog_Client";
|
||||||
|
path += boost::lexical_cast<std::string>( userId );
|
||||||
|
path += ".bin";
|
||||||
|
myFile.open (path.c_str(), std::ios::out | std::ios::binary);
|
||||||
|
fileOpened = true;
|
||||||
|
debugSerializer & userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( close || debugSerializer.data.size() > bufferSize )
|
||||||
|
{
|
||||||
|
myFile.write( debugSerializer.data.data(), debugSerializer.data.size() );
|
||||||
|
debugSerializer.data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( close && fileOpened )
|
||||||
|
{
|
||||||
|
close = false;
|
||||||
|
enabled = false;
|
||||||
|
myFile.close();
|
||||||
|
fileOpened = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boost::uint64_t frame = 0;
|
||||||
|
if( enabled )
|
||||||
|
{
|
||||||
|
debugSerializer & frame;
|
||||||
|
debugSerializer & debugTime;
|
||||||
|
frame++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void serializeConstraints( const ArrayBase< Constraint* >& connectors )
|
||||||
|
{
|
||||||
|
if( enabled )
|
||||||
|
{
|
||||||
|
debugSerializer.tag("Connectors");
|
||||||
|
debugSerializer & (boost::uint32_t)connectors.size();
|
||||||
|
for( const auto* c : connectors )
|
||||||
|
{
|
||||||
|
debugSerializer & (boost::uint8_t)c->getType() & c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void serializeForces( const ArrayBase< SimBody* >& simBodies, boost::uint32_t total )
|
||||||
|
{
|
||||||
|
if( enabled )
|
||||||
|
{
|
||||||
|
debugSerializer.tag("Forces");
|
||||||
|
debugSerializer & total;
|
||||||
|
size_t i = 0;
|
||||||
|
for( i = 0; i < simBodies.size(); i++ )
|
||||||
|
{
|
||||||
|
debugSerializer & simBodies[ i ]->getForce();
|
||||||
|
debugSerializer & simBodies[ i ]->getTorque();
|
||||||
|
debugSerializer & simBodies[ i ]->getImpulse();
|
||||||
|
debugSerializer & simBodies[ i ]->getRotationallmpulse();
|
||||||
|
}
|
||||||
|
Vector3 zero = Vector3::zero();
|
||||||
|
for( ; i < total; i++ )
|
||||||
|
{
|
||||||
|
debugSerializer & zero & zero & zero & zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void serializeComputedImpulse( const ArrayBase< ConstraintVariables >& velocityStage, const ArrayBase< ConstraintVariables >& positionStage )
|
||||||
|
{
|
||||||
|
if(enabled)
|
||||||
|
{
|
||||||
|
ArrayDynamic< float > impulses;
|
||||||
|
impulses.reserve(velocityStage.size());
|
||||||
|
for( const auto& v : velocityStage )
|
||||||
|
{
|
||||||
|
impulses.push_back(v.impulse);
|
||||||
|
}
|
||||||
|
debugSerializer & impulses;
|
||||||
|
impulses.clear();
|
||||||
|
impulses.reserve(velocityStage.size());
|
||||||
|
for( const auto& v : positionStage )
|
||||||
|
{
|
||||||
|
impulses.push_back(v.impulse);
|
||||||
|
}
|
||||||
|
debugSerializer & impulses;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class Cache >
|
||||||
|
void serializeBodyCache( const Cache& bodyCache )
|
||||||
|
{
|
||||||
|
if( enabled )
|
||||||
|
{
|
||||||
|
debugSerializer & boost::uint32_t( bodyCache.size() );
|
||||||
|
for( const auto& it : bodyCache )
|
||||||
|
{
|
||||||
|
debugSerializer & (boost::uint32_t)it.second.simBodyDebug->getBody()->getGuidIndex();
|
||||||
|
debugSerializer & it.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class T >
|
||||||
|
SolverSerializer& operator&( const T& t )
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_SOLVER_DEBUG_SERIALIZER
|
||||||
|
if( enabled )
|
||||||
|
{
|
||||||
|
debugSerializer & t;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template< class T >
|
||||||
|
SolverSerializer& operator&( const ArrayDynamic< T >& t )
|
||||||
|
{
|
||||||
|
#ifdef ENABLE_SOLVER_DEBUG_SERIALIZER
|
||||||
|
if( enabled )
|
||||||
|
{
|
||||||
|
debugSerializer & static_cast< const ArrayBase< T >& >( t );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
SolverSerializer& tag( const char* name )
|
||||||
|
{
|
||||||
|
if( enabled )
|
||||||
|
{
|
||||||
|
debugSerializer.tag(name);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream myFile;
|
||||||
|
bool fileOpened;
|
||||||
|
bool enabled;
|
||||||
|
DebugSerializer debugSerializer;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "rbx/boost.hpp"
|
||||||
|
#include "rbx/threadsafe.h"
|
||||||
|
#include "rbx/signal.h"
|
||||||
|
#include "rbx/TaskScheduler.Job.h"
|
||||||
|
|
||||||
|
#include <boost/unordered_map.hpp>
|
||||||
|
#include <boost/function.hpp>
|
||||||
|
|
||||||
|
#include "util/Name.h"
|
||||||
|
#include "util/Region3.h"
|
||||||
|
#include "reflection/YieldFunction.h"
|
||||||
|
#include "v8tree/Instance.h"
|
||||||
|
#include "V8DataModel/DataModel.h"
|
||||||
|
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user