Files
2025-09-18 17:55:52 -04:00

133 lines
3.8 KiB
C++

/* Copyright 2003-2005 ROBLOX Corporation, All Rights Reserved */
#include "stdafx.h"
#include "V8DataModel/PhysicsService.h"
#include "V8DataModel/PartInstance.h"
#include "V8DataModel/Workspace.h"
#include "V8World/World.h"
#include "V8World/Assembly.h"
#include "Network/Players.h"
#include "rbx/Debug.h"
namespace RBX {
const char *const sPhysicsService = "PhysicsService";
PhysicsService::~PhysicsService()
{
RBXASSERT(parts.empty());
RBXASSERT(!assemblyPhysicsOnConnection.connected());
RBXASSERT(!assemblyPhysicsOffConnection.connected());
}
void PhysicsService::onServiceProvider(ServiceProvider* oldProvider, ServiceProvider* newProvider)
{
assemblyPhysicsOnConnection.disconnect();
assemblyPhysicsOffConnection.disconnect();
touchesConnection.disconnect();
playersChangedConnection.disconnect();
Super::onServiceProvider(oldProvider, newProvider);
onServiceProviderHeartbeatInstance(oldProvider, newProvider); // hooks up heartbeat
if (Workspace* w = ServiceProvider::find<Workspace>(newProvider))
{
touchesConnection = w->stepTouch.connect(boost::bind(&PhysicsService::onTouchStep, this, _1));
Network::Players* players = ServiceProvider::find<Network::Players>(this);
playersChangedConnection = players->combinedSignal.connect(boost::bind(&PhysicsService::onPlayersChanged, this, _1, _2));
SendPhysics* sendPhysics = w->getWorld()->getSendPhysics();
if (sendPhysics)
{
assemblyPhysicsOnConnection = sendPhysics->assemblyPhysicsOnSignal.connect(boost::bind(&PhysicsService::onAssemblyPhysicsOn, this, _1));
assemblyPhysicsOffConnection = sendPhysics->assemblyPhysicsOffSignal.connect(boost::bind(&PhysicsService::onAssemblyPhysicsOff, this, _1));
}
}
}
void PhysicsService::onAssemblyPhysicsOn(Primitive* primitive)
{
WriteValidator writeValidator(concurrencyValidator);
RBXASSERT(primitive->getWorld()); // confirm the Part is in Workspace / primitive is in World
PartInstance* part = PartInstance::fromPrimitive(primitive);
RBXASSERT(Assembly::isAssemblyRootPrimitive(part->getPartPrimitive()));
// force update assembly radius so farther usage is not dirty
primitive->getAssembly()->computeMaxRadius();
shared_ptr<PartInstance> sharedPart = shared_from<PartInstance>(part);
assemblyAddingSignal(sharedPart);
RBXASSERT(!part->PhysicsServiceHook::is_linked());
parts.insert(*part);
if (!iAmServer)
{
iAmServer = Workspace::serverIsPresent(this);
}
if (iAmServer)
{
part->addMovementNode(part->getCoordinateFrame(), part->getVelocity(), Time::nowFast());
}
}
void PhysicsService::onAssemblyPhysicsOff(Primitive* primitive)
{
WriteValidator writeValidator(concurrencyValidator);
RBXASSERT(primitive->getWorld()); // confirm the Part is in Workspace / primitive is in World
PartInstance* part = PartInstance::fromPrimitive(primitive);
RBXASSERT(Assembly::isAssemblyRootPrimitive(part->getPartPrimitive()));
RBXASSERT(part->PhysicsServiceHook::is_linked());
parts.remove_element(*part);
assemblyRemovedSignal(shared_from<PartInstance>(part));
}
void PhysicsService::onHeartbeat(const Heartbeat& event)
{
if ((touchesSendList.empty() && !touchesReceiveList.empty()) || touchSentCounter >= touchResetCount)
{
touchesSendList.clear();
touchesSendList.swap(touchesReceiveList);
touchSentCounter = 0;
touchSendListId++;
}
}
void PhysicsService::onTouchStep(const TouchPair& tp)
{
touchesReceiveList.insert(tp);
}
void PhysicsService::getTouches(std::list<TouchPair>& out)
{
out.insert(out.end(), touchesSendList.begin(), touchesSendList.end());
}
void PhysicsService::onTouchesSent()
{
touchSentCounter++;
}
void PhysicsService::onPlayersChanged(Instance::CombinedSignalType type, const ICombinedSignalData* data)
{
if (Network::Players::backendProcessing(this))
{
if (type == Instance::CHILD_ADDED || type == Instance::CHILD_REMOVED)
touchResetCount = Network::Players::getPlayerCount(this);
}
}
} // namespace RBX