Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Client/App/App.vcproj
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,10 @@
RelativePath=".\include\v8datamodel\Teams.h"
>
</File>
<File
RelativePath=".\include\v8datamodel\TimerService.h"
>
</File>
<File
RelativePath=".\include\v8datamodel\Tool.h"
>
Expand Down Expand Up @@ -942,6 +946,14 @@
>
</File>
</Filter>
<Filter
Name="security"
>
<File
RelativePath=".\include\security\SecurityContext.h"
>
</File>
</Filter>
</Filter>
<Filter
Name="v8kernel"
Expand Down Expand Up @@ -1315,6 +1327,14 @@
>
</File>
</Filter>
<Filter
Name="security"
>
<File
RelativePath=".\security\SecurityContext.cpp"
>
</File>
</Filter>
</Files>
<Globals>
</Globals>
Expand Down
1 change: 1 addition & 0 deletions Client/App/include/gui/Gui.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include "RbxGraphics/Adorn.h"
#include "v8tree/Instance.h"
#include "gui/GuiEvent.h"
#include "gui/Layout.h"
Expand Down
10 changes: 8 additions & 2 deletions Client/App/include/reflection/property.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,14 @@ namespace RBX
TypedPropertyDescriptor(ClassDescriptor&, const Type&, const char*, const char*, std::auto_ptr<GetSet>, Functionality);
public:
virtual bool isReadOnly() const;
PropType getValue(const DescribedBase*) const;
void setValue(DescribedBase*, const PropType&) const;
PropType getValue(const DescribedBase* object) const
{
return getset->getValue(object);
}
void setValue(DescribedBase* object, const PropType& value) const
{
getset->setValue(object, value);
}
virtual bool equalValues(const DescribedBase*, const DescribedBase*) const;
virtual bool hasStringValue() const;
virtual std::string getStringValue(const DescribedBase*) const;
Expand Down
89 changes: 89 additions & 0 deletions Client/App/include/security/SecurityContext.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include <boost/thread/tss.hpp>
#include <G3D/format.h>

namespace RBX
{
namespace Security
{
enum Identities
{
Anonymous,
LocalGUI,
GameScript,
CmdLine,
TrustedCOM,
TrustedWebService,
Replicator
};

enum Permissions
{
None,
Administrator
};

class Context
{
friend class Impersonator;

private:
const Identities identity;
public:
void requirePermission(Permissions permission, const char* operation) const
{
if (!isInRole(identity, permission))
{
if (operation)
throw std::runtime_error(G3D::format("The current security context cannot %s", operation));
else
throw std::runtime_error(G3D::format("The current security context cannot perform the requested operation"));
}
}

bool hasPermission(Permissions);
private:
Context(Identities identity)
: identity(identity)
{
}

public:
static Context& current()
{
Context* context = ptr().get();
if (!context)
{
context = new Context(Anonymous);
ptr().reset(context);
}

return *context;
}
static __declspec(noinline) bool isInRole(Identities identity, Permissions permission);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this noinline?
It won't inline regardless, since its defined in a C++ file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SecurityContext::requirePermission does not inline this function in RBXGS although it was inlined for me when I was matching this function.

Functions defined in the source file can STILL be inlined, see BlockBlockContact::computeIsColliding overloads

Copy link
Collaborator

@bluepilledgreat bluepilledgreat Jan 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SecurityContext::requirePermission does not inline this function in RBXGS although it was inlined for me when I was matching this function.

How? requirePermission is defined in the header, and isInRole is defined in the C++ file. It should not inline.

Functions defined in the source file can STILL be inlined, see BlockBlockContact::computeIsColliding overloads

Shouldn't be possible.

private:
static boost::thread_specific_ptr<Context>& ptr()
{
static boost::thread_specific_ptr<Context> value;
return value;
}
};

class Impersonator
{
private:
Context* previous;
public:
Impersonator(Identities identity)
{
Context* newContext = new Context(identity);
previous = Context::ptr().release();
Context::ptr().reset(newContext);
}

~Impersonator()
{
Context::ptr().reset(previous);
}
};
}
}
2 changes: 1 addition & 1 deletion Client/App/include/v8datamodel/ICameraOwner.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#pragma once
#include <vector>
#include <g3d/gcamera.h>
#include "v8datamodel/Camera.h"
#include "util/Extents.h"

namespace RBX
{
class Primitive;
class PartInstance;
class Camera;
class __declspec(novtable) ICameraOwner
{
private:
Expand Down
26 changes: 26 additions & 0 deletions Client/App/include/v8datamodel/TimerService.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include "util/RunStateOwner.h"

namespace RBX
{
extern const char* sTimerService;

class TimerService : public DescribedCreatable<TimerService, Instance, &sTimerService>, public Service, public Listener<RunService, Heartbeat>
{
class Item
{
public:
G3D::RealTime time;
boost::function0<void> func;
};

private:
boost::shared_ptr<RunService> runService;
std::list<Item> items;
public:
TimerService();
void delay(boost::function0<void>, double);
protected:
virtual void onServiceProvider(const ServiceProvider*, const ServiceProvider*);
virtual void onEvent(const RunService*, Heartbeat);
};
}
27 changes: 27 additions & 0 deletions Client/App/security/SecurityContext.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include "security/SecurityContext.h"

namespace RBX
{
namespace Security
{
bool Context::isInRole(Identities identity, Permissions permission)
{
switch (identity)
{
case Anonymous:
case GameScript:
return permission == None;

case LocalGUI:
case CmdLine:
case TrustedCOM:
case TrustedWebService:
case Replicator:
return true;

default:
return false;
}
}
}
}
16 changes: 7 additions & 9 deletions Client/App/v8datamodel/PartInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@

namespace RBX
{
const char* const category_Part = "Part";

static const Reflection::PropDescriptor<PartInstance, G3D::Vector3> prop_PositionUi("Position", "Data", &PartInstance::getTranslationUi, NULL, Reflection::PropertyDescriptor::LEGACY);
static const Reflection::PropDescriptor<PartInstance, G3D::Vector3> prop_Velocity("Velocity", "Data", &PartInstance::getLinearVelocity, NULL, Reflection::PropertyDescriptor::LEGACY);
static const Reflection::PropDescriptor<PartInstance, G3D::Vector3> prop_SizeUi("Size", category_Part, &PartInstance::getPartSizeUi, NULL, Reflection::PropertyDescriptor::LEGACY);
static const Reflection::PropDescriptor<PartInstance, bool> prop_Dragging("DraggingV1", "Behavior", &PartInstance::getDragging, NULL, Reflection::PropertyDescriptor::LEGACY);
static const Reflection::PropDescriptor<PartInstance, PartInstance::FormFactor> prop_formFactor("FormFactor", category_Part, &PartInstance::getFormFactor, NULL, Reflection::PropertyDescriptor::LEGACY);
static const Reflection::PropDescriptor<PartInstance, float> prop_Friction("Friction", category_Part, &PartInstance::getFriction, NULL, Reflection::PropertyDescriptor::LEGACY);
static const Reflection::PropDescriptor<PartInstance, float> prop_Elasticity("Elasticity", category_Part, &PartInstance::getElasticity, NULL, Reflection::PropertyDescriptor::LEGACY);
static const Reflection::PropDescriptor<PartInstance, G3D::Vector3> prop_PositionUi("Position", "Data", &PartInstance::getTranslationUi, &PartInstance::setTranslationUi, Reflection::PropertyDescriptor::UI);
static const Reflection::PropDescriptor<PartInstance, G3D::Vector3> prop_Velocity("Velocity", "Data", &PartInstance::getLinearVelocity, &PartInstance::setLinearVelocity, Reflection::PropertyDescriptor::STANDARD);
static const Reflection::PropDescriptor<PartInstance, G3D::Vector3> prop_SizeUi("Size", category_Part, &PartInstance::getPartSizeUi, &PartInstance::setPartSizeUi, Reflection::PropertyDescriptor::UI);
static const Reflection::PropDescriptor<PartInstance, bool> prop_Dragging("DraggingV1", "Behavior", &PartInstance::getDragging, &PartInstance::setDragging, Reflection::PropertyDescriptor::STREAMING);
static const Reflection::PropDescriptor<PartInstance, PartInstance::FormFactor> prop_formFactor("FormFactor", category_Part, &PartInstance::getFormFactor, &PartInstance::setFormFactorXml, Reflection::PropertyDescriptor::STREAMING);
static const Reflection::PropDescriptor<PartInstance, float> prop_Friction("Friction", category_Part, &PartInstance::getFriction, &PartInstance::setFriction, Reflection::PropertyDescriptor::STANDARD);
static const Reflection::PropDescriptor<PartInstance, float> prop_Elasticity("Elasticity", category_Part, &PartInstance::getElasticity, &PartInstance::setElasticity, Reflection::PropertyDescriptor::STANDARD);

namespace Reflection
{
Expand Down
8 changes: 8 additions & 0 deletions Client/Network/Network.vcproj
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,14 @@
RelativePath=".\IdManager.cpp"
>
</File>
<File
RelativePath=".\Player.cpp"
>
</File>
<File
RelativePath=".\Players.cpp"
>
</File>
<File
RelativePath=".\Replicator.cpp"
>
Expand Down
137 changes: 137 additions & 0 deletions Client/Network/Player.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#include "Player.h"
#include "Client.h"
#include "v8datamodel/TimerService.h"

namespace RBX
{
namespace Network
{
Reflection::PropDescriptor<Player, BrickColor> prop_teamColor("TeamColor", "Team", &Player::getTeamColor, &Player::setTeamColor, Reflection::PropertyDescriptor::STANDARD);
Reflection::PropDescriptor<Player, bool> prop_neutral("Neutral", "Team", &Player::getNeutral, &Player::setNeutral, Reflection::PropertyDescriptor::STANDARD);
Reflection::PropDescriptor<Player, std::string> prop_characterAppearance("CharacterAppearance", "Data", &Player::getCharacterAppearance, &Player::setCharacterAppearance, Reflection::PropertyDescriptor::STANDARD);

Reflection::SignalDesc<Player, void(float)> event_Idled("Idled", "time");

Backpack* Player::getPlayerBackpack() const
{
Backpack* backpack = findFirstChildOfType<Backpack>();

RBXASSERT(backpack != NULL);
return backpack;
}

void Player::onCharacterChangedFrontend()
{
RBXASSERT(Players::frontendProcessing(this, true));

Player* localPlayer = Players::findLocalPlayer(this);
if (this == localPlayer)
{
Workspace* workspace = ServiceProvider::find<Workspace>(this);
RBXASSERT(workspace != NULL);

if (!character)
{
workspace->getCamera()->setCameraType(Camera::FIXED_CAMERA);
workspace->getCamera()->setDistanceFromTarget(0.0f);
workspace->getCamera()->zoom(-1.0f);
}
else
{
workspace->getCamera()->setCameraSubject(Humanoid::modelIsCharacter(character.get()));
workspace->getCamera()->setCameraType(Camera::CUSTOM_CAMERA);
workspace->getCamera()->setDistanceFromTarget(13.0f);
workspace->getCamera()->zoom(-1.0f);
workspace->setDefaultMouseCommand();
}
}
}

void Player::setTeamColor(BrickColor value)
{
if (value != teamColor)
{
teamColor = value;
raisePropertyChanged(prop_teamColor);
}
}

void Player::setNeutral(bool value)
{
if (value != neutral)
{
neutral = value;
raisePropertyChanged(prop_neutral);
}
}

void Player::removeCharacter()
{
if (!Players::backendProcessing(this, true))
throw std::runtime_error("RemoveCharacter can only be called by the backend server");

setCharacter(NULL);
}

void Player::setName(const std::string& value)
{
Security::Context::current().requirePermission(Security::Administrator, "set a Player's name");
Instance::setName(value);
}

void Player::setCharacterAppearance(const std::string& value)
{
if (value != characterAppearance)
{
characterAppearance = value;
if (Players::backendProcessing(this, false))
loadCharacterAppearance();

raisePropertyChanged(prop_characterAppearance);
}
}

void Player::onServiceProvider(const ServiceProvider* oldProvider, const ServiceProvider* newProvider)
{
if (oldProvider && Players::backendProcessing(oldProvider, true))
setCharacter(NULL);

Instance::onServiceProvider(oldProvider, newProvider);

if (newProvider && Players::frontendProcessing(newProvider, true))
onCharacterChangedFrontend();

if (!oldProvider && Players::frontendProcessing(newProvider, true))
{
RBXASSERT(Players::frontendProcessing(this, true));
lastActivityTime = G3D::System::getLocalTime();
doPeriodicIdleCheck();
}
}

void Player::doPeriodicIdleCheck()
{
if (ServiceProvider::findServiceProvider(this))
{
RBXASSERT(Players::frontendProcessing(this, true));
if (lastActivityTime != 0.0)
{
G3D::RealTime idleTime = G3D::System::getLocalTime() - lastActivityTime;
if (idleTime > 120.0)
{
Players* players = ServiceProvider::find<Players>(this);
if (players && players->getLocalPlayer() && Players::clientIsPresent(this, true))
{
event_Idled.fire(this, idleTime);
}
}
}

TimerService* timerService = ServiceProvider::create<TimerService>(this);

if (timerService)
timerService->delay(boost::bind(&Player::doPeriodicIdleCheck, shared_from(this)), 30.0);
}
}
}
}
Loading