So, I have made chair system - I use WeldConstraint to weld character primary part to part (Not SeatPart, just Part).
Sitting on chair is absolutely ok, but when I try to stand up, depending on time I spent sitting on it, current moon phase, star alignment, math.random() and many other factors I can die. Reason of such death is character being parented to nil. But why?
- Server code for handling chairs:
local RS = game:GetService("ReplicatedStorage")
local SSS = game:GetService("ServerScriptService")
local IsLobby = --check for PlaceId
local Remotes = RS:WaitForChild("Remotes")
local CollectionService = game:GetService("CollectionService")
local Libraries = {
Materials = require(RS:WaitForChild("Libraries"):WaitForChild("Materials")),
ItemCreator = require(RS:WaitForChild("Libraries"):WaitForChild("ItemCreator")),
Types = require(RS:WaitForChild("Libraries"):WaitForChild("TypesLibrary")),
CurrentItems = require(RS:WaitForChild("Libraries"):WaitForChild("CurrentItemsData")),
AntiCheat = require(SSS.PlayerActions.AntiCheat.AntiCheatController),
}
local ModuleMeta = {}
ModuleMeta.__index = ModuleMeta
local ClientAllowedActions = {"Sit", "Free"}
if IsLobby then
--So far no issue on lobby side was noticed.
else
--Initialization of chair
function ModuleMeta.Initialize(Object:Instance, StartInfo)
local self = setmetatable({}, ModuleMeta)
self.Owner = StartInfo.Owner
self.Object = Object
self.Occupants = StartInfo.Occupants or {}
self.ClientAllowed = ClientAllowedActions
self.Connections = {}
local Seats = {}
for _, Object in pairs(self.Object:GetDescendants()) do
if CollectionService:HasTag(Object, "Seat") then
table.insert(Seats, Object)
end
end
return self
end
--handles sitting on chairs.
function ModuleMeta:Sit(Occupant, Seat)
if not Seat:IsDescendantOf(self.Object) then return false, "This seat is not from this chair" end
if self.Occupants[Seat] then return false, "Already occupied" end
for Seat, Person in self.Occupants do
if Person == Occupant then
self:Free(Occupant, Seat)
end
end
if Occupant.Character.Humanoid:GetState() == Enum.HumanoidStateType.Seated then return false, "Already sitting" end
self.Occupants[Seat] = Occupant
local Root = Occupant.Character.HumanoidRootPart
Occupant.Character:PivotTo(Seat.CFrame * CFrame.new(0, 1, 0))
local Weld = Instance.new("WeldConstraint")
Weld.Name = "SeatWeld"
Weld.Part0 = Seat
Weld.Part1 = Root
Weld.Parent = Seat
Remotes.CharacterEvent:FireClient(Occupant, "Sit", {State = true, Object = self.Object, Seat = Seat})
local CurTime = DateTime.now().UnixTimestampMillis/1000
return true
end
--handles standing up from chairs.
function ModuleMeta:Free(Player, Seat)
--print(Player, Seat, self.Object)
if not (self.Occupants[Seat] or Seat:IsDescendantOf(self.Object)) then return false, "This seat is not from this chair" end
if not self.Occupants[Seat] then return false, "Already free" end
if self.Occupants[Seat] ~= Player then return false, "You are not sitting here" end
self.Occupants[Seat] = nil
if Seat:FindFirstChild("SeatWeld") then
Seat.SeatWeld:Destroy()
end
Remotes.CharacterEvent:FireClient(Player, "Sit", {State = false})
local CurTime = DateTime.now().UnixTimestampMillis/1000
--print("Freed!")
return true
end
--this function is called when chair gets destroyed.
function ModuleMeta:Exit()
local function DisconnectAll(Connections)
for _, Connection in pairs(Connections) do
if typeof(Connection) == "table" then
DisconnectAll(Connection)
else
Connection:Disconnect()
end
end
end
for Seat, Occupant in self.Occupants do
print("Freeing ", Occupant, "on seat:", Seat)
self:Free(Occupant, Seat)
end
DisconnectAll(self.Connections)
self = nil
end
end
return ModuleMeta
Client side of chair handling:
local function ActionReact(Action, Data)
if Action == "Ragdoll" then
--handling of ragdolling.
elseif Action == "Sit" then
if self.CurrentCharacter and self.CurrentHumanoid:GetState() ~= Enum.HumanoidStateType.Ragdoll then
--locks all HumanoidStateTypes, and sets it to Seated.
self:ChangeHumanoidState(not Data.State, Enum.HumanoidStateType.Seated)
self.CurrentHumanoid.Sit = Data.State
if Data.State then
self.Seat = {Object = Data.Object, Seat = Data.Seat}
elseif self.Seat then
local Success, Info = Libraries.ObjectController.Action("Chair/Free", self.Seat.Object, Player, self.Seat.Seat)
if Success then
self.Seat = nil
end
end
end
end
end
Remotes.CharacterEvent.OnClientEvent:Connect(ActionReact)
--... a lot of line codes later, unrelated to chairs ...
--self.ActiveModule.IsJumping is true when spacebar is being held, or jump button on mobile.
if self.Seat and self.ActiveModule.IsJumping then
if not IsLobby and self.Seat.Object:GetAttribute("DataId") then
--this line initializes chair on client side, to access it's functions. Used further to invoke server functions only.
Libraries.ObjectController.Action("Chair/Initialize", self.Seat.Object, Libraries.CurrentItems.GetItem(self.Seat.Object:GetAttribute("DataId")))
end
--this line of code invokes server via my module and runs "Free" function of chair, shown above.
local Success, Info = Libraries.ObjectController.Action("Chair/Free", self.Seat.Object, Player, self.Seat.Seat)
if Success then
self:ChangeHumanoidState(true, Enum.HumanoidStateType.Running)
self.Seat = nil
end
end
self.CurrentHumanoid.Jump = self.ActiveModule.IsJumping
I genuinely can’t understand why everyone who tried to sit on chair for longer than 3 seconds has chance to be sent to nil-zone. Maybe, anyone here has clues on what’s going on here?