Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --// StateManager
- local Knit = require(game:GetService("ReplicatedStorage").Packages.Knit)
- local StateManager = Knit.CreateController {
- Name = "StateManager",
- }
- local ReplicatedStorage = game:GetService("ReplicatedStorage")
- local RunService = game:GetService("RunService")
- local Player = game:GetService("Players").LocalPlayer
- local Events = ReplicatedStorage:WaitForChild("Events")
- local State = ReplicatedStorage:WaitForChild("State")
- local StateClass = require(State:WaitForChild("StateClass"))
- local PromptMachine = Events:WaitForChild("PromptMachine")
- local ChangeState = Events:WaitForChild("ChangeState")
- local RequestState = Events:WaitForChild("RequestState")
- local LastChange = nil
- local AlreadyCounting = false
- local StatesConfigured = false
- local StateMachines = {
- HumanoidStateMachine = {},
- CombatStateMachine = {}
- }
- local IDLE_REVERT_TIME = 5
- local ITERATION_INTERVAL = 1
- local function SetToDefault(Player)
- for _,StateMachine in StateMachines do
- StateMachine:ChangeState("Idle")
- end
- end
- local function ConfigureStates(Character)
- local Humanoid = Character:WaitForChild("Humanoid")
- local HumanoidStateMachine = StateManager:FetchStateMachine("Humanoid", Player)
- local CombatStateMachine = StateManager:FetchStateMachine("Combat", Player)
- local ConnectionMade = false
- RunService.RenderStepped:Connect(function()
- local IsWalking = Humanoid.MoveDirection.Magnitude > 0
- local IsStationary = Humanoid.MoveDirection.Magnitude == 0
- local IsMoving = HumanoidStateMachine:FetchState().Movement
- if (IsWalking and not IsMoving) or IsStationary and IsMoving then
- HumanoidStateMachine:ChangeState("Walking")
- end
- end)
- Humanoid.StateChanged:Connect(function(_, NewState)
- if NewState ~= Enum.HumanoidStateType.Running then
- HumanoidStateMachine:ChangeState(NewState.Name)
- end
- end)
- --RequestState.OnCli
- SetToDefault(Player)
- StatesConfigured = true
- end
- function StateManager.KnitInit()
- for StateMachine,_ in StateMachines do
- StateMachines[StateMachine] = StateClass.new(StateMachine)
- StateMachines[StateMachine]:InitStates()
- end
- if Player.Character then ConfigureStates(Player.Character) end
- Player.CharacterAdded:Connect(ConfigureStates)
- PromptMachine.OnClientEvent:Connect(function(Machine, State)
- local Machine = StateMachines[Machine.."StateMachine"]
- Machine:ChangeState(State)
- end)
- repeat task.wait() until StatesConfigured
- setmetatable(StateManager, {
- __index = function(_, State)
- return function()
- for _,StateMachine in StateMachines do
- if StateMachine.States[State] then StateMachine:ChangeState(State) end
- end
- end
- end,
- })
- end
- function StateManager:FetchStateMachine(StateMachine)
- return StateMachines[StateMachine.."StateMachine"]
- end
- function StateManager:FetchAllMachines()
- return StateMachines
- end
- return StateManager
- -- //
- -- // StateClass
- local StateClass = {}
- StateClass.__index = StateClass
- local ReplicatedStorage = game:GetService("ReplicatedStorage")
- local RunService = game:GetService("RunService")
- local Player = game:GetService("Players").LocalPlayer
- local Knit = require(ReplicatedStorage.Packages.Knit)
- local State = ReplicatedStorage:WaitForChild("State")
- local AlreadyCounting = false
- local LastChange = nil
- local ReturnStates = {
- "Ready",
- "Idle"
- }
- local COUNTDOWN_INTERVAL = .5
- local IDLE_REVERT_TIME = 5
- local function IsRequiredState(OldState, NewState, OtherState)
- if not NewState.RequiredStates then return true end
- local RequiredStates = 0
- local FoundStates = 0
- for _ in NewState.RequiredStates do
- RequiredStates += 1
- end
- for _,States in NewState.RequiredStates do
- for _,State in ipairs(States) do
- if State == OldState.Name or State == OtherState.Name then
- FoundStates += 1
- end
- end
- end
- if FoundStates >= RequiredStates then
- return true
- end
- return false
- end
- local function ValidNewState(OldState, NewState, States)
- if OldState.Name == NewState.Name
- and not table.find(ReturnStates, NewState.Name) then
- return
- end
- for StateName,_ in States do
- if StateName == NewState.Name then
- return true
- end
- end
- return false
- end
- local function RevertToReturn(NewState)
- if NewState.Movement then
- local Humanoid = Player.Character.Humanoid
- repeat task.wait() until Humanoid.MoveDirection.Magnitude == 0
- elseif not NewState.Movement and not NewState.Holdable then
- while true do
- task.wait(COUNTDOWN_INTERVAL)
- local DeltaTime = os.clock() - LastChange
- if DeltaTime >= IDLE_REVERT_TIME then
- break
- end
- end
- end
- end
- function StateClass.new(StateMachine)
- local self = setmetatable({}, StateClass)
- self.Name = StateMachine
- self.States = {}
- for _,State in ipairs(State[StateMachine]:GetChildren()) do
- self.States[State.Name] = require(State)
- end
- self.ReturnState = "Idle"
- self.State = self.States.Idle
- return self
- end
- function StateClass:InitStates()
- for _,State in self.States do
- if State.Init then
- State.Init()
- end
- end
- end
- function StateClass:ChangeState(State)
- local StateManager = Knit.GetController("StateManager")
- local OtherMachineName = self.Name == "HumanoidStateMachine" and "Combat"
- or self.Name == "CombatStateMachine" and "Humanoid"
- or error("Couldn't grab state machine: "..self.Name)
- local OtherMachine = StateManager:FetchStateMachine(OtherMachineName)
- local OldState = self.State
- local NewState = self.States[State] or error("State enum not found:"..State)
- local OtherState = OtherMachine:FetchState()
- local SwappingReturnState = OldState.Name == NewState.Name
- and table.find(ReturnStates, NewState.Name)
- if not ValidNewState(OldState, NewState, self.States) then return end
- if not IsRequiredState(OldState, NewState, OtherState)
- and not SwappingReturnState then
- return
- end
- if SwappingReturnState then
- if NewState.Name == "Ready" then
- NewState = self.States.Idle
- self:ChangeReturnState("Idle")
- else
- return
- end
- end
- if OldState.Exit then
- OldState.Exit(NewState)
- end
- if NewState.Enter then
- NewState.Enter(OldState)
- end
- self.State = NewState
- print(self.Name.." State Change:",self.State.Name)
- if table.find(ReturnStates, NewState.Name) then
- return
- end
- -- // This return statement means that we are returning to a resting state,
- -- // Such as "Ready" or "Idle", and therefore don't need to RevertToReturn()
- LastChange = os.clock()
- if AlreadyCounting or NewState.Holdable then return end
- AlreadyCounting = true
- RevertToReturn(NewState)
- -- // This function yields the code until it is time to revert,
- -- // To the return state (where applicable)
- AlreadyCounting = false
- end
- function StateClass:ChangeReturnState(State)
- if table.find(ReturnStates, State) then
- self.ReturnState = State
- end
- end
- function StateClass:FetchState(State)
- return self.State
- end
- return StateClass
- -- //
- -- // None State
- return {
- Name = script.Name,
- Holdable = false,
- -- // Holdable means that Enter() will occour on InputBegan,
- -- // And Exit() will occour on InputEnded.
- RequiredStates = {
- Humanoid = {},
- Combat = {},
- },
- -- // RequiredStates is a list which contains possible states,
- -- // In order to enter the state this list resides in, the
- -- // State corresponding to the sub-lists StateMachine (i.e, Humanoid or Combat),
- -- // Must have already been within that list, ex; If Humanoid contains "Attacking",
- -- // Then in order to enter the state this list resides in, I must be "Attacking".
- -- // This is a matter of OR, not AND. Therefore you must be in one of, not all of.
- -- // In the event states exist for both sub-lists, each state machine must be in
- -- // A state from their corresponding list.
- -- // If this list is nil or does not exist, you can enter the state from any state.
- Init = function()
- end,
- -- // Occurs when confiruing states.
- Enter = function()
- end,
- --// Occurs when entering this state.
- Exit = function()
- end,
- -- Occurs when leaving this state.
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement