为了支持复杂的物理机制,同时也为玩家提供顺滑且响应的体验,Roblox 物理 引擎使用分布式物理系统,在服务器和所有连接的客户端之间分配计算。在这个系统中,引擎将物理模拟的网络所有权分配给客户端或服务器,以分割物理计算的工作。
客户端体验到 更多响应 的物理互动与他们拥有的零件,因为与服务器通信没有延迟。网络所有权还会提高服务器性能,因为物理计算可以分配给单个客户端,允许服务器优先处理其他任务。
基础零件所有权
默认情况下,服务器保留对任何 BasePart 的所有权。此外,服务器 总是 拥有锚定的 BaseParts ,您无法手动更改其所有权。
基于客户端的硬件能力和玩家对未锚定 的距离,引擎自动将该部分的所有权分配给客户端。因此,靠近玩家角色的零件更可能成为玩家所有。
装配所有权
如果物理基础机制没有锚定部件,在机制内的集装体中设置所有权将为机制内的每个集装体设置相同的所有权。
如果你锚定一个孤立的组件,该组件不属于更广泛的机制,其所有权属于服务器,因为服务器总是拥有锚定的 。取消同一装配的锚定后,其之前的所有权状态丢失,并恢复到引擎自动处理状态。
如果你将一个装配安装在更广范围的装配机制中,其所有权转移到服务器,但其他装配的所有权仍然不变。取消同一装配的锚定会恢复其之前设置的所有权。
设置所有权
在涉及复杂物理互动的体验或在需要分配直接控制的情况下,您可以通过服务器端调用将所有权设置为 BasePart:SetNetworkOwner()。
考虑一个车辆,其中包含驾驶员的 VehicleSeat 对象和乘客的 Seat 对象,两者都包含在车辆装配中。使用默认的所有权规则,如果玩家角色坐在 Seat (乘客),然后另一名玩家跳入 VehicleSeat (驾驶),那么 乘客 获得了整车的物理所有权,因为他们先进入了。驾驶员必须等待几个网络周期才能识别输入,车辆的响应性会下降。
以下 Script 修复了这一问题,通过手动分配网络所有权给驱动程序来解决。在它中, VehicleSeat 将其 Occupant 设置为坐在它上的 Humanoid ,因此脚本可以听到座位的 Changed 事件,当玩家坐在座位上时捕获。当驾驶员离开座椅时,车辆的网络所有权将恢复为自动的 BasePart:SetNetworkOwnershipAuto() 。
local Players = game:GetService("Players")
local vehicleSeat = script.Parent
vehicleSeat.Changed:Connect(function(prop)
if prop == "Occupant" then
local humanoid = vehicleSeat.Occupant
if humanoid then
-- 从角色中获取玩家
local player = Players:GetPlayerFromCharacter(humanoid.Parent)
if player then
vehicleSeat:SetNetworkOwner(player)
end
else
-- 当座位未占用时重置所有权
vehicleSeat:SetNetworkOwnershipAuto()
end
end
end)
视觉化拥有权
为了帮助网络所有权调试,Studio 在游戏测试时可以渲染对象周围的彩色轮廓。
边框颜色 | 描述 | |
---|---|---|
(绿色) | 你的客户拥有零件,正在模拟它。 | |
(红色) | 部分位于你的客户正在模拟的“缓冲区”中,但仍然属于另一家公司。您的客户可能在此后获得所有权,也可能拒绝。 | |
(白色/灰色) | 服务器或其他客户端通过自动网络拥有或从明确分配中拥有零件。 |
要启用网络所有权视觉化:
单击3D视图右上角的 可视化选项 按钮。
在下拉菜单中,切换到 网络所有者 。
安全担心
Roblox无法在客户拥有BasePart时验证物理计算。客户可以利用这一点并向服务器发送错误数据,例如传送 BasePart ,使其穿墙或飞行。
此外,BasePart.Touched事件与网络所有权相关,意味着客户可以在其拥有的Touched网络上发射BasePart事件,即使服务器没有看到它触碰任何东西。例如,客户端可以通过发射脚本注入事件对地图上的另一名玩家造成剑交易伤害,因此重要的是检查客户端发射的这类事件的有效性。
请参阅安全策略和欺诈防御,了解 Roblox 体验的详细安全策略和欺诈防御策略。