From 3936efef3af36c2f1d164817f35efdf1c370b0d8 Mon Sep 17 00:00:00 2001 From: luasoft10 Date: Mon, 5 Jan 2026 22:37:28 +0200 Subject: [PATCH 01/15] Players --- Client/App/App.vcproj | 24 +++++ Client/App/include/gui/Gui.h | 1 + Client/App/include/reflection/property.h | 10 ++- Client/App/include/security/SecurityContext.h | 79 ++++++++++++++++ Client/App/include/v8datamodel/ICameraOwner.h | 2 +- Client/App/include/v8tree/Service.h | 3 + Client/App/security/SecurityContext.cpp | 28 ++++++ Client/App/v8datamodel/PartInstance.cpp | 14 +-- Client/Network/Network.vcproj | 8 ++ Client/Network/Player.cpp | 90 +++++++++++++++++++ Client/Network/Players.cpp | 28 ++++++ Client/Network/include/Network/Player.h | 48 +++++++--- Client/Network/include/Network/Players.h | 56 +++++++++--- 13 files changed, 354 insertions(+), 37 deletions(-) create mode 100644 Client/App/include/security/SecurityContext.h create mode 100644 Client/App/security/SecurityContext.cpp create mode 100644 Client/Network/Player.cpp create mode 100644 Client/Network/Players.cpp diff --git a/Client/App/App.vcproj b/Client/App/App.vcproj index fe1db49b..76b2be1a 100644 --- a/Client/App/App.vcproj +++ b/Client/App/App.vcproj @@ -934,6 +934,14 @@ > + + + + + + + + + + + diff --git a/Client/App/include/gui/Gui.h b/Client/App/include/gui/Gui.h index a435beba..f1085b38 100644 --- a/Client/App/include/gui/Gui.h +++ b/Client/App/include/gui/Gui.h @@ -1,4 +1,5 @@ #pragma once +#include "RbxGraphics/Adorn.h" #include "v8tree/Instance.h" #include "gui/GuiEvent.h" #include "gui/Layout.h" diff --git a/Client/App/include/reflection/property.h b/Client/App/include/reflection/property.h index 2660483f..43506b42 100644 --- a/Client/App/include/reflection/property.h +++ b/Client/App/include/reflection/property.h @@ -138,8 +138,14 @@ namespace RBX TypedPropertyDescriptor(ClassDescriptor&, const Type&, const char*, const char*, std::auto_ptr, 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; diff --git a/Client/App/include/security/SecurityContext.h b/Client/App/include/security/SecurityContext.h new file mode 100644 index 00000000..c1637cc1 --- /dev/null +++ b/Client/App/include/security/SecurityContext.h @@ -0,0 +1,79 @@ +#include +#include + +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(); + static __declspec(noinline) bool isInRole(Identities identity, Permissions permission); + private: + static boost::thread_specific_ptr& ptr() + { + static boost::thread_specific_ptr 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); + } + }; + } +} \ No newline at end of file diff --git a/Client/App/include/v8datamodel/ICameraOwner.h b/Client/App/include/v8datamodel/ICameraOwner.h index e3163fcc..dcc2c939 100644 --- a/Client/App/include/v8datamodel/ICameraOwner.h +++ b/Client/App/include/v8datamodel/ICameraOwner.h @@ -1,13 +1,13 @@ #pragma once #include #include +#include "v8datamodel/Camera.h" #include "util/Extents.h" namespace RBX { class Primitive; class PartInstance; - class Camera; class ICameraOwner { private: diff --git a/Client/App/include/v8tree/Service.h b/Client/App/include/v8tree/Service.h index 5e42b67d..5d9dcf09 100644 --- a/Client/App/include/v8tree/Service.h +++ b/Client/App/include/v8tree/Service.h @@ -87,6 +87,9 @@ namespace RBX public: template Class* find() const; + + template + static Class* find(const Instance* context); template Class* create() const; diff --git a/Client/App/security/SecurityContext.cpp b/Client/App/security/SecurityContext.cpp new file mode 100644 index 00000000..7674d0db --- /dev/null +++ b/Client/App/security/SecurityContext.cpp @@ -0,0 +1,28 @@ +#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; + } + } + } +} \ No newline at end of file diff --git a/Client/App/v8datamodel/PartInstance.cpp b/Client/App/v8datamodel/PartInstance.cpp index 7c8ddcdc..428cc1bd 100644 --- a/Client/App/v8datamodel/PartInstance.cpp +++ b/Client/App/v8datamodel/PartInstance.cpp @@ -4,13 +4,13 @@ namespace RBX { - static const Reflection::PropDescriptor prop_PositionUi("Position", "Data", &PartInstance::getTranslationUi, NULL, Reflection::PropertyDescriptor::LEGACY); - static const Reflection::PropDescriptor prop_Velocity("Velocity", "Data", &PartInstance::getLinearVelocity, NULL, Reflection::PropertyDescriptor::LEGACY); - static const Reflection::PropDescriptor prop_SizeUi("Size", category_Part, &PartInstance::getPartSizeUi, NULL, Reflection::PropertyDescriptor::LEGACY); - static const Reflection::PropDescriptor prop_Dragging("DraggingV1", "Behavior", &PartInstance::getDragging, NULL, Reflection::PropertyDescriptor::LEGACY); - static const Reflection::PropDescriptor prop_formFactor("FormFactor", category_Part, &PartInstance::getFormFactor, NULL, Reflection::PropertyDescriptor::LEGACY); - static const Reflection::PropDescriptor prop_Friction("Friction", category_Part, &PartInstance::getFriction, NULL, Reflection::PropertyDescriptor::LEGACY); - static const Reflection::PropDescriptor prop_Elasticity("Elasticity", category_Part, &PartInstance::getElasticity, NULL, Reflection::PropertyDescriptor::LEGACY); + static const Reflection::PropDescriptor prop_PositionUi("Position", "Data", &PartInstance::getTranslationUi, &PartInstance::setTranslationUi, Reflection::PropertyDescriptor::UI); + static const Reflection::PropDescriptor prop_Velocity("Velocity", "Data", &PartInstance::getLinearVelocity, &PartInstance::setLinearVelocity, Reflection::PropertyDescriptor::STANDARD); + static const Reflection::PropDescriptor prop_SizeUi("Size", category_Part, &PartInstance::getPartSizeUi, &PartInstance::setPartSizeUi, Reflection::PropertyDescriptor::UI); + static const Reflection::PropDescriptor prop_Dragging("DraggingV1", "Behavior", &PartInstance::getDragging, &PartInstance::setDragging, Reflection::PropertyDescriptor::STREAMING); + static const Reflection::PropDescriptor prop_formFactor("FormFactor", category_Part, &PartInstance::getFormFactor, &PartInstance::setFormFactorXml, Reflection::PropertyDescriptor::STREAMING); + static const Reflection::PropDescriptor prop_Friction("Friction", category_Part, &PartInstance::getFriction, &PartInstance::setFriction, Reflection::PropertyDescriptor::STANDARD); + static const Reflection::PropDescriptor prop_Elasticity("Elasticity", category_Part, &PartInstance::getElasticity, &PartInstance::setElasticity, Reflection::PropertyDescriptor::STANDARD); namespace Reflection { diff --git a/Client/Network/Network.vcproj b/Client/Network/Network.vcproj index 1482bfb9..f7c93d45 100644 --- a/Client/Network/Network.vcproj +++ b/Client/Network/Network.vcproj @@ -222,6 +222,14 @@ RelativePath=".\IdManager.cpp" > + + + + diff --git a/Client/Network/Player.cpp b/Client/Network/Player.cpp new file mode 100644 index 00000000..058b63b3 --- /dev/null +++ b/Client/Network/Player.cpp @@ -0,0 +1,90 @@ +#include "Player.h" + +namespace RBX +{ + namespace Network + { + Reflection::PropDescriptor prop_teamColor("TeamColor", "Team", &Player::getTeamColor, &Player::setTeamColor, Reflection::PropertyDescriptor::STANDARD); + Reflection::PropDescriptor prop_neutral("Neutral", "Team", &Player::getNeutral, &Player::setNeutral, Reflection::PropertyDescriptor::STANDARD); + Reflection::PropDescriptor prop_characterAppearance("CharacterAppearance", "Data", &Player::getCharacterAppearance, &Player::setCharacterAppearance, Reflection::PropertyDescriptor::STANDARD); + + Backpack* Player::getPlayerBackpack() const + { + Backpack* backpack = findFirstChildOfType(); + + 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(this); + RBXASSERT(workspace != NULL); + + if (!character.get()) + { + 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); + } + } + } +} \ No newline at end of file diff --git a/Client/Network/Players.cpp b/Client/Network/Players.cpp new file mode 100644 index 00000000..a72c93a0 --- /dev/null +++ b/Client/Network/Players.cpp @@ -0,0 +1,28 @@ +#include "Players.h" + +namespace RBX +{ + namespace Network + { + bool Players::clientIsPresent(const Instance* context, bool testInDatamodel) + { + return Client::clientIsPresent(context, testInDatamodel); + } + + bool Players::askAddChild(const Instance* instance) const + { + return fastDynamicCast(instance) != NULL; + } + + void Players::setConnection(RakPeerInterface* peer) + { + if (this->peer) + this->peer->DetachPlugin(plugin.get()); + + this->peer = peer; + + if (peer) + peer->AttachPlugin(plugin.get()); + } + } +} \ No newline at end of file diff --git a/Client/Network/include/Network/Player.h b/Client/Network/include/Network/Player.h index 8c3cdee0..af7e3507 100644 --- a/Client/Network/include/Network/Player.h +++ b/Client/Network/include/Network/Player.h @@ -1,13 +1,15 @@ #pragma once +#include "Players.h" +#include "security/SecurityContext.h" +#include "humanoid/Humanoid.h" #include "v8tree/Instance.h" +#include "v8tree/Service.h" #include "v8datamodel/BrickColor.h" +#include "v8datamodel/Backpack.h" +#include "v8datamodel/Workspace.h" namespace RBX { - class ServiceProvider; - class ModelInstance; - class Backpack; - namespace Network { struct CharacterAdded @@ -65,19 +67,37 @@ namespace RBX virtual ~Player(); public: virtual XmlElement* write(); - virtual void setName(const std::string&); - ModelInstance* getCharacter() const; + virtual void setName(const std::string& value); + ModelInstance* getCharacter() const + { + return character.get(); + } void setCharacter(ModelInstance*); - BrickColor getTeamColor() const; - void setTeamColor(BrickColor); - bool getNeutral() const; - void setNeutral(bool); - std::string getCharacterAppearance() const; - void setCharacterAppearance(const std::string&); + BrickColor getTeamColor() const + { + return teamColor; + } + void setTeamColor(BrickColor value); + bool getNeutral() const + { + return neutral; + } + void setNeutral(bool value); + std::string getCharacterAppearance() const + { + return characterAppearance; + } + void setCharacterAppearance(const std::string& value); bool getUnder13() const; bool getSuperSafeChat() const; - void setUnder13(bool); - void setSuperSafeChat(bool); + void setUnder13(bool value) + { + prop_Under13.setValue(this, value); + } + void setSuperSafeChat(bool value) + { + prop_SuperSafeChat.setValue(this, value); + } int getUserID() const; void rebuildBackpack(); Backpack* getPlayerBackpack() const; diff --git a/Client/Network/include/Network/Players.h b/Client/Network/include/Network/Players.h index 599bdfbe..35dc2d99 100644 --- a/Client/Network/include/Network/Players.h +++ b/Client/Network/include/Network/Players.h @@ -1,18 +1,33 @@ #pragma once -#include "Network/Player.h" -#include "Network/SuperSafeChanged.h" +#include "Player.h" +#include "SuperSafeChanged.h" +#include "v8tree/Service.h" +#include "v8datamodel/ModelInstance.h" +#include "Client.h" #include #include class RakPeerInterface; -class Packet; +struct Packet; -namespace RBX +template +class PluginInterfaceAdapter : public PluginInterface { - class ModelInstance; +private: + Class* c; +protected: + PluginInterfaceAdapter(Class*); +public: + virtual PluginReceiveResult OnReceive(RakPeerInterface* peer, Packet* packet); +}; +namespace RBX +{ namespace Network { + class Player; + struct CharacterAdded; + struct ChatMessage { public: @@ -101,7 +116,10 @@ namespace RBX public Listener { private: - class Plugin; + class Plugin : public PluginInterfaceAdapter + { + Plugin(Players*); + }; private: boost::scoped_ptr abuseReporter; @@ -125,12 +143,24 @@ namespace RBX public: bool superSafeOn() const; boost::shared_ptr createLocalPlayer(int); - Player* getLocalPlayer() const; + Player* getLocalPlayer() const + { + return localPlayer.get(); + } int getNumPlayers() const; - int numPlayers() const; - int getMaxPlayers() const; + int numPlayers() const + { + return (int)players->size(); + } + int getMaxPlayers() const + { + return maxPlayers; + } void setMaxPlayers(int); - boost::shared_ptr>> getPlayers(); + boost::shared_ptr>> getPlayers() + { + return players.read(); + } void chat(std::string); void reportAbuse(boost::shared_ptr, std::string); void reportAbuse(Player*, std::string); @@ -139,11 +169,11 @@ namespace RBX bool canReportAbuse() const; void setAbuseReportUrl(std::string); bool OnReceive(RakPeerInterface*, Packet*); - void setConnection(RakPeerInterface*); + void setConnection(RakPeerInterface* peer); boost::shared_ptr playerFromCharacter(boost::shared_ptr); boost::shared_ptr getPlayerByID(int); protected: - virtual bool askAddChild(const Instance*) const; + virtual bool askAddChild(const Instance* instance) const; virtual void onChildAdded(Instance*); virtual void onChildRemoving(Instance*); private: @@ -155,7 +185,7 @@ namespace RBX static Player* getPlayerFromCharacter(Instance*); static ModelInstance* findLocalCharacter(const Instance*); static Player* findLocalPlayer(const Instance*); - static bool clientIsPresent(const Instance*, bool); + static bool clientIsPresent(const Instance* context, bool testInDatamodel); static bool serverIsPresent(const Instance*, bool); static bool frontendProcessing(const Instance*, bool); static bool backendProcessing(const Instance*, bool); From d342d7084b91d7182c9a55c84ca28d9b26ced843 Mon Sep 17 00:00:00 2001 From: luasoft10 Date: Mon, 5 Jan 2026 22:45:27 +0200 Subject: [PATCH 02/15] what the dog doin --- Client/App/security/SecurityContext.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Client/App/security/SecurityContext.cpp b/Client/App/security/SecurityContext.cpp index 7674d0db..a3434b82 100644 --- a/Client/App/security/SecurityContext.cpp +++ b/Client/App/security/SecurityContext.cpp @@ -4,7 +4,6 @@ namespace RBX { namespace Security { - bool Context::isInRole(Identities identity, Permissions permission) { switch(identity) From a5e52316ac65f2951cd8988cd9f12aa0a9cd2500 Mon Sep 17 00:00:00 2001 From: luasoft10 Date: Mon, 5 Jan 2026 22:46:05 +0200 Subject: [PATCH 03/15] whitespace police --- Client/App/security/SecurityContext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/App/security/SecurityContext.cpp b/Client/App/security/SecurityContext.cpp index a3434b82..5af3181f 100644 --- a/Client/App/security/SecurityContext.cpp +++ b/Client/App/security/SecurityContext.cpp @@ -6,7 +6,7 @@ namespace RBX { bool Context::isInRole(Identities identity, Permissions permission) { - switch(identity) + switch (identity) { case Anonymous: case GameScript: From 3788ed0e02d011062a92455b46a2213fbcfe865d Mon Sep 17 00:00:00 2001 From: luasoft10 Date: Mon, 5 Jan 2026 22:47:15 +0200 Subject: [PATCH 04/15] newlines --- Client/App/include/security/SecurityContext.h | 2 +- Client/App/security/SecurityContext.cpp | 2 +- Client/Network/Player.cpp | 2 +- Client/Network/Players.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Client/App/include/security/SecurityContext.h b/Client/App/include/security/SecurityContext.h index c1637cc1..66d41f40 100644 --- a/Client/App/include/security/SecurityContext.h +++ b/Client/App/include/security/SecurityContext.h @@ -76,4 +76,4 @@ namespace RBX } }; } -} \ No newline at end of file +} diff --git a/Client/App/security/SecurityContext.cpp b/Client/App/security/SecurityContext.cpp index 5af3181f..1f94dff8 100644 --- a/Client/App/security/SecurityContext.cpp +++ b/Client/App/security/SecurityContext.cpp @@ -24,4 +24,4 @@ namespace RBX } } } -} \ No newline at end of file +} diff --git a/Client/Network/Player.cpp b/Client/Network/Player.cpp index 058b63b3..9f15fc75 100644 --- a/Client/Network/Player.cpp +++ b/Client/Network/Player.cpp @@ -87,4 +87,4 @@ namespace RBX } } } -} \ No newline at end of file +} diff --git a/Client/Network/Players.cpp b/Client/Network/Players.cpp index a72c93a0..b8611ba4 100644 --- a/Client/Network/Players.cpp +++ b/Client/Network/Players.cpp @@ -25,4 +25,4 @@ namespace RBX peer->AttachPlugin(plugin.get()); } } -} \ No newline at end of file +} From 671d1232dc53bf2a4141820bd12f79fc1863af82 Mon Sep 17 00:00:00 2001 From: luasoft10 Date: Mon, 5 Jan 2026 23:29:19 +0200 Subject: [PATCH 05/15] oops --- Client/App/App.vcproj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Client/App/App.vcproj b/Client/App/App.vcproj index 76b2be1a..8ebb5d76 100644 --- a/Client/App/App.vcproj +++ b/Client/App/App.vcproj @@ -1309,14 +1309,6 @@ - - - From c95c76e14490808e6ba06662a7bacf4fa0f5001e Mon Sep 17 00:00:00 2001 From: luasoft10 Date: Thu, 8 Jan 2026 16:26:28 +0200 Subject: [PATCH 06/15] a few more functions --- Client/App/App.vcproj | 4 ++ Client/App/include/v8datamodel/TimerService.h | 26 +++++++++++ Client/Network/Player.cpp | 46 +++++++++++++++++++ Client/Network/Players.cpp | 12 +++++ Client/Network/include/Network/Player.h | 5 +- Client/Network/include/Network/Players.h | 2 +- 6 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 Client/App/include/v8datamodel/TimerService.h diff --git a/Client/App/App.vcproj b/Client/App/App.vcproj index 8ebb5d76..d26710ab 100644 --- a/Client/App/App.vcproj +++ b/Client/App/App.vcproj @@ -865,6 +865,10 @@ RelativePath=".\include\v8datamodel\Teams.h" > + + diff --git a/Client/App/include/v8datamodel/TimerService.h b/Client/App/include/v8datamodel/TimerService.h new file mode 100644 index 00000000..3c2689b4 --- /dev/null +++ b/Client/App/include/v8datamodel/TimerService.h @@ -0,0 +1,26 @@ +#include "util/RunStateOwner.h" + +namespace RBX +{ + extern const char* sTimerService; + + class TimerService : public DescribedCreatable, public Service, public Listener + { + class Item + { + public: + G3D::RealTime time; + boost::function0 func; + }; + + private: + boost::shared_ptr runService; + std::list items; + public: + TimerService(); + void delay(boost::function0, double); + protected: + virtual void onServiceProvider(const ServiceProvider*, const ServiceProvider*); + virtual void onEvent(const RunService*, Heartbeat); + }; +} diff --git a/Client/Network/Player.cpp b/Client/Network/Player.cpp index 9f15fc75..d992cfb9 100644 --- a/Client/Network/Player.cpp +++ b/Client/Network/Player.cpp @@ -1,4 +1,5 @@ #include "Player.h" +#include "v8datamodel/TimerService.h" namespace RBX { @@ -8,6 +9,8 @@ namespace RBX Reflection::PropDescriptor prop_neutral("Neutral", "Team", &Player::getNeutral, &Player::setNeutral, Reflection::PropertyDescriptor::STANDARD); Reflection::PropDescriptor prop_characterAppearance("CharacterAppearance", "Data", &Player::getCharacterAppearance, &Player::setCharacterAppearance, Reflection::PropertyDescriptor::STANDARD); + Reflection::SignalDesc event_Idled("Idled", "time"); + Backpack* Player::getPlayerBackpack() const { Backpack* backpack = findFirstChildOfType(); @@ -86,5 +89,48 @@ namespace RBX 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(this); + if (players && players->getLocalPlayer() && Players::clientIsPresent(this, true)) + { + event_Idled.fire(this, idleTime); + } + } + } + + TimerService* tService = ServiceProvider::create(this); + + if (tService) + tService->delay(boost::bind(&Player::doPeriodicIdleCheck, shared_from(this)), 30.0); + } + } } } diff --git a/Client/Network/Players.cpp b/Client/Network/Players.cpp index b8611ba4..015beb51 100644 --- a/Client/Network/Players.cpp +++ b/Client/Network/Players.cpp @@ -24,5 +24,17 @@ namespace RBX if (peer) peer->AttachPlugin(plugin.get()); } + + Player* Players::findLocalPlayer(const Instance* context) + { + Players* players = ServiceProvider::find(context); + return players ? players->getLocalPlayer() : NULL; + } + + ModelInstance* Players::findLocalCharacter(const Instance* context) + { + Player* player = Players::findLocalPlayer(context); + return player ? player->getCharacter() : NULL; + } } } diff --git a/Client/Network/include/Network/Player.h b/Client/Network/include/Network/Player.h index af7e3507..7a557e91 100644 --- a/Client/Network/include/Network/Player.h +++ b/Client/Network/include/Network/Player.h @@ -1,4 +1,5 @@ #pragma once +#include #include "Players.h" #include "security/SecurityContext.h" #include "humanoid/Humanoid.h" @@ -48,7 +49,7 @@ namespace RBX bool under13; bool superSafeChat; int userId; - double lastActivityTime; + G3D::RealTime lastActivityTime; public: static Reflection::BoundProp prop_userId; @@ -58,7 +59,7 @@ namespace RBX private: virtual bool askAddChild(const Instance*) const; - virtual void onServiceProvider(const ServiceProvider*, const ServiceProvider*); + virtual void onServiceProvider(const ServiceProvider* oldProvider, const ServiceProvider* newProvider); void onCharacterChangedFrontend(); void registerLocalPlayerNotIdle(); public: diff --git a/Client/Network/include/Network/Players.h b/Client/Network/include/Network/Players.h index 35dc2d99..be32ab4e 100644 --- a/Client/Network/include/Network/Players.h +++ b/Client/Network/include/Network/Players.h @@ -184,7 +184,7 @@ namespace RBX public: static Player* getPlayerFromCharacter(Instance*); static ModelInstance* findLocalCharacter(const Instance*); - static Player* findLocalPlayer(const Instance*); + static Player* findLocalPlayer(const Instance* context); static bool clientIsPresent(const Instance* context, bool testInDatamodel); static bool serverIsPresent(const Instance*, bool); static bool frontendProcessing(const Instance*, bool); From 94726d097155076d6ed71f6559a0a7010ea5272c Mon Sep 17 00:00:00 2001 From: luasoft10 Date: Thu, 8 Jan 2026 19:53:13 +0200 Subject: [PATCH 07/15] a few more --- Client/Network/Players.cpp | 27 ++++++++++++++++++++++++ Client/Network/include/Network/Players.h | 6 +++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Client/Network/Players.cpp b/Client/Network/Players.cpp index 015beb51..4a35997a 100644 --- a/Client/Network/Players.cpp +++ b/Client/Network/Players.cpp @@ -36,5 +36,32 @@ namespace RBX Player* player = Players::findLocalPlayer(context); return player ? player->getCharacter() : NULL; } + + void Players::setAbuseReportUrl(std::string value) + { + if (value.empty()) + abuseReporter.reset(NULL); + else + abuseReporter.reset(new AbuseReporter(value)); + } + + void Players::reportAbuse(boost::shared_ptr player, std::string comment) + { + reportAbuse(fastDynamicCast(player.get()), comment); + } + + Player* Players::getPlayerFromCharacter(Instance* character) + { + Players* players = ServiceProvider::find(character); + if (players) + { + boost::shared_ptr found = players->playerFromCharacter(shared_from(character)); + return static_cast(found.get()); + } + else + { + return NULL; + } + } } } diff --git a/Client/Network/include/Network/Players.h b/Client/Network/include/Network/Players.h index be32ab4e..47672a30 100644 --- a/Client/Network/include/Network/Players.h +++ b/Client/Network/include/Network/Players.h @@ -162,12 +162,12 @@ namespace RBX return players.read(); } void chat(std::string); - void reportAbuse(boost::shared_ptr, std::string); + void reportAbuse(boost::shared_ptr player, std::string comment); void reportAbuse(Player*, std::string); std::list::const_iterator chatHistory_begin(); std::list::const_iterator chatHistory_end(); bool canReportAbuse() const; - void setAbuseReportUrl(std::string); + void setAbuseReportUrl(std::string value); bool OnReceive(RakPeerInterface*, Packet*); void setConnection(RakPeerInterface* peer); boost::shared_ptr playerFromCharacter(boost::shared_ptr); @@ -182,7 +182,7 @@ namespace RBX //Players& operator=(const Players&); public: - static Player* getPlayerFromCharacter(Instance*); + static Player* getPlayerFromCharacter(Instance* character); static ModelInstance* findLocalCharacter(const Instance*); static Player* findLocalPlayer(const Instance* context); static bool clientIsPresent(const Instance* context, bool testInDatamodel); From d9d0374f26c4f95d00e42d28312b5374709887af Mon Sep 17 00:00:00 2001 From: luasoft10 Date: Thu, 8 Jan 2026 23:15:12 +0200 Subject: [PATCH 08/15] chat, frontendProcessing --- Client/Network/Player.cpp | 2 +- Client/Network/Players.cpp | 29 ++++++++++++++++++++++++ Client/Network/include/Network/Player.h | 5 +++- Client/Network/include/Network/Players.h | 7 +++--- 4 files changed, 38 insertions(+), 5 deletions(-) diff --git a/Client/Network/Player.cpp b/Client/Network/Player.cpp index d992cfb9..d4e3def3 100644 --- a/Client/Network/Player.cpp +++ b/Client/Network/Player.cpp @@ -29,7 +29,7 @@ namespace RBX Workspace* workspace = ServiceProvider::find(this); RBXASSERT(workspace != NULL); - if (!character.get()) + if (!character) { workspace->getCamera()->setCameraType(Camera::FIXED_CAMERA); workspace->getCamera()->setDistanceFromTarget(0.0f); diff --git a/Client/Network/Players.cpp b/Client/Network/Players.cpp index 4a35997a..7c06f813 100644 --- a/Client/Network/Players.cpp +++ b/Client/Network/Players.cpp @@ -63,5 +63,34 @@ namespace RBX return NULL; } } + + void Players::chat(std::string message) + { + if (!localPlayer) + throw std::runtime_error("No local Player to chat from"); + + RakNet::BitStream bitStream; + bitStream << 'P'; + + Guid::Data data; + localPlayer->getGuid().extract(data); + + bitStream << data.scope->name; + bitStream << data.index; + bitStream << message; + + peer->Send(&bitStream, MEDIUM_PRIORITY, RELIABLE, 2, UNASSIGNED_SYSTEM_ADDRESS, true); + + ChatMessage event = {message, localPlayer, boost::shared_ptr()}; + Notifier::raise(event); + } + + bool Players::backendProcessing(const Instance* context, bool testInDatamodel) + { + const ServiceProvider* sp = ServiceProvider::findServiceProvider(context); + RBXASSERT(!testInDatamodel || sp); + + return sp && !Client::clientIsPresent(context, testInDatamodel); + } } } diff --git a/Client/Network/include/Network/Player.h b/Client/Network/include/Network/Player.h index 7a557e91..cb713a09 100644 --- a/Client/Network/include/Network/Player.h +++ b/Client/Network/include/Network/Player.h @@ -99,7 +99,10 @@ namespace RBX { prop_SuperSafeChat.setValue(this, value); } - int getUserID() const; + int getUserID() const + { + return userId; + } void rebuildBackpack(); Backpack* getPlayerBackpack() const; void loadCharacter(); diff --git a/Client/Network/include/Network/Players.h b/Client/Network/include/Network/Players.h index 47672a30..7f887ec3 100644 --- a/Client/Network/include/Network/Players.h +++ b/Client/Network/include/Network/Players.h @@ -1,5 +1,6 @@ #pragma once #include "Player.h" +#include "Streaming.h" #include "SuperSafeChanged.h" #include "v8tree/Service.h" #include "v8datamodel/ModelInstance.h" @@ -161,7 +162,7 @@ namespace RBX { return players.read(); } - void chat(std::string); + void chat(std::string message); void reportAbuse(boost::shared_ptr player, std::string comment); void reportAbuse(Player*, std::string); std::list::const_iterator chatHistory_begin(); @@ -183,11 +184,11 @@ namespace RBX public: static Player* getPlayerFromCharacter(Instance* character); - static ModelInstance* findLocalCharacter(const Instance*); + static ModelInstance* findLocalCharacter(const Instance* context); static Player* findLocalPlayer(const Instance* context); static bool clientIsPresent(const Instance* context, bool testInDatamodel); static bool serverIsPresent(const Instance*, bool); - static bool frontendProcessing(const Instance*, bool); + static bool frontendProcessing(const Instance* context, bool testInDatamodel); static bool backendProcessing(const Instance*, bool); }; } From e05fc903de659cbe348ff996405d8ff1f37183a0 Mon Sep 17 00:00:00 2001 From: luasoft10 Date: Fri, 9 Jan 2026 13:54:07 +0200 Subject: [PATCH 09/15] abuse reporting --- Client/Network/Players.cpp | 25 ++++++++++++++++++++++++ Client/Network/include/Network/Players.h | 14 +++---------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Client/Network/Players.cpp b/Client/Network/Players.cpp index 7c06f813..dab65742 100644 --- a/Client/Network/Players.cpp +++ b/Client/Network/Players.cpp @@ -92,5 +92,30 @@ namespace RBX return sp && !Client::clientIsPresent(context, testInDatamodel); } + + void AbuseReport::addMessage(const ChatMessage& cm) + { + int userId = cm.source ? Player::prop_userId.getValue(cm.source.get()) : 0; + AbuseReport::Message m = {userId, cm.message}; + messages.push_back(m); + } + + AbuseReporter::AbuseReporter(std::string abuseUrl) + : _data(new AbuseReporter::data) + { + requestProcessor.reset(new worker_thread(boost::bind(&AbuseReporter::processRequests, _data, abuseUrl), "rbx_abusereporter")); + } + + void AbuseReporter::add(AbuseReport& r, const std::list& chatHistory) + { + std::for_each(chatHistory.begin(), chatHistory.end(), boost::bind(&AbuseReport::addMessage, &r, _1)); + + { + boost::mutex::scoped_lock lock(_data->requestSync); + _data->queue.push(r); + } + + requestProcessor->wake(); + } } } diff --git a/Client/Network/include/Network/Players.h b/Client/Network/include/Network/Players.h index 7f887ec3..1d9c4b97 100644 --- a/Client/Network/include/Network/Players.h +++ b/Client/Network/include/Network/Players.h @@ -46,16 +46,8 @@ namespace RBX public: struct Message { - public: int userID; std::string text; - - public: - //Message(const Message&); - Message(); - ~Message(); - public: - //Message& operator=(const Message&); }; public: @@ -65,7 +57,7 @@ namespace RBX std::list messages; public: - void addMessage(const ChatMessage&); + void addMessage(const ChatMessage& cm); public: //AbuseReport(const AbuseReport&); AbuseReport(); @@ -97,9 +89,9 @@ namespace RBX public: //AbuseReporter(const AbuseReporter&); - AbuseReporter(std::string); + AbuseReporter(std::string abuseUrl); public: - void add(AbuseReport&, const std::list&); + void add(AbuseReport& r, const std::list& chatHistory); public: ~AbuseReporter(); public: From 4d5cec00b10dd20b46d217c9daa7d38e9e680988 Mon Sep 17 00:00:00 2001 From: luasoft10 Date: Sat, 17 Jan 2026 14:54:08 +0200 Subject: [PATCH 10/15] move includes and declarations --- Client/Network/Player.cpp | 12 +++++++++--- Client/Network/Players.cpp | 12 ++++++++++++ Client/Network/include/Network/Player.h | 2 +- Client/Network/include/Network/Players.h | 19 +++---------------- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/Client/Network/Player.cpp b/Client/Network/Player.cpp index d4e3def3..1c307dd1 100644 --- a/Client/Network/Player.cpp +++ b/Client/Network/Player.cpp @@ -1,10 +1,16 @@ #include "Player.h" +#include "Client.h" #include "v8datamodel/TimerService.h" namespace RBX { namespace Network { + class Plugin : public PluginInterfaceAdapter + { + Plugin(Players*); + }; + Reflection::PropDescriptor prop_teamColor("TeamColor", "Team", &Player::getTeamColor, &Player::setTeamColor, Reflection::PropertyDescriptor::STANDARD); Reflection::PropDescriptor prop_neutral("Neutral", "Team", &Player::getNeutral, &Player::setNeutral, Reflection::PropertyDescriptor::STANDARD); Reflection::PropDescriptor prop_characterAppearance("CharacterAppearance", "Data", &Player::getCharacterAppearance, &Player::setCharacterAppearance, Reflection::PropertyDescriptor::STANDARD); @@ -126,10 +132,10 @@ namespace RBX } } - TimerService* tService = ServiceProvider::create(this); + TimerService* timerService = ServiceProvider::create(this); - if (tService) - tService->delay(boost::bind(&Player::doPeriodicIdleCheck, shared_from(this)), 30.0); + if (timerService) + timerService->delay(boost::bind(&Player::doPeriodicIdleCheck, shared_from(this)), 30.0); } } } diff --git a/Client/Network/Players.cpp b/Client/Network/Players.cpp index dab65742..fa4fe313 100644 --- a/Client/Network/Players.cpp +++ b/Client/Network/Players.cpp @@ -1,4 +1,16 @@ #include "Players.h" +#include "Streaming.h" + +template +class PluginInterfaceAdapter : public PluginInterface +{ +private: + Class* c; +protected: + PluginInterfaceAdapter(Class*); +public: + virtual PluginReceiveResult OnReceive(RakPeerInterface* peer, Packet* packet); +}; namespace RBX { diff --git a/Client/Network/include/Network/Player.h b/Client/Network/include/Network/Player.h index cb713a09..3a49c18e 100644 --- a/Client/Network/include/Network/Player.h +++ b/Client/Network/include/Network/Player.h @@ -1,6 +1,6 @@ #pragma once #include -#include "Players.h" +#include "Network/Players.h" #include "security/SecurityContext.h" #include "humanoid/Humanoid.h" #include "v8tree/Instance.h" diff --git a/Client/Network/include/Network/Players.h b/Client/Network/include/Network/Players.h index 1d9c4b97..f0f4c4ec 100644 --- a/Client/Network/include/Network/Players.h +++ b/Client/Network/include/Network/Players.h @@ -1,10 +1,8 @@ #pragma once -#include "Player.h" -#include "Streaming.h" +#include "Network/Player.h" #include "SuperSafeChanged.h" #include "v8tree/Service.h" #include "v8datamodel/ModelInstance.h" -#include "Client.h" #include #include @@ -12,15 +10,7 @@ class RakPeerInterface; struct Packet; template -class PluginInterfaceAdapter : public PluginInterface -{ -private: - Class* c; -protected: - PluginInterfaceAdapter(Class*); -public: - virtual PluginReceiveResult OnReceive(RakPeerInterface* peer, Packet* packet); -}; +class PluginInterfaceAdapter; namespace RBX { @@ -109,10 +99,7 @@ namespace RBX public Listener { private: - class Plugin : public PluginInterfaceAdapter - { - Plugin(Players*); - }; + class Plugin; private: boost::scoped_ptr abuseReporter; From 7310658b68e9b6b77a7baeff14420f0f08f66232 Mon Sep 17 00:00:00 2001 From: luasoft10 Date: Sat, 17 Jan 2026 18:53:50 +0200 Subject: [PATCH 11/15] OOPS --- Client/App/include/v8tree/Service.h | 3 --- Client/Network/Player.cpp | 5 ----- Client/Network/Players.cpp | 6 ++++++ 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Client/App/include/v8tree/Service.h b/Client/App/include/v8tree/Service.h index 8eb612c7..d1f720f1 100644 --- a/Client/App/include/v8tree/Service.h +++ b/Client/App/include/v8tree/Service.h @@ -87,9 +87,6 @@ namespace RBX public: template Class* find() const; - - template - static Class* find(const Instance* context); template Class* create() const; diff --git a/Client/Network/Player.cpp b/Client/Network/Player.cpp index 1c307dd1..9952436c 100644 --- a/Client/Network/Player.cpp +++ b/Client/Network/Player.cpp @@ -6,11 +6,6 @@ namespace RBX { namespace Network { - class Plugin : public PluginInterfaceAdapter - { - Plugin(Players*); - }; - Reflection::PropDescriptor prop_teamColor("TeamColor", "Team", &Player::getTeamColor, &Player::setTeamColor, Reflection::PropertyDescriptor::STANDARD); Reflection::PropDescriptor prop_neutral("Neutral", "Team", &Player::getNeutral, &Player::setNeutral, Reflection::PropertyDescriptor::STANDARD); Reflection::PropDescriptor prop_characterAppearance("CharacterAppearance", "Data", &Player::getCharacterAppearance, &Player::setCharacterAppearance, Reflection::PropertyDescriptor::STANDARD); diff --git a/Client/Network/Players.cpp b/Client/Network/Players.cpp index fa4fe313..847bb415 100644 --- a/Client/Network/Players.cpp +++ b/Client/Network/Players.cpp @@ -1,4 +1,5 @@ #include "Players.h" +#include "Client.h" #include "Streaming.h" template @@ -16,6 +17,11 @@ namespace RBX { namespace Network { + class Players::Plugin : public PluginInterfaceAdapter + { + Plugin(Players*); + }; + bool Players::clientIsPresent(const Instance* context, bool testInDatamodel) { return Client::clientIsPresent(context, testInDatamodel); From 874dce88f8b996c3f15e3172e40c495dd4fb3c80 Mon Sep 17 00:00:00 2001 From: luasoft10 Date: Sat, 17 Jan 2026 19:05:37 +0200 Subject: [PATCH 12/15] consistency --- Client/Network/include/Network/Players.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Client/Network/include/Network/Players.h b/Client/Network/include/Network/Players.h index f0f4c4ec..06cc1973 100644 --- a/Client/Network/include/Network/Players.h +++ b/Client/Network/include/Network/Players.h @@ -1,6 +1,6 @@ #pragma once #include "Network/Player.h" -#include "SuperSafeChanged.h" +#include "Network/SuperSafeChanged.h" #include "v8tree/Service.h" #include "v8datamodel/ModelInstance.h" #include From b5068558b3470c85875223d072993e8d3a04e78d Mon Sep 17 00:00:00 2001 From: luasoft10 Date: Mon, 26 Jan 2026 00:12:06 +0200 Subject: [PATCH 13/15] playerFromCharacter, getPlayerByID --- Client/Network/Players.cpp | 30 ++++++++++++++++++++++++ Client/Network/include/Network/Players.h | 4 ++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Client/Network/Players.cpp b/Client/Network/Players.cpp index 847bb415..829e596b 100644 --- a/Client/Network/Players.cpp +++ b/Client/Network/Players.cpp @@ -111,6 +111,36 @@ namespace RBX return sp && !Client::clientIsPresent(context, testInDatamodel); } + boost::shared_ptr Players::playerFromCharacter(boost::shared_ptr character) + { + boost::shared_ptr>> myPlayers = getPlayers(); + + std::vector>::const_iterator iter = myPlayers->begin(); + std::vector>::const_iterator end = myPlayers->end(); + + for(; iter != end; iter++) + { + if (static_cast(iter->get())->getCharacter() == static_cast(character.get())) + return *iter; + } + + return boost::shared_ptr(); + } + + boost::shared_ptr Players::getPlayerByID(int userID) + { + std::vector>::const_iterator iter = players->begin(); + std::vector>::const_iterator end = players->end(); + + for(; iter != end; iter++) + { + if (static_cast(iter->get())->getUserID() == userID) + return *iter; + } + + return boost::shared_ptr(); + } + void AbuseReport::addMessage(const ChatMessage& cm) { int userId = cm.source ? Player::prop_userId.getValue(cm.source.get()) : 0; diff --git a/Client/Network/include/Network/Players.h b/Client/Network/include/Network/Players.h index 06cc1973..bb8eb557 100644 --- a/Client/Network/include/Network/Players.h +++ b/Client/Network/include/Network/Players.h @@ -150,8 +150,8 @@ namespace RBX void setAbuseReportUrl(std::string value); bool OnReceive(RakPeerInterface*, Packet*); void setConnection(RakPeerInterface* peer); - boost::shared_ptr playerFromCharacter(boost::shared_ptr); - boost::shared_ptr getPlayerByID(int); + boost::shared_ptr playerFromCharacter(boost::shared_ptr character); + boost::shared_ptr getPlayerByID(int userID); protected: virtual bool askAddChild(const Instance* instance) const; virtual void onChildAdded(Instance*); From 4a20f61602e330d5fc363d638256875c12c09832 Mon Sep 17 00:00:00 2001 From: luasoft10 Date: Mon, 26 Jan 2026 15:57:40 +0200 Subject: [PATCH 14/15] oops --- Client/Network/Players.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Client/Network/Players.cpp b/Client/Network/Players.cpp index 829e596b..e14418a9 100644 --- a/Client/Network/Players.cpp +++ b/Client/Network/Players.cpp @@ -118,7 +118,7 @@ namespace RBX std::vector>::const_iterator iter = myPlayers->begin(); std::vector>::const_iterator end = myPlayers->end(); - for(; iter != end; iter++) + for (; iter != end; iter++) { if (static_cast(iter->get())->getCharacter() == static_cast(character.get())) return *iter; @@ -132,7 +132,7 @@ namespace RBX std::vector>::const_iterator iter = players->begin(); std::vector>::const_iterator end = players->end(); - for(; iter != end; iter++) + for (; iter != end; iter++) { if (static_cast(iter->get())->getUserID() == userID) return *iter; From b3c750ca80e22241d128f1e3794b78e9df276746 Mon Sep 17 00:00:00 2001 From: luasoft10 Date: Tue, 3 Feb 2026 19:36:07 +0200 Subject: [PATCH 15/15] Context::current --- Client/App/include/security/SecurityContext.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Client/App/include/security/SecurityContext.h b/Client/App/include/security/SecurityContext.h index 66d41f40..0152e6ab 100644 --- a/Client/App/include/security/SecurityContext.h +++ b/Client/App/include/security/SecurityContext.h @@ -48,7 +48,17 @@ namespace RBX } public: - static Context& current(); + 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); private: static boost::thread_specific_ptr& ptr()