I neither check Angular velocity once not use function to check value change.
Client:
local Vehicle = {}
Vehicle.__index = Vehicle
function Vehicle:Initialize(Enabled, SentModule)
self.Enabled = false
self.CurrentSeat = nil
self.BindedKeys = {}
self.AllowedBinds = {}
self.ActiveModule = SentModule
return self
end
function Vehicle:ChangeVehicle(Object)
if not UserInputService.KeyboardEnabled then
return false
end
if Object == nil then
self:UnbindActions()
self:DisconnectFocusEvents()
return false
else
print(self.ActiveModule)
local FoundKeybinds
local Parts = Object:GetChildren()
for a = 1, #Parts, 1 do
local Special = Parts[a]
if Special:IsA("Model") and Special.Name ~= "Seat" then -- Checking, if smth is Motor, Piston or etc.
local Properties = Special.Properties
if Special.Name == "SteeringWheel" or Special.Name == "Lever" or Special.Name == "Button" then
--This 3 things give you ability to bind keys.
...
else
--otherwise, we will add keybinds motors requested to dicitonary.
...
end
end
end
for Key, Specials in pairs(self.BindedKeys) do
local PossibleInputType = self.AllowedBinds[Key]
if PossibleInputType then
local BestInputType = PossibleInputType
local FunctionToBind = function(actionName, inputState, inputObject)
if inputState == Enum.UserInputState.Begin then
local Pending = {}
for i = 1, #Specials, 1 do
local Object = Specials[i]
if PrefferedInputTypes[Object.Name] == "Hold" and string.match(BestInputType, "Hold") then
table.insert(Pending, Object)
elseif PrefferedInputTypes[Object.Name] == "Click" and string.match(BestInputType, "Click") then
table.insert(Pending, Object)
elseif PrefferedInputTypes[Object.Name] == "Hold" then
table.insert(Pending, Object)
end
end
local Success = Remotes:WaitForChild("VehicleEventTwoWay"):InvokeServer("ActivateSpeciality", Pending, true)
--Asking server, can we activate "Pending" motors?
if Success then
for i = 1, #Pending, 1 do
local Object = Pending[i]
if PrefferedInputTypes[Object.Name] == "Hold" and string.match(BestInputType, "Hold") then
local Mover = SpecialsConstraints[Object.Name]
if Mover == "HingeConstraint" then
local KeyDirection = if Object.Properties:GetAttribute("KeybindClockwise") == Key then 1 else -1
--Bc there's only 2 possible inputs, so if 1 is clockwise, second WILL be anticlockwise.
local Motor = Object.Constraints[Mover]
if Object.Name == "Motor" then
local Speed = Object.Properties:GetAttribute("Speed")
Motor.AngularVelocity += Speed * KeyDirection
elseif string.match(Object.Name, "Servo") then
Motor.TargetAngle = KeyDirection == 1 and Motor.UpperAngle or Motor.LowerAngle
end
end
elseif PrefferedInputTypes[Object.Name] == "Click" and string.match(BestInputType, "Click") then
print(Object.Name .. " is activated")
local Mover = SpecialsConstraints[Object.Name]
if Mover == "Spotlight" then
local Motor = Object.Constraints[Mover]
Motor.Enabled = not Motor.Enabled
end
elseif PrefferedInputTypes[Object.Name] == "Hold" then
print(Object.Name .. " is activated but badly")
local Mover = SpecialsConstraints[Object.Name]
if Mover == "HingeConstraint" then
local KeyDirection = if Object.Properties:GetAttribute("KeybindClockwise") == Key then 1 else -1
--Bc there's only 2 possible inputs, so if 1 is clockwise, second WILL be anticlockwise.
local Motor = Object.Constraints[Mover]
if Object.Name == "Motor" then
local Speed = Object.Properties:GetAttribute("Speed")
if Motor.AngularVelocity == Speed * KeyDirection then
Motor.AngularVelocity = 0
else
Motor.AngularVelocity = Speed * KeyDirection
end
elseif string.match(Object.Name, "Servo") then
if Motor.TargetAngle == (KeyDirection == 1 and Motor.UpperAngle or Motor.LowerAngle) then
Motor.TargetAngle = 0
else
Motor.TargetAngle = KeyDirection == 1 and Motor.UpperAngle or Motor.LowerAngle
end
end
end
end
end
end
elseif inputState == Enum.UserInputState.End and string.match(BestInputType, "Hold") then
--print("Keycode " .. Key .. " is end")
local Pending = {}
for i = 1, #Specials, 1 do
local Object = Specials[i]
if PrefferedInputTypes[Object.Name] == "Hold" then
local Mover = SpecialsConstraints[Object.Name]
if Mover == "HingeConstraint" then
local Motor = Object.Constraints[Mover]
table.insert(Pending, Object)
if Object.Name == "Motor" then
Motor.AngularVelocity = 0
elseif Object.Name == "Servo" then
Motor.TargetAngle = Motor.CurrentAngle
elseif Object.Name == "ReturningServo" then
Motor.TargetAngle = 0
end
end
end
end
Remotes:WaitForChild("VehicleEventOneWay"):FireServer("ActivateSpeciality", Pending, false)
--bc we need to toggle off motors, we don't need to ask server, can we do this, and only send signal that we want do such things.
end
return Enum.ContextActionResult.Pass
end
self.ActiveModule:ConnectNewAction("VehicleKeycode" .. Key, FunctionToBind, Enum.KeyCode[Key])
end
end
end
return true
end
return Vehicle--:Initialize()
Server:
local RS = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local Remotes = RS:WaitForChild("Remotes")
local VehicleEvent = Remotes:WaitForChild("VehicleEventOneWay")
local VehicleFunction = Remotes:WaitForChild("VehicleEventTwoWay")
local VehiclesOnTrack = {}
local SpecialsForTrack = {"Motor", "Servo", "ReturningServo", "Headlight"}
local SpecialsConstraints = {
Motor = "HingeConstraint",
Servo = "HingeConstraint",
ReturningServo = "HingeConstraint",
Headlight = "Spotlight",
Jet = "VectorForce",
Piston = "RodConstraint",
}
local VehiclePowerUsageFunction = nil
local function ChangeNetworkOwner(Player, Part)
Part:SetNetworkOwner(Player)
return true
end
local function SitPlayer(Player, Seat)
if Seat.Parent.Name ~= "Seat" then
Player:Kick("You can't sit on NON-SEATS. Toggle off your hacks, dude.")
return false
end
if Seat.Parent.Properties:GetAttribute("CurrentPlayer") == nil or Seat.Parent.Properties:GetAttribute("CurrentPlayer") == "" and Seat.Parent.Parent.Name == "Vehicle" then
local Weld = Instance.new("Weld")
Weld.Part0 = Seat
Weld.Part1 = Player.Character.HumanoidRootPart
Weld.C0 = CFrame.new(0, 1, 0)
Weld.Parent = Player.Character.HumanoidRootPart
Seat.Parent.Properties:SetAttribute("CurrentPlayer", Player.Name)
local NetworkOwner = Seat:GetNetworkOwner()
if NetworkOwner == nil or NetworkOwner == Player.Name then
if NetworkOwner == nil then
ChangeNetworkOwner(Player, Seat)
end
local Vehicle = Seat.Parent.Parent
VehiclesOnTrack[Vehicle] = {}
local Objects = Vehicle:GetChildren()
for i = 1, #Objects, 1 do
local Object = Objects[i]
if Object:IsA("Model") and table.find(SpecialsForTrack, Object.Name) then
VehiclesOnTrack[Vehicle][Object] = false
end
end
end
end
return true
end
local function ActivateSpecials(Player, Objects, Active)
local Vehicle = Objects[1].Parent
local Players = Vehicle:GetChildren()
local Success = false
for i = 1, #Players, 1 do
if Players[i].Name == "Seat" and Players[i].Properties:GetAttribute("CurrentPlayer") == Player.Name then
Success = true
break
end
end
if Success then
if Active == true then
local PreEnergyUse = Vehicle.Properties:GetAttribute("CurrentEnergyUsage")
warn(#Objects)
for a = 1, #Objects, 1 do
local Object = Objects[a]
local EnergyUsage = Object.Properties:GetAttribute("EnergyUsage")
if not VehiclesOnTrack[Vehicle] then
Player:Kick("How you driving this vehicle?")
end
--print(VehiclesOnTrack[Vehicle][Object])
if VehiclesOnTrack[Vehicle][Object] == false then
PreEnergyUse += EnergyUsage
--print("Energy usage increased by " .. tostring(EnergyUsage) .. " by " .. Object.Name)
end
end
--print("Total energy usage: " .. tostring(PreEnergyUse))
local CurrentEnergy = 0
local Battaries = Vehicle:GetChildren()
for i = 1, #Battaries, 1 do
if Battaries[i].Name == "Battary" then
CurrentEnergy += Battaries[i].Properties:GetAttribute("CurrentEnergy")
end
end
if CurrentEnergy >= PreEnergyUse then
for a = 1, #Objects, 1 do
local Object = Objects[a]
VehiclesOnTrack[Vehicle][Object] = true
--print(Object.Name .. " is activated")
end
Vehicle.Properties:SetAttribute("CurrentEnergyUsage", PreEnergyUse)
if VehiclePowerUsageFunction == nil then
local CurrentTime = 0
VehiclePowerUsageFunction = RunService.Heartbeat:Connect(function(Delta)
CurrentTime += Delta
if CurrentTime >= 1 then
local Multiplier = math.floor(CurrentTime / 1)
CurrentTime = CurrentTime % 1
for Vehicle, Specials in pairs(VehiclesOnTrack) do
local Parts = Vehicle:GetChildren()
local Battaries = {}
local CurrentEnergy = 0
local MaxEnergy = 0
for i = 1, #Parts, 1 do
if Parts[i].Name == "Battary" then
table.insert(Battaries, Parts[i])
CurrentEnergy += Parts[i].Properties:GetAttribute("CurrentEnergy")
MaxEnergy += Parts[i].Properties:GetAttribute("MaxEnergy")
end
end
if CurrentEnergy >= Vehicle.Properties:GetAttribute("CurrentEnergyUsage") * Multiplier then
CurrentEnergy -= Vehicle.Properties:GetAttribute("CurrentEnergyUsage") * Multiplier
for i = 1, #Battaries, 1 do
local BattaryWeight = Battaries[i].Properties:GetAttribute("MaxEnergy") / MaxEnergy
local BattaryEnergy = math.floor(CurrentEnergy * BattaryWeight)
Battaries[i].Properties:SetAttribute("CurrentEnergy", BattaryEnergy)
CurrentEnergy -= BattaryEnergy
MaxEnergy -= Battaries[i].Properties:GetAttribute("MaxEnergy")
end
for Special, Active in pairs(Specials) do
if Active == false then
local Mover = SpecialsConstraints[Special.Name]
if Mover == "HingeConstraint" then
local Motor = Special.Constraints[Mover]
if Special.Name == "Motor" then
Motor.AngularVelocity = 0.001
Motor.AngularVelocity = 0
elseif Special.Name == "Servo" then
Motor.TargetAngle = Motor.CurrentAngle
elseif Special.Name == "ReturningServo" then
Motor.TargetAngle = 0
end
end
end
end
else
for i = 1, #Battaries, 1 do
Battaries[i].Properties:SetAttribute("CurrentEnergy", 0)
end
for Special, Active in pairs(Specials) do
if Active == true then
VehiclesOnTrack[Vehicle][Special] = false
local Mover = SpecialsConstraints[Special.Name]
if Mover == "HingeConstraint" then
local Motor = Special.Constraints[Mover]
if Special.Name == "Motor" then
Motor.AngularVelocity = 0.001
Motor.AngularVelocity = 0
elseif Special.Name == "Servo" then
Motor.TargetAngle = Motor.CurrentAngle
elseif Special.Name == "ReturningServo" then
Motor.TargetAngle = 0
end
end
end
end
end
end
end
end)
end
return true
else
return false
end
else
local PreEnergyUse = Vehicle.Properties:GetAttribute("CurrentEnergyUsage")
for a = 1, #Objects, 1 do
local Object = Objects[a]
local EnergyUsage = Object.Properties:GetAttribute("EnergyUsage")
if VehiclesOnTrack[Vehicle] then
if VehiclesOnTrack[Vehicle][Object] == true then
VehiclesOnTrack[Vehicle][Object] = false
PreEnergyUse -= EnergyUsage
end
end
end
if PreEnergyUse < 0 then
Player:Kick("If you are cheater: you can't drive vehicles at no-cost. If you are innocent: Report this bug to developer.")
end
Vehicle.Properties:SetAttribute("CurrentEnergyUsage", PreEnergyUse)
return true
end
end
return false
end
VehicleEvent.OnServerEvent:Connect(function(Player, Action, ...)
if Action == "Sit" then
SitPlayer(Player, ...)
elseif Action == "ActivateSpeciality" then
ActivateSpecials(Player, ...)
end
end)
VehicleFunction.OnServerInvoke = function(Player, Action, ...)
local Success = false
if Action == "Sit" then
Success = SitPlayer(Player, ...)
elseif Action == "ActivateSpeciality" then
Success = ActivateSpecials(Player, ...)
end
return Success
end