From 65e4b7eef225d5d817317b1a2b6f7022c7ce5bd9 Mon Sep 17 00:00:00 2001 From: unittensor Date: Sun, 21 Apr 2024 15:04:12 -0400 Subject: [PATCH] Big client character refactor --- src/client/Character/Actions.lua | 8 +- src/client/Character/Camera/Bobbing.lua | 33 +++--- src/client/Character/Camera/init.lua | 6 +- src/client/Character/Humanoid.lua | 8 +- src/client/Character/HumanoidRootPart.lua | 2 + src/client/Character/SpineKinematics.lua | 15 +-- src/client/Character/init.lua | 132 ++++++++++++---------- src/shared/Algebra.lua | 7 +- src/shared/Client/KeyBinds.lua | 51 ++++++--- 9 files changed, 152 insertions(+), 110 deletions(-) diff --git a/src/client/Character/Actions.lua b/src/client/Character/Actions.lua index 0c310e8..78980d5 100644 --- a/src/client/Character/Actions.lua +++ b/src/client/Character/Actions.lua @@ -41,6 +41,8 @@ type Constructor_Return_Props = { ActionsTCP: TCP } +export type ActionsConstructor = ClassConstructor + local Actions = {} :: Impl_Constructor Actions.__index = Actions @@ -116,7 +118,7 @@ function Actions:DisableCrouch() }, Easing) end -function Actions:EnableFlashlight(FlashlightKey: Enum.KeyCode) +function Actions:EnableFlashlight(FlashlightKey) Actions.FlashlightEnabled = true task.spawn(function() @@ -133,12 +135,12 @@ function Actions:EnableFlashlight(FlashlightKey: Enum.KeyCode) self.ActionsTCP:FireServer(FlashlightKey) end -function Actions:DisableFlashlight(FlashlightKey: Enum.KeyCode) +function Actions:DisableFlashlight(FlashlightKey) self.ActionsTCP:FireServer(FlashlightKey) Actions.FlashlightEnabled = false end -function Actions:ToggleFlashlight(FlashlightKey: Enum.KeyCode) +function Actions:ToggleFlashlight(FlashlightKey) if Actions.FlashlightEnabled then self:DisableFlashlight(FlashlightKey) else diff --git a/src/client/Character/Camera/Bobbing.lua b/src/client/Character/Camera/Bobbing.lua index bde3b6b..c824069 100644 --- a/src/client/Character/Camera/Bobbing.lua +++ b/src/client/Character/Camera/Bobbing.lua @@ -40,11 +40,16 @@ type Constructor_Return_Props = { Humanoid: Humanoid } -export type BobbingConstructor = Impl_Constructor +export type BobbingConstructor = ClassConstructor local Bobbing = {} :: Impl_Constructor Bobbing.__index = Bobbing +local UIS = game:GetService("UserInputService") +local RS = game:GetService("ReplicatedStorage") + +local Algebra = require(RS:WaitForChild("Algebra")) + Bobbing.TurnAlpha = 0.050 Bobbing.LeanMultiplier = 1.7 Bobbing.SwayMultiplier = 1.5 @@ -56,8 +61,6 @@ Bobbing.ForceStop = false local Animations = {} :: AnimationsMap -local UIS = game:GetService("UserInputService") - local CN = CFrame.new local ANG = CFrame.Angles local CameraLean = CN() @@ -66,8 +69,8 @@ local Animation = CN() function Bobbing.constructor(HumanoidRootPart: HumanoidRootPart, CurrentCamera: CurrentCamera, Humanoid: Humanoid) return setmetatable({ HumanoidRootPart = HumanoidRootPart, - CurrentCamera = CurrentCamera, - Humanoid = Humanoid + CurrentCamera = CurrentCamera, + Humanoid = Humanoid }, Bobbing) end @@ -100,10 +103,6 @@ function Animations.Falling() return ANG(0,0,0) end -local function maxmin(min: number, mid: number, max: number): number - return math.max(min, math.min(mid, max)) -end - local function Camera_YArc(Camera: Camera): EulerValue --stop Euler gimbal lock when you're looking directly up or down local EulerY,_,_ = Camera.CFrame.Rotation:ToEulerAnglesYXZ() return math.abs(math.deg(EulerY)) @@ -113,20 +112,20 @@ local function CameraAnimation(self: ClassConstructor, dt: deltatime) --crying Bobbing.Tick += 1 - local Root: BasePart = self.HumanoidRootPart - local Velocity: Vector3 = Root:GetVelocityAtPosition(Root.Position) - local RootMagnitude: number = Velocity.Magnitude + local Root: BasePart = self.HumanoidRootPart + local Velocity: Vector3 = Root:GetVelocityAtPosition(Root.Position) + local RootMagnitude: number = Velocity.Magnitude --go go boolean algebra - local MaxMinY: boolean = Camera_YArc(self.CurrentCamera)>Bobbing.MaxGimbalLockY --TODO: instead, make this an equation so it will just subtract from the existing animation radians - local AnimationType: string = Bobbing.ForceStop and "Stop" or RootMagnitude>1 and "Walk" or (not MaxMinY and "Idle" or "Stop") - local CurrentAnimation: CFrame = Animations[AnimationType](Bobbing.Tick, dt) + local MaxMinY: boolean = Camera_YArc(self.CurrentCamera)>Bobbing.MaxGimbalLockY --TODO: instead, make this an equation so it will just subtract from the existing animation radians + local AnimationType: string = Bobbing.ForceStop and "Stop" or RootMagnitude>1 and "Walk" or (not MaxMinY and "Idle" or "Stop") + local CurrentAnimation: CFrame = Animations[AnimationType](Bobbing.Tick, dt) --"Lerp" so the transitions between walking and idling are smoothed instead of instant return Animation:Lerp(CurrentAnimation, Bobbing.AnimationAlpha) end -function Bobbing:Frame(dt: number) +function Bobbing:Frame(dt) local Camera = self.CurrentCamera local Humanoid = self.Humanoid @@ -139,7 +138,7 @@ function Bobbing:Frame(dt: number) --Jump?! --local LeanDegree_Pitch = -CameraCF.UpVector:Dot(Humanoid.MoveDirection)*Bobbing.LeanMultiplier - local LeanMult_Roll = maxmin(-Bobbing.SwayMultiplier, LeanDegree_Roll-MouseDelta.X, Bobbing.SwayMultiplier) + local LeanMult_Roll = Algebra.maxmin(-Bobbing.SwayMultiplier, LeanDegree_Roll-MouseDelta.X, Bobbing.SwayMultiplier) CameraLean = CameraLean:Lerp(ANG(0, 0, math.rad(LeanMult_Roll)), Bobbing.TurnAlpha) Camera.CFrame *= Animation*CameraLean diff --git a/src/client/Character/Camera/init.lua b/src/client/Character/Camera/init.lua index 26ac8dc..4a9080d 100644 --- a/src/client/Character/Camera/init.lua +++ b/src/client/Character/Camera/init.lua @@ -4,10 +4,8 @@ local Bobbing = require(script:WaitForChild("Bobbing")) -type FakeCamera = BasePart type CurrentCamera = Camera type HumanoidRootPart = BasePart -type Module = any type ClassConstructor = typeof(setmetatable({} :: Constructor_Return_Props, {} :: Impl_Constructor)) type Impl_Constructor = { @@ -26,13 +24,15 @@ type Constructor_Return_Props = { BobbingCamera: Bobbing.BobbingConstructor } +export type CameraConstructor = ClassConstructor + local Camera = {} :: Impl_Constructor Camera.__index = Camera local RS = game:GetService("RunService") function Camera.constructor(CurrentCamera: CurrentCamera, HumanoidRootPart: HumanoidRootPart, Humanoid: Humanoid) - local self = {} + local self = {} :: Constructor_Return_Props self.CameraFPS = false self.CurrentCamera = CurrentCamera self.HumanoidRootPart = HumanoidRootPart diff --git a/src/client/Character/Humanoid.lua b/src/client/Character/Humanoid.lua index 55ef848..32205ed 100644 --- a/src/client/Character/Humanoid.lua +++ b/src/client/Character/Humanoid.lua @@ -22,20 +22,22 @@ type Constructor_Return_Props = { Humanoid: Humanoid } +export type HumanoidConstructor = ClassConstructor + local HumanoidModule = {} :: Impl_Constructor HumanoidModule.__index = HumanoidModule -function HumanoidModule.constructor(Humanoid: Humanoid) +function HumanoidModule.constructor(Humanoid) return setmetatable({ Humanoid = Humanoid }, HumanoidModule) end -function HumanoidModule:SetWalkSpeed(Speed: WalkSpeed) +function HumanoidModule:SetWalkSpeed(Speed) self.Humanoid.WalkSpeed = Speed or 10 end -function HumanoidModule:SetJumpHeight(Height: JumpHeight) +function HumanoidModule:SetJumpHeight(Height) self.Humanoid.JumpHeight = Height or 7.2 end diff --git a/src/client/Character/HumanoidRootPart.lua b/src/client/Character/HumanoidRootPart.lua index ac0f9ff..d43a015 100644 --- a/src/client/Character/HumanoidRootPart.lua +++ b/src/client/Character/HumanoidRootPart.lua @@ -18,6 +18,8 @@ type Constructor_Return_Props = { HumanoidRootPart: HumanoidRootPart } +export type HumanoidRPSettingsConstructor = ClassConstructor + local HumanoidRPSettings = {} :: Impl_Constructor HumanoidRPSettings.__index = HumanoidRPSettings diff --git a/src/client/Character/SpineKinematics.lua b/src/client/Character/SpineKinematics.lua index 5b876cb..a46563e 100644 --- a/src/client/Character/SpineKinematics.lua +++ b/src/client/Character/SpineKinematics.lua @@ -4,6 +4,7 @@ type UDP = UnreliableRemoteEvent type CurrentCamera = Camera +type CharacterShared = Folder type ClassConstructor = typeof(setmetatable({} :: Constructor_Return_Props, {} :: Impl_Constructor)) type Impl_Constructor = { @@ -14,7 +15,7 @@ type Impl_Constructor = { Disable: (self: ClassConstructor) -> () } & Impl_Static_Props -type Constructor_Fun = (CurrentCamera: CurrentCamera) -> ClassConstructor +type Constructor_Fun = (CharacterShared: CharacterShared, CurrentCamera: CurrentCamera) -> ClassConstructor type Impl_Static_Props = { Running: boolean } @@ -23,6 +24,8 @@ type Constructor_Return_Props = { CurrentCamera: CurrentCamera } +export type SpineConstructor = ClassConstructor + local Spine = {} :: Impl_Constructor Spine.__index = Spine @@ -30,16 +33,14 @@ Spine.Running = false local Storage = game:GetService("ReplicatedStorage") local Players = game:GetService("Players") +local Player = Players.LocalPlayer local Delta = require(Storage:WaitForChild("Delta")) -local Player = Players.LocalPlayer -local CharacterShared = _G.include(script, "CharacterShared") - -function Spine.constructor(CurrentCamera: CurrentCamera) +function Spine.constructor(CharacterShared, CurrentCamera) return setmetatable({ - Remote = CharacterShared:WaitForChild("SpineStream"), - CurrentCamera = CurrentCamera + Remote = CharacterShared:WaitForChild("SpineStream") :: UDP, + CurrentCamera = CurrentCamera :: CurrentCamera }, Spine) end diff --git a/src/client/Character/init.lua b/src/client/Character/init.lua index cdb0fdf..7004487 100644 --- a/src/client/Character/init.lua +++ b/src/client/Character/init.lua @@ -2,62 +2,86 @@ --!native --!strict -type CharacterSharedFolder = Folder -type Character = Model -type TCP = RemoteEvent - -type include = (this: LuaSourceContainer, FunName: string, ...T) -> T - -local CharacterModule = {} -CharacterModule.__index = CharacterModule - local RS = game:GetService("RunService") local Storage = game:GetService("ReplicatedStorage") -local ClientStorage = Storage:WaitForChild("Client") :: Folder +local ClientStorage = Storage:WaitForChild("Client") +local BindModule = require(ClientStorage:WaitForChild("KeyBinds")) -local function client_preprocessor(Character: Character): (include, CharacterSharedFolder) - local preprocessor = {} - local CharacterShared = Character:WaitForChild("shared") :: CharacterSharedFolder +local HumanoidRPSettings = require(script:WaitForChild("HumanoidRootPart")) +local CameraModule = require(script:WaitForChild("Camera")) +local HumanoidModule = require(script:WaitForChild("Humanoid")) +local SpineModule = require(script:WaitForChild("SpineKinematics")) +local ActionsModule = require(script:WaitForChild("Actions")) - function preprocessor.CharacterShared(): CharacterSharedFolder - return CharacterShared - end +type Character = Model +type HumanoidRootPart = BasePart +type TCP = RemoteEvent +type CurrentCamera = Camera - _G.include = function(this: LuaSourceContainer, FunName: string, ...: T) - if this:IsDescendantOf(script) then --getfenv is being removed - local switch = preprocessor[FunName] - return type(switch) == "function" and switch(...) or switch - else - warn(`Preprocessor append failed "{FunName}"`, debug.traceback()) - return nil - end - end +type ClassConstructor = typeof(setmetatable({} :: Constructor_Return_Props, {} :: Impl_Constructor)) +type Impl_Constructor = { + __index: Impl_Constructor, + constructor: Constructor_Fun, + --Class functions + CharacterKeyBinds: (self: ClassConstructor) -> (), + Crosshair: (self: ClassConstructor) -> RBXScriptConnection, + SetWalkSpeed: (self: ClassConstructor) -> (), + SetJumpHeight: (self: ClassConstructor) -> (), + DisableRobloxSounds: (self: ClassConstructor) -> (), + EnableCameraBobbing: (self: ClassConstructor) -> (), + EnableSpineMovement: (self: ClassConstructor) -> () +} & Impl_Static_Props - return _G.include, CharacterShared -end +type Impl_Static_Props = { + KeyBinds: { + Crouch: {Enum.KeyCode}, + Walk: {Enum.KeyCode}, + Flashlight: {Enum.KeyCode} + } +} + +type Constructor_Fun = (Character: Character) -> ClassConstructor +type Constructor_Return_Props = { + ActionsTCP: TCP, + CurrentCamera: CurrentCamera, + HRPSettings: HumanoidRPSettings.HumanoidRPSettingsConstructor, + CameraConsturctor: CameraModule.CameraConstructor, + HumanoidSettings: HumanoidModule.HumanoidConstructor, + SpineMovement: SpineModule.SpineConstructor +} + +local CharacterModule = {} :: Impl_Constructor +CharacterModule.__index = CharacterModule + +CharacterModule.KeyBinds = { + Crouch = { + Enum.KeyCode.RightControl, + Enum.KeyCode.LeftControl + }, + Walk = { + Enum.KeyCode.LeftAlt, + Enum.KeyCode.RightAlt, + Enum.KeyCode.LeftShift, + Enum.KeyCode.RightShift + }, + Flashlight = { + Enum.KeyCode.F + } +} function CharacterModule.constructor(Character) - local _, CharacterShared = client_preprocessor(Character) - - local HumanoidRPSettings = require(script:WaitForChild("HumanoidRootPart")) - local CameraModule = require(script:WaitForChild("Camera")) - local HumanoidModule = require(script:WaitForChild("Humanoid")) - local SpineModule = require(script:WaitForChild("SpineKinematics")) - - local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart") - local Humanoid = Character:WaitForChild("Humanoid") - - local self = {} - self.ActionsTCP = CharacterShared:WaitForChild("Actions") - self.ActionsModule = require(script:WaitForChild("Actions")) - self.BindModule = require(ClientStorage:WaitForChild("KeyBinds")) + local CharacterShared = Character:WaitForChild("shared") :: Folder + local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart") :: HumanoidRootPart + local Humanoid = Character:WaitForChild("Humanoid") :: Humanoid + local self = {} :: Constructor_Return_Props self.CurrentCamera = workspace.CurrentCamera + self.ActionsTCP = CharacterShared:WaitForChild("Actions") :: TCP self.HRPSettings = HumanoidRPSettings.constructor(HumanoidRootPart) self.CameraConsturctor = CameraModule.constructor(self.CurrentCamera, HumanoidRootPart, Humanoid) self.HumanoidSettings = HumanoidModule.constructor(Humanoid) - self.SpineMovement = SpineModule.constructor(self.CurrentCamera) + self.SpineMovement = SpineModule.constructor(CharacterShared, self.CurrentCamera) pcall(table.clear, _G) pcall(table.freeze, _G) @@ -68,37 +92,27 @@ function CharacterModule.constructor(Character) end function CharacterModule:CharacterKeyBinds() - local ClientBindMap = self.BindModule.constructor(false) - local Actions = self.ActionsModule.constructor(self.HumanoidSettings, self.CurrentCamera, self.ActionsTCP) + local ClientBindMap = BindModule.constructor(false) + local Actions = ActionsModule.constructor(self.HumanoidSettings, self.CurrentCamera, self.ActionsTCP) --Crouch - ClientBindMap:AddInputBegan({Enum.KeyCode.RightControl, Enum.KeyCode.LeftControl}, function(_KeyPressed) + ClientBindMap:AddInputBegan(CharacterModule.KeyBinds.Crouch, function(_KeyPressed) Actions:EnableCrouch() end) - ClientBindMap:AddInputEnded({Enum.KeyCode.RightControl, Enum.KeyCode.LeftControl}, function(_KeyPressed) + ClientBindMap:AddInputEnded(CharacterModule.KeyBinds.Crouch, function(_KeyPressed) Actions:DisableCrouch() end) --Walk - ClientBindMap:AddInputBegan({ - Enum.KeyCode.LeftAlt, - Enum.KeyCode.RightAlt, - Enum.KeyCode.LeftShift, - Enum.KeyCode.RightShift - }, function(_KeyPressed) + ClientBindMap:AddInputBegan(CharacterModule.KeyBinds.Walk, function(_KeyPressed) Actions:EnableSneak() end) - ClientBindMap:AddInputEnded({ - Enum.KeyCode.LeftAlt, - Enum.KeyCode.RightAlt, - Enum.KeyCode.LeftShift, - Enum.KeyCode.RightShift - }, function(_KeyPressed) + ClientBindMap:AddInputEnded(CharacterModule.KeyBinds.Walk, function(_KeyPressed) Actions:DisableSneak() end) --Flashlight - ClientBindMap:AddInputBegan({Enum.KeyCode.F}, function(KeyPressed: Enum.KeyCode) + ClientBindMap:AddInputBegan(CharacterModule.KeyBinds.Flashlight, function(KeyPressed: Enum.KeyCode) Actions:ToggleFlashlight(KeyPressed) end) end diff --git a/src/shared/Algebra.lua b/src/shared/Algebra.lua index feb678f..2e2f858 100644 --- a/src/shared/Algebra.lua +++ b/src/shared/Algebra.lua @@ -28,11 +28,16 @@ export type Math = { OutBounce: EaseFunction, InQuad: EaseFunction, RotationMatrix: (X: number, Y: number, Z: number) -> RotationMatrix, - Scalar: (X1: number, Y1: number, X2: number, Y2: number) -> Scalar + Scalar: (X1: number, Y1: number, X2: number, Y2: number) -> Scalar, + maxmin: (min: number, n: number, max: number) -> number } local Math = {} :: Math +function Math.maxmin(min, n, max) + return math.max(min, math.min(n, max)) +end + function Math.RotationMatrix(X: number, Y: number, Z: number): RotationMatrix return { Ixx = math.cos(Z)*math.cos(X)-math.sin(Z)*math.sin(X)*math.sin(Y); diff --git a/src/shared/Client/KeyBinds.lua b/src/shared/Client/KeyBinds.lua index 8d54570..232fd01 100644 --- a/src/shared/Client/KeyBinds.lua +++ b/src/shared/Client/KeyBinds.lua @@ -2,34 +2,51 @@ --!native --!strict ---I couldn't get ContextActionService to work how i wanted it to +--Couldn't get ContextActionService to work how i wanted -local BindLink = {} -BindLink.__index = BindLink +type ClassConstructor = typeof(setmetatable({} :: Constructor_Return_Props, {} :: Impl_Constructor)) +type Impl_Constructor = { + __index: Impl_Constructor, + constructor: Constructor_Fun, + --Class functions + CharacterKeyBinds: (self: ClassConstructor) -> (), + AddInputBegan: (self: ClassConstructor, Keys: {Enum.KeyCode}, Callback: CallbackFunction) -> (), + AddInputEnded: (self: ClassConstructor, Keys: {Enum.KeyCode}, Callback: CallbackFunction) -> (), + KeyHold: (self: ClassConstructor, Key: Enum.KeyCode) -> boolean +} + +type Constructor_Fun = (gameProcessing: boolean) -> ClassConstructor +type Constructor_Return_Props = { + BindMap: KeyBindMap, + InputBegan: InputBegan, + InputEnded: InputEnded +} + +type CallbackFunction = (KeyPressed: Enum.KeyCode) -> () export type KeyBindMap = { [string]: { [Enum.KeyCode]: (KeyPressed: Enum.KeyCode) -> () } } -type BindConstructor = { - BindMap: KeyBindMap, - InputBegan: InputBegan, - InputEnded: InputEnded -} export type InputBegan = RBXScriptConnection export type InputEnded = RBXScriptConnection -type CallbackFunction = (KeyPressed: Enum.KeyCode) -> () + +export type KeyBindsConstructor = ClassConstructor + +local BindLink = {} :: Impl_Constructor +BindLink.__index = BindLink local UIS = game:GetService("UserInputService") function BindLink.constructor(gameProcessing: boolean) --Allow multiple bindings of the same keys, no overwrites - local self = {} :: BindConstructor + local self = {} :: Constructor_Return_Props self.BindMap = { Began = {}, Ended = {} } + --Return these for convenience self.InputBegan = UIS.InputBegan:Connect(function(input, gameProcessedEvent) if gameProcessing and gameProcessedEvent or not gameProcessedEvent then @@ -55,9 +72,9 @@ function BindLink.constructor(gameProcessing: boolean) --Allow multiple bindings return setmetatable(self, BindLink) end -function BindLink:AddInputBegan(Keys: {Enum.KeyCode}, Callback: CallbackFunction) - for i = 1, #Keys do - local Key = Keys[i] +function BindLink:AddInputBegan(Keys, Callback) + for n: number = 1, #Keys do + local Key = Keys[n] if self.BindMap.Began[Key] then warn(`Key >began< "{Key.Name}" is already binded on this KeyBind map`, debug.traceback()) end @@ -65,9 +82,9 @@ function BindLink:AddInputBegan(Keys: {Enum.KeyCode}, Callback: CallbackFunction end end -function BindLink:AddInputEnded(Keys: {Enum.KeyCode}, Callback: CallbackFunction) - for i = 1, #Keys do - local Key = Keys[i] +function BindLink:AddInputEnded(Keys, Callback) + for n: number = 1, #Keys do + local Key = Keys[n] if self.BindMap.Ended[Key] then warn(`Key >ended< "{Key.Name}" is already binded on this KeyBind map`, debug.traceback()) end @@ -75,7 +92,7 @@ function BindLink:AddInputEnded(Keys: {Enum.KeyCode}, Callback: CallbackFunction end end -function BindLink:KeyHold(Key: Enum.KeyCode): boolean +function BindLink:KeyHold(Key) return UIS:IsKeyDown(Key) end