I am trying to script an anti-gravity system where all players and parts in a room receive zero gravity. I’ve been able to set the players’ workspace gravity to 0 on their client and this causes the parts around the player to act weightless BUT, if a player with gravity on (client side) walks near the parts, the parts receive gravity again. I’ve tried to set the NetworkOwner of these parts to the server but this causes the parts to act strange when other players collide with them. Setting the NetworkOwnership to a single client who’s gravity is off (client sided) works but, the parts still act strange when other players interact with them and I think the ownership resets if the chosen player leaves.
Here is my question. Is there a way to EXCLUDE certain players’ ownership from the engine’s default method of handling physics when players are near? For example, PartA will switch Network Ownership from server to Player1 when Player1 walks by. Then ownership switchs from Player1 to Player2 when Player2 walks by. Is it possible to prevent the Network Ownership from being assigned to Player2?
I’ve considered using BodyForces to counteract gravity but I would not prefer this method because if a limp is destroyed then the character or model will be forced upwards.
In my case, I would need the Network Ownership to be excluded from certain players and the server (server’s workspace gravity is on). Any ideas would be appreciated, Thanks! : )
Sounds like you’re having a case of automatic network ownership assignment. I’m pretty sure you can override this behaviour by just setting the network owner to the nearest client/a client.
Not sure. I kind of just went off of what I could discern from this.
It looks like you would need to assign network ownership using a script if you want to exclude some players from receiving network ownership.
You could do this by drawing magnitudes on each part (I use the convenient Player:DistanceFromCharacter method here), and seeing if it is inside anyone’s simulation radius that is not on a blacklist (or whitelist). I do not know if parts switch network ownership once they leave the host player’s simulation radius, or if they just change based on which player is nearest to the part, but I will be using the former here, with support for the latter:
local PhysicsParts = {
-- [Part] = Player/true/nil
}
for _, part in pairs(workspace:GetDescendants()) do
if part:IsA("Part") and not part.Anchored and not part:IsGrounded() then
-- part:SetNetworkOwner()
table.insert(PhysicsParts, part, true)
end
end
-- wrapper function for anchoring and
-- unanchoring, use this to account for setting
-- parts as anchored in the table
-- you might want to connect this to an event if
-- you are letting other scripts set parts as
-- anchored
function setAnchored(part, bool)
part.Anchored = bool
if bool then
table.remove(PhysicsParts, part)
else
table.insert(PhysicsParts, part, true)
end
end
-- you would need to come up with your own
-- method to figure out which players to exclude
local playerIgnoreList = {
-- [Player] = true/nil
}
function CheckServerOwner(part)
local closest = math.huge
local newOwner
for _, plr in pairs(Players:GetPlayers()) do
local distance = plr:DistanceFromCharacter(part.Position)
if
distance ~= 0 and
not playerIgnoreList[plr] and
distance <= math.min(closest, plr.SimulationRadius)
then
closest = distance
newOwner = plr
end
end
part:SetNetworkOwner(newOwner)
PhysicsParts[part] = newOwner or true
end
function CheckPlayerOwner(part, player)
if player:DistanceFromCharacter(part.Position) > player.SimulationRadius then
CheckServerOwner(part)
end
end
-- simulation radii can get really big, so you
-- don't have to check toooo often...
-- and assuming it's on a host player basis:
while wait(0.5) do
for part, player in pairs(PhysicsParts) do
if player ~= true then
CheckPlayerOwner(part, player)
else
CheckServerOwner(part)
end
end
end
If you want it to be closest player basis, just use CheckServerOwner on every part.
If you want to take it a step further, you could take the avg of simulation radii for all players and factor that into the loop frequency. I suggest you tweak the loop frequency nonetheless, since this is the main part of the code that is dependent on the speed of your parts/players, of which I don’t know.
A better solution would be to make these objects float on the server so that any client can simulate the parts correctly.
You can make a part weightless by adding a VectorForce or BodyForce with a force of (0, mass*workspace.Gravity, 0) to the part. You can add just one of these to a group of connected parts if you sum the mass of all of the connected parts.
Edit:
Either add forces to each individual part, or use DescendantAdded and DescendantRemoving to detect when parts are added/removed to the model to recalculate the mass.
Using SetNetworkOwner will prevent any automatic handling of that/those instances. Not sure why you’d want to have different gravity between server and client but as long as you use it, you have full control. If you set it to the server (nil argument) the server will keep the control. If you assign it a player the client will keep the control, if this player leaves I guess you’d need to assign it a new player, but I’m not sure why you’d want that setup in the first place.
@goldenstein64@Corecii@gullet
Thanks for the different solutions! Considering all the solutions, I think I will try Corecii’s solution with bodyForces. Using DescendantAdded/DescendantRemoving would be a good idea because my game is always adding/removing parts. This would save me from needing to deal with Network ownership too. I wish there was a “Weightless” property in Parts.