--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "blind",
    Category = "FunCommands",
    Description = "Blinds a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to blind.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            local PlayerGui = Player:FindFirstChild("PlayerGui")
            if PlayerGui then
                if not PlayerGui:FindFirstChild("NexusAdminBlind") then
                    local NexusAdminBlind = Instance.new("ScreenGui")
                    NexusAdminBlind.Name = "NexusAdminBlind"
                    NexusAdminBlind.Parent = PlayerGui

                    local Frame = Instance.new("Frame")
                    Frame.Size = UDim2.new(3, 0, 3, 0)
                    Frame.Position = UDim2.new(-1, 0, -1, 0)
                    Frame.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
                    Frame.BorderSizePixel = 0
                    Frame.Parent = NexusAdminBlind
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Lighting = game:GetService("Lighting")

local IncludedCommandUtil = require(script.Parent.Parent:WaitForChild("IncludedCommandUtil"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "disco",
    Category = "FunCommands",
    Description = "Toggles disco on and off.",
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        local Util = IncludedCommandUtil.ForContext(CommandContext)
        local Api = Util:GetApi()

        --Toggle Disco on or off.
        Api.CommandData.DiscoActive = not Api.CommandData.DiscoActive
        if Api.CommandData.DiscoActive then
            task.spawn(function()
                Api.CommandData.DiscoOriginalAmbient = Lighting.Ambient
                while Api.CommandData.DiscoActive do
                    Lighting.Ambient = Color3.new(math.random(), math.random(), math.random())
                    wait(0.25)
                end
            end)
        else
            Lighting.Ambient = Api.CommandData.DiscoOriginalAmbient
        end
    end,
}


--Implementation of a command.
--!strict

local InsertService = game:GetService("InsertService")

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "face",
    Category = "FunCommands",
    Description = "Gives the face with the given id to each player.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to change the face.",
        },
        {
            Type = "integer",
            Name = "Id",
            Description = "Face id to use.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, Id: number)
        --Insert the face.
        local Face = nil
        local Model = InsertService:LoadAsset(Id)
        for _, FaceItem in Model:GetChildren() do
            if FaceItem:IsA("Decal") then
                Face = FaceItem
            end
        end

        --Set the face.
        if Face then
            for _, Player in Players do
                local Character = Player.Character
                if Character then
                    local Head = Character:FindFirstChild("Head")
                    if Head then
                        --Get the transparency.
                        local ExistingFace = Head:FindFirstChildOfClass("Decal") :: Decal
                        local Transparency = ExistingFace.Transparency
                        ExistingFace:Destroy()

                        --Add the new face.
                        local NewFace = Face:Clone()
                        NewFace.Transparency = Transparency
                        NewFace.Parent = Head
                    end
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "fire",
    Category = "FunCommands",
    Description = "Adds a fire to a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to give fire to.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        --Add the fire.
        for _, Player in Players do
            if Player.Character then
                local HumanoidRootPart = Player.Character:FindFirstChild("HumanoidRootPart")
                if HumanoidRootPart then
                    local Fire = Instance.new("Fire")
                    Fire.Name = "NexusAdminFire"
                    Fire.Parent = HumanoidRootPart
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local InsertService = game:GetService("InsertService")

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "hat",
    Category = "FunCommands",
    Description = "Gives hats to the given players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to give hats.",
        },
        {
            Type = "integers",
            Name = "Ids",
            Description = "Hats ids to insert.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, Ids: {number})
        --Insert the hats.
        local Hats = {}
        for _,Id in Ids do
            local Model = InsertService:LoadAsset(Id)
            for _, Hat in Model:GetChildren() do
                if Hat:IsA("Hat") or Hat:IsA("Accoutrement") or Hat:IsA("Accessory") then
                    table.insert(Hats, Hat)
                end
            end
        end

        --Give the hats to the players.
        for _,Player in Players do
            if Player.Character then
                for _, Hat in Hats do
                    Hat:Clone().Parent = Player.Character
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "invisible",
    Category = "FunCommands",
    Description = "Makes a set of players invisible.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to make invisible.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                for _, Ins in Player.Character:GetDescendants() do
                    if (Ins:IsA("BasePart") or Ins:IsA("Decal")) and Ins.Transparency <= 1 then
                        (Ins :: BasePart).Transparency = Ins.Transparency + 1.1
                    end
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "light",
    Category = "FunCommands",
    Description = "Adds a light to a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to give light to.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                local HumanoidRootPart = Player.Character:FindFirstChild("HumanoidRootPart")
                if HumanoidRootPart then
                    local Light = Instance.new("PointLight")
                    Light.Name = "NexusAdminLight"
                    Light.Parent = HumanoidRootPart
                end
            end
        end
    end,
}


--[Implementation of a command.
--!strict

local IncludedCommandUtil = require(script.Parent.Parent:WaitForChild("IncludedCommandUtil"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "pause",
    Category = "FunCommands",
    Description = "Pauses the audio.",
    ServerRun = function(CommandContext: Types.CmdrCommandContext)
        local Util = IncludedCommandUtil.ForContext(CommandContext)
        local Api = Util:GetServerApi()

        Api.CommandData.GlobalAudioSound:Pause()
    end,
}


--Implementation of a command.
--!strict

local Workspace = game:GetService("Workspace")
local Players = game:GetService("Players")
local MarketplaceService = game:GetService("MarketplaceService")

local IncludedCommandUtil = require(script.Parent.Parent:WaitForChild("IncludedCommandUtil"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "play",
    Category = "FunCommands",
    Description = "Plays music with the given id.",
    Arguments = {
        {
            Type = "integer",
            Name = "AudioId",
            Description = "Audio id to play.",
        },
    },
    ServerLoad = function(Api: Types.NexusAdminApiServer)
        local GlobalAudio = Instance.new("Sound")
        GlobalAudio.Name = "NexusAdmin_GlobalAudio"
        GlobalAudio.Looped = true
        Api.CommandData.GlobalAudioSound = GlobalAudio
    end,
    ServerRun = function(CommandContext: Types.CmdrCommandContext, AudioId: number)
        local Util = IncludedCommandUtil.ForContext(CommandContext)
        local Api = Util:GetServerApi()

        --Get the audio information.
        local Worked,ProductData = pcall(function()
            return MarketplaceService:GetProductInfo(AudioId)
        end)
        if not Worked or not ProductData then
            Util:SendError(`Error loading audio {AudioId}.`)
            return
        end

        --Display a message for playing the audio.
        if ProductData.AssetTypeId ~= 3 then
            Util:SendError(tostring(`{ProductData.Name}({AudioId}) is not an audio.`))
            return
        end
        for _,Player in Players:GetPlayers() do
            Api.Messages:DisplayHint(Player, Api.Filter:EscapeRichText(`Now playing "{ProductData.Name}" ({AudioId}).`))
        end

        --Play the audio.
        local GlobalAudio = Api.CommandData.GlobalAudioSound
        GlobalAudio:Stop()
        GlobalAudio.SoundId = `rbxassetid://{AudioId}`
        GlobalAudio.Parent = Workspace
        GlobalAudio:Play()
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "removehats",
    Category = "FunCommands",
    Description = "Removes the hats of a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to remove the hats of.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                for _, Hat in Player.Character:GetChildren() do
                    if Hat:IsA("Accoutrement") or Hat:IsA("Accessory") then
                        Hat:Destroy()
                    end
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Workspace = game:GetService("Workspace")

local IncludedCommandUtil = require(script.Parent.Parent:WaitForChild("IncludedCommandUtil"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "resume",
    Category = "FunCommands",
    Description = "Resumes the audio.",
    ServerRun = function(CommandContext: Types.CmdrCommandContext)
        local Util = IncludedCommandUtil.ForContext(CommandContext)
        local Api = Util:GetServerApi()

        Api.CommandData.GlobalAudioSound:Resume()
        Api.CommandData.GlobalAudioSound.Parent = Workspace
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "rocket",
    Category = "FunCommands",
    Description = "Adds a rocket to a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to give a rocket to.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                local HumanoidRootPart = Player.Character:FindFirstChild("HumanoidRootPart") :: Part
                if HumanoidRootPart and not HumanoidRootPart:FindFirstChild("NexusAdminRocket") then
                    local NexusAdminRocket = Instance.new("Part")
                    NexusAdminRocket.Name = "NexusAdminRocket"
                    NexusAdminRocket.Material = Enum.Material.SmoothPlastic
                    NexusAdminRocket.CanCollide = false
                    NexusAdminRocket.Size = Vector3.new(1, 2, 2)
                    NexusAdminRocket.Parent = HumanoidRootPart

                    local Mesh = Instance.new("SpecialMesh")
                    Mesh.MeshType = Enum.MeshType.FileMesh
                    Mesh.MeshId = "rbxassetid://2251534"
                    Mesh.Scale = Vector3.new(0.5, 0.5, 0.5)
                    Mesh.Parent = NexusAdminRocket

                    local Weld = Instance.new("Weld")
                    Weld.Part0 = HumanoidRootPart
                    Weld.Part1 = NexusAdminRocket
                    Weld.C1 = CFrame.new(0, -0.8, 0.4) * CFrame.Angles(-math.pi / 2, 0, 0)
                    Weld.Parent = NexusAdminRocket

                    local Fire = Instance.new("Fire")
                    Fire.Heat = 0
                    Fire.Parent = NexusAdminRocket

                    local BodyVelocity = Instance.new("BodyVelocity")
                    BodyVelocity.MaxForce = Vector3.new(0, math.huge, 0)
                    BodyVelocity.Velocity = Vector3.new(0, 75, 0)
                    BodyVelocity.Parent = NexusAdminRocket
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local SCALE_TYPES = {
    {
        Name = "All",
        Values = {"BodyDepthScale", "BodyHeightScale", "BodyWidthScale", "HeadScale"},
    },
    {
        Name = "Depth",
        Values = {"BodyDepthScale"},
    },
    {
        Name = "Height",
        Values = {"BodyHeightScale"},
    },
    {
        Name = "Width",
        Values = {"BodyWidthScale"},
    },
    {
        Name = "Head",
        Values = {"HeadScale"},
    },
}

local IncludedCommandUtil = require(script.Parent.Parent:WaitForChild("IncludedCommandUtil"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "scale",
    Category = "FunCommands",
    Description = "Scales the given characters by a multiplier. Does not support R6.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to give smoke to.",
        },
        {
            Type = "number",
            Name = "Multiplier",
            Description = "Multiplier to scale by.",
        },
        {
            Type = "characterScaleTypes",
            Name = "Type",
            Description = "Type of value to scale.",
            Optional = true,
        },
    },
    ServerLoad = function(Api: Types.NexusAdminApiServer)
        local ScaleTypes = {}
        for _, ScaleType in SCALE_TYPES do
            table.insert(ScaleTypes, ScaleType.Name)
        end
        Api.Registry:AddEnumType("characterScaleType", ScaleTypes)
    end,
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, Multiplier: number, ScaleTypes: {string}?)
        --Get the scale values.
        local ScaleValueNames = {}
        for _, ScaleTypeName in ScaleTypes or {"All"} :: {string} do
            for _, ScaleType in SCALE_TYPES do
                if ScaleType.Name ~= ScaleTypeName then continue end
                for _, ScaleValueName in ScaleType.Values do
                    ScaleValueNames[ScaleValueName] = true
                end
            end
        end

        --Scale the characters.
        local Util = IncludedCommandUtil.ForContext(CommandContext)
        for _, Player in Players do
            local Character = Player.Character
            if not Character then continue end
            local Humanoid = Character:FindFirstChildOfClass("Humanoid") :: Humanoid
            if not Humanoid then continue end
            if Humanoid.RigType == Enum.HumanoidRigType.R6 then
                Util:SendError(`{Player.Name} can't be scaled because the scale command does not support R6.`)
                continue
            end
            for ValueName, _ in ScaleValueNames do
                local ScaleValue = Humanoid:FindFirstChild(ValueName) :: NumberValue
                if not ScaleValue then continue end
                ScaleValue.Value = Multiplier * ScaleValue.Value
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "smoke",
    Category = "FunCommands",
    Description = "Adds a smoke to a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to give smoke to.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                local HumanoidRootPart = Player.Character:FindFirstChild("HumanoidRootPart")
                if HumanoidRootPart then
                    local Smoke = Instance.new("Smoke")
                    Smoke.Color = Color3.fromRGB(100, 100, 100)
                    Smoke.RiseVelocity = 5
                    Smoke.Opacity = 0.75
                    Smoke.Name = "NexusAdminSmoke"
                    Smoke.Parent = HumanoidRootPart
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "sparkles",
    Category = "FunCommands",
    Description = "Adds a sparkles to a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to sparkles smoke to.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                local HumanoidRootPart = Player.Character:FindFirstChild("HumanoidRootPart")
                if HumanoidRootPart then
                    local Sparkles = Instance.new("Sparkles")
                    Sparkles.Name = "NexusAdminSparkles"
                    Sparkles.Parent = HumanoidRootPart
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "spin",
    Category = "FunCommands",
    Description = "Spins a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to spin.",
        },
        {
            Type = "number",
            Name = "Speed",
            Description = "Speed to spin at.",
            Optional = true,
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, Speed: number)
        Speed = Speed or 1

        for _, Player in Players do
            if Player.Character then
                local HumanoidRootPart = Player.Character:FindFirstChild("HumanoidRootPart")
                if HumanoidRootPart then
                    --Remove the existing spin effect.
                    local ExistingBodyAngularVelocity = HumanoidRootPart:FindFirstChild("NexusAdminSpinEffect")
                    if ExistingBodyAngularVelocity then
                        ExistingBodyAngularVelocity:Destroy()
                    end

                    --Add the new spin effect.
                    local BodyAngularVelocity = Instance.new("BodyAngularVelocity")
                    BodyAngularVelocity.Name = "NexusAdminSpinEffect"
                    BodyAngularVelocity.MaxTorque = Vector3.new(0, math.huge, 0)
                    BodyAngularVelocity.AngularVelocity = Vector3.new(0, 8 * Speed, 0)
                    BodyAngularVelocity.Parent = HumanoidRootPart
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local IncludedCommandUtil = require(script.Parent.Parent:WaitForChild("IncludedCommandUtil"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "stop",
    Category = "FunCommands",
    Description = "Stops the audio.",
    ServerRun = function(CommandContext: Types.CmdrCommandContext)
        local Util = IncludedCommandUtil.ForContext(CommandContext)
        local Api = Util:GetServerApi()

        Api.CommandData.GlobalAudioSound:Stop()
        Api.CommandData.GlobalAudioSound.Parent = nil
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "unblind",
    Category = "FunCommands",
    Description = "Unblinds a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to unblind.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            local PlayerGui = Player:FindFirstChild("PlayerGui")
            if PlayerGui then
                if PlayerGui:FindFirstChild("NexusAdminBlind") then
                    (PlayerGui:FindFirstChild("NexusAdminBlind") :: ScreenGui):Destroy()
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "unfire",
    Category = "FunCommands",
    Description = "Removes all fire from a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to remove fire from.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                local HumanoidRootPart = Player.Character:FindFirstChild("HumanoidRootPart")
                if HumanoidRootPart then
                    for _, Fire in HumanoidRootPart:GetChildren() do
                        if Fire.Name == "NexusAdminFire" then
                            Fire:Destroy()
                        end
                    end
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "unlight",
    Category = "FunCommands",
    Description = "Removes all light from a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to remove light from.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                local HumanoidRootPart = Player.Character:FindFirstChild("HumanoidRootPart")
                if HumanoidRootPart then
                    for _, Light in HumanoidRootPart:GetChildren() do
                        if Light.Name == "NexusAdminLight" then
                            Light:Destroy()
                        end
                    end
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "unrocket",
    Category = "FunCommands",
    Description = "Removes all rockets from a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to remove rockets from.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                local HumanoidRootPart = Player.Character:FindFirstChild("HumanoidRootPart")
                if HumanoidRootPart and HumanoidRootPart:FindFirstChild("NexusAdminRocket") then
                    (HumanoidRootPart:FindFirstChild("NexusAdminRocket") :: BasePart):Destroy()
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "unsmoke",
    Category = "FunCommands",
    Description = "Removes all smoke from a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to remove smoke from.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                local HumanoidRootPart = Player.Character:FindFirstChild("HumanoidRootPart")
                if HumanoidRootPart then
                    for _, Smoke in HumanoidRootPart:GetChildren() do
                        if Smoke.Name == "NexusAdminSmoke" then
                            Smoke:Destroy()
                        end
                    end
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "unsparkles",
    Category = "FunCommands",
    Description = "Removes all sparkles from a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to remove sparkles from.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                local HumanoidRootPart = Player.Character:FindFirstChild("HumanoidRootPart")
                if HumanoidRootPart then
                    for _, Sparkles in HumanoidRootPart:GetChildren() do
                        if Sparkles.Name == "NexusAdminSparkles" then
                            Sparkles:Destroy()
                        end
                    end
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "unspin",
    Category = "FunCommands",
    Description = "Unspins a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to unspin.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                local HumanoidRootPart = Player.Character:FindFirstChild("HumanoidRootPart")
                if HumanoidRootPart then
                    local BodyAngularVelocity = HumanoidRootPart:FindFirstChild("NexusAdminSpinEffect")
                    if BodyAngularVelocity then
                        BodyAngularVelocity:Destroy()
                    end
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local IncludedCommandUtil = require(script.Parent.Parent:WaitForChild("IncludedCommandUtil"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "unvibrate",
    Category = "FunCommands",
    Description = "Unvibrates a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to unvibrate.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        local Util = IncludedCommandUtil.ForContext(CommandContext)
        local Api = Util:GetServerApi()

        --Stop the vibrating.
        for _, Player in Players do
            if Api.CommandData.PlayerVibrations[Player] then
                Api.CommandData.PlayerVibrations[Player]:Destroy()
            end
        end
    end,
}


--Implementation of a command.
--!strict

local IncludedCommandUtil = require(script.Parent.Parent:WaitForChild("IncludedCommandUtil"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "vibrate",
    Category = "FunCommands",
    Description = "Vibrates a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to vibrate.",
        },
        {
            Type = "number",
            Name = "Intensity",
            Description = "Intensity of the vibration.",
            Optional = true,
        },
    },
    ServerLoad = function(Api: Types.NexusAdminApiServer)
        Api.CommandData.PlayerVibrations = {}
    end,
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, Intensity: number)
        Intensity = Intensity or 0.1
        local Util = IncludedCommandUtil.ForContext(CommandContext)
        local Api = Util:GetServerApi()

        for _, Player in Players do
            if Player.Character then
                local HumanoidRootPart = Player.Character:FindFirstChild("HumanoidRootPart") :: BasePart
                if HumanoidRootPart then
                    --Stop the existing vibration.
                    if Api.CommandData.PlayerVibrations[Player] then
                        Api.CommandData.PlayerVibrations[Player]:Destroy()
                    end

                    --Create the object.
                    local Vibration = {}
                    Vibration.Active = true
                    Vibration.Intensity = Intensity
                    Vibration.HumanoidRootPart = HumanoidRootPart
                    function Vibration:Run()
                        while self.Active do
                            self.HumanoidRootPart.CFrame = (self.HumanoidRootPart :: BasePart).CFrame * CFrame.new((math.random(-100, 100) / 100) * self.Intensity, 0, (math.random(-100, 100) / 100) * self.Intensity)
                            task.wait()
                        end
                    end
                    function Vibration:Destroy()
                        Vibration.Active = false
                    end

                    --Store the object and start vibrating.
                    if Intensity ~= 0 then
                        task.spawn(function()
                            Vibration:Run()
                        end)
                    end
                    Api.CommandData.PlayerVibrations[Player] = Vibration
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "visible",
    Category = "FunCommands",
    Description = "Makes a set of players visible.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to make visible.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                for _, Ins in Player.Character:GetDescendants() do
                    if (Ins:IsA("BasePart") or Ins:IsA("Decal")) and Ins.Transparency > 1 then
                        (Ins :: BasePart).Transparency = Ins.Transparency - 1.1
                    end
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local IncludedCommandUtil = require(script.Parent.Parent:WaitForChild("IncludedCommandUtil"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "volume",
    Category = "FunCommands",
    Description = "Changes the volume of the audio.",
    Arguments = {
        {
            Type = "number",
            Name = "Volume",
            Description = "Volume to set.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Volume: number)
        local Util = IncludedCommandUtil.ForContext(CommandContext)
        local Api = Util:GetServerApi()

        Api.CommandData.GlobalAudioSound.Volume = Volume
    end,
}


--Helper function for comparing consistency data between the client and server.
--!strict

local INDENT = "    "
local IGNORED_INSTANCES = {
    {
        Names = {
            ThumbnailCamera = true,
        },
        ClassName = "Camera",
    },
    {
        Names = {
            Climbing = true,
            Died = true,
            GettingUp = true,
            Swimming = true,
            Jumping = true,
            Landing = true,
            Splash = true,
            FreeFalling = true,
            Running = true,
        },
        ClassName = "Sound",
    },
} :: {{Names: {[string]: boolean}, ClassName: string}}

--[[
Creates a warning line with an indent.
--]]
local function GetIndentedWarningLine(Text)
    return {
        Text = `{INDENT}{Text}`,
        TextColor3 = Color3.fromRGB(255, 255, 0),
    }
end

--[[
Returns the lines for a KeyValue comparison.
--]]
local function CheckKeyValue(ClientData, ServerData)
    local Lines = {}
    for PropertyName, ServerValue in ServerData do
        local ClientValue = ClientData[PropertyName]
        if ClientValue ~= ServerValue then
            table.insert(Lines, GetIndentedWarningLine(`{PropertyName} is inconsistent. (Client: {ClientValue}, Server: {ServerValue})`))
        end
    end
    return Lines
end

--[[
Returns the lines for a InstanceTree comparison.
--]]
local function CheckInstanceTree(ClientData, ServerData)
    local Lines = {}
    local Scans = {
        {
            NotFoundPrefix = "Client is missing ",
            Source = ServerData,
            Target = ClientData,
        },
        {
            NotFoundPrefix = "Client has extra ",
            Source = ClientData,
            Target = ServerData,
        },
    }
    for i, Scan in Scans do
        --Build the queue of children to look at.
        local RemainingInstances = {}
        for _, SourceChild in Scan.Source do
            SourceChild.FullName = SourceChild.Name
            SourceChild.NameParts = {SourceChild.Name}
            table.insert(RemainingInstances, SourceChild)
        end

        --Iterate over the queue.
        while #RemainingInstances > 0 do
            local NextInstance = table.remove(RemainingInstances, 1) :: any

            --Ignore the instance if it should be ignored.
            local IgnoreInstance = false
            for _, IgnoredInstanceData in IGNORED_INSTANCES do
                if NextInstance.ClassName == IgnoredInstanceData.ClassName and (not IgnoredInstanceData.Names or IgnoredInstanceData.Names[NextInstance.Name]) then
                    IgnoreInstance = true
                    break
                end
            end
            if IgnoreInstance then
                continue
            end

            --Determine if the instance exists in the target.
            local TargetInstance = nil
            local CurrentParent = Scan.Target
            for i, Name in NextInstance.NameParts do
                local NewParent = nil
                for _, TargetChild in CurrentParent.Children or CurrentParent do
                    if (TargetChild :: any).Name == Name then
                        NewParent = TargetChild
                        break
                    end
                end
                if NewParent then
                    CurrentParent = NewParent :: any
                    if i == #NextInstance.NameParts then
                        TargetInstance = NewParent
                    end
                end
            end

            --Either the instance does not exist or enqueue the children.
            if not TargetInstance then
                table.insert(Lines, GetIndentedWarningLine(`{Scan.NotFoundPrefix}{NextInstance.FullName} ({NextInstance.ClassName})`))
            else
                if i == 1 and NextInstance.ClassName ~= (TargetInstance :: any).ClassName then
                    table.insert(Lines, GetIndentedWarningLine(`{NextInstance.FullName} classes don't match ({NextInstance.ClassName} ~= {(TargetInstance :: any).ClassName})`))
                end
                for _, Child in NextInstance.Children do
                    Child.FullName = `{NextInstance.FullName}.{Child.Name}`
                    local NameParts = {}
                    for _, NamePart in NextInstance.NameParts do
                        table.insert(NameParts, NamePart)
                    end
                    table.insert(NameParts, Child.Name)
                    Child.NameParts = NameParts
                    table.insert(RemainingInstances, Child)
                end
            end
        end
    end

    --Remove entries thatt show they are missing and exist on the client.
    --This can happen duplicate instance names exist.
    local LinesToRemove = {}
    local Prefix1, Prefix2 = GetIndentedWarningLine(Scans[1].NotFoundPrefix).Text, GetIndentedWarningLine(Scans[2].NotFoundPrefix).Text
    for i, Entry in Lines do
        if string.sub(Entry.Text, 1, string.len(Prefix1)) == Prefix1 then
            local TargetLine = `{Prefix2}{string.sub(Entry.Text, string.len(Prefix1) + 1)}`
            for j, OtherEntry in Lines do
                if LinesToRemove[j] then continue end
                if OtherEntry.Text ~= TargetLine then continue end
                LinesToRemove[i] = true
                LinesToRemove[j] = true
                break
            end
        end
    end
    for i = #Lines, 1, - 1 do
        if not LinesToRemove[i] then continue end
        table.remove(Lines, i)
    end

    --Return the lines.
    return Lines
end

return function (ClientData, ServerData)
    --Create a map of the client data.
    local ClientDataMap = {}
    for _, ClientDataEntry in ClientData do
        if ClientDataEntry.Description then
            ClientDataMap[ClientDataEntry.Description] = ClientDataEntry
        end
    end

    --Build the lines.
    local Lines = {}
    for i, ServerEntry in ServerData do
        table.insert(Lines, ServerEntry.Description)

        --Run the comparison.
        local ClientEntry = ClientDataMap[ServerEntry.Description]
        if not ClientEntry then
            table.insert(Lines, GetIndentedWarningLine("Client returned no data."))
        else
            local ComparisonLines = nil
            if ServerEntry.CompareMode == "KeyValue" then
                ComparisonLines = CheckKeyValue(ClientEntry.Data, ServerEntry.Data)
            elseif ServerEntry.CompareMode == "InstanceTree" then
                ComparisonLines = CheckInstanceTree(ClientEntry.Data, ServerEntry.Data)
            end
            if ComparisonLines then
                for _, Line in ComparisonLines do
                    table.insert(Lines, Line)
                end
                if #ComparisonLines == 0 then
                    table.insert(Lines, `{INDENT}Client and server are consistent.`)
                end
            else
                table.insert(Lines, GetIndentedWarningLine(`Unknown compare mode {ServerEntry.CompareMode}.`))
            end
        end

        --Add an extra line if there is another entry.
        if i ~= #ServerData then
            table.insert(Lines, "")
        end
    end
    return Lines
end


--Deserializers for DataTypes.
--!strict

return {
    ["Axes"] = function(Data)
        local AxesEnums = {}
        for _, EnunName in Data do
            table.insert(AxesEnums, (Enum.Axis :: any)[EnunName])
        end
        return Axes.new(unpack(AxesEnums))
    end,
    ["BrickColor"] = function(Data)
        return BrickColor.new(Data)
    end,
    ["Color3"] = function(Data)
        return Color3.new(unpack(Data))
    end,
    ["ColorSequence"] = function(Data)
        local Keypoints = {}
        for _, KeypointData in Data do
            table.insert(Keypoints, ColorSequenceKeypoint.new(KeypointData[1], Color3.new(KeypointData[2], KeypointData[3], KeypointData[4])))
        end
        return ColorSequence.new(Keypoints)
    end,
    ["CFrame"] = function(Data)
        return CFrame.new(unpack(Data))
    end,
    ["Faces"] = function(Data)
        local FaceEnums = {}
        for _, EnunName in Data do
            table.insert(FaceEnums, (Enum.NormalId :: any)[EnunName])
        end
        return Faces.new(unpack(FaceEnums))
    end,
    ["NumberRange"] = function(Data)
        return NumberRange.new(Data[1], Data[2])
    end,
    ["NumberSequence"] = function(Data)
        local Keypoints = {}
        for _, KeypointData in Data do
            table.insert(Keypoints, NumberSequenceKeypoint.new(KeypointData[1], KeypointData[2], KeypointData[3]))
        end
        return NumberSequence.new(Keypoints)
    end,
    ["PhysicalProperties"] = function(Data)
        return PhysicalProperties.new(unpack(Data))
    end,
    ["Ray"] = function(Data)
        return Ray.new(Vector3.new(Data[1], Data[2], Data[3]), Vector3.new(Data[4], Data[5], Data[6]))
    end,
    ["Rect"] = function(Data)
        return Rect.new(unpack(Data))
    end,
    ["UDim"] = function(Data)
        return UDim.new(unpack(Data))
    end,
    ["UDim2"] = function(Data)
        return UDim2.new(unpack(Data))
    end,
    ["Vector2"] = function(Data)
        return Vector2.new(unpack(Data))
    end,
    ["Vector3"] = function(Data)
        return Vector3.new(unpack(Data))
    end,
    ["Vector3int16"] = function(Data)
        return Vector3int16.new(unpack(Data))
    end,
} :: {[string]: (any) -> (any)}


--Serializers for DataTypes.
--!strict

return {
    ["Axes"] = function(Data: Axes)
        local AxesStrings = {}
        if Data.X then
            table.insert(AxesStrings, "X")
        end
        if Data.Y then
            table.insert(AxesStrings, "Y")
        end
        if Data.Z then
            table.insert(AxesStrings, "Z")
        end
        return AxesStrings
    end,
    ["BrickColor"] = function(Data: BrickColor)
        return Data.Name
    end,
    ["Color3"] = function(Data: Color3)
        return {Data.R, Data.G, Data.B}
    end,
    ["ColorSequence"] = function(Data: ColorSequence)
        local SerializedPoints = {}
        for _, Keypoint: ColorSequenceKeypoint in Data.Keypoints do
            table.insert(SerializedPoints, {Keypoint.Time, Keypoint.Value.R, Keypoint.Value.G, Keypoint.Value.B})
        end
        return SerializedPoints
    end,
    ["CFrame"] = function(Data: CFrame)
        return {Data:GetComponents()}
    end,
    ["Faces"] = function(Data: Faces)
        local FacesStrings = {}
        if Data.Top then
            table.insert(FacesStrings, "Top")
        end
        if Data.Bottom then
            table.insert(FacesStrings, "Bottom")
        end
        if Data.Front then
            table.insert(FacesStrings, "Front")
        end
        if Data.Bottom then
            table.insert(FacesStrings, "Bottom")
        end
        if Data.Left then
            table.insert(FacesStrings, "Left")
        end
        if Data.Right then
            table.insert(FacesStrings, "Right")
        end
        return FacesStrings
    end,
    ["NumberRange"] = function(Data: NumberRange)
        return {Data.Min, Data.Max}
    end,
    ["NumberSequence"] = function(Data: NumberSequence)
        local SerializedPoints = {}
        for _, Keypoint: NumberSequenceKeypoint in Data.Keypoints do
            table.insert(SerializedPoints, {Keypoint.Time, Keypoint.Value, Keypoint.Envelope})
        end
        return SerializedPoints
    end,
    ["PhysicalProperties"] = function(Data: PhysicalProperties)
        return {Data.Density, Data.Friction, Data.Elasticity, Data.FrictionWeight, Data.ElasticityWeight}
    end,
    ["Ray"] = function(Data: Ray)
        return {Data.Origin.X, Data.Origin.Y, Data.Origin.Z, Data.Direction.X, Data.Direction.Y, Data.Direction.Z}
    end,
    ["Rect"] = function(Data: Rect)
        return {Data.Min.X, Data.Min.Y, Data.Max.X, Data.Max.Y}
    end,
    ["UDim"] = function(Data: UDim)
        return {Data.Scale, Data.Offset}
    end,
    ["UDim2"] = function(Data: UDim2)
        return {Data.X.Scale, Data.X.Offset, Data.Y.Scale, Data.Y.Offset}
    end,
    ["Vector2"] = function(Data: Vector2)
        return {Data.X, Data.Y}
    end,
    ["Vector3"] = function(Data: Vector3)
        return {Data.X, Data.Y, Data.Z}
    end,
    ["Vector3int16"] = function(Data: Vector3int16)
        return {Data.X, Data.Y, Data.Z}
    end,
} :: {[string]: (any) -> (any)}


--Serializes and deserializes instances.
--!strict

local DIRECT_SERIALIZE_TYPES = {
    boolean = true,
    EnumItem = true,
    number = true,
    string = true,
}
local IGNORED_TYPES = {
    Content = true,
    Font = true,
    SecurityCapabilities = true,
}
local IGNORED_INSTANCES = {
    Script = true,
    LocalScript = true,
    ModuleScript = true,
}
local DEPENDENT_PROPERTIES = {
    CanvasPosition = true,
} :: {[string]: boolean}

local HttpService = game:GetService("HttpService")
local ReflectionService = game:GetService("ReflectionService")

local DataTypeSerializers = require(script:WaitForChild("DataTypeSerializers"))
local DataTypeDeserializers = require(script:WaitForChild("DataTypeDeserializers"))

local Serialization = {}
Serialization._CanCreateCache = {} :: {[string]: boolean}
Serialization._PropertiesCache = {} :: {[string]: {PropertiesEntry}}

export type Serialization = typeof(Serialization)
type PropertiesEntry = {
    Name: string,
    Type: string,
}

--[[
Returns if an instance can be created.
--]]
function Serialization.CanCreate(self: Serialization, ClassName: string): boolean
    if self._CanCreateCache[ClassName] == nil then
        local ClassPermits = ReflectionService:GetClass(ClassName).Permits
        self._CanCreateCache[ClassName] = (ClassPermits ~= nil and ClassPermits.New ~= nil)
    end
    return self._CanCreateCache[ClassName]
end

--[[
Returns the properties for a class.
--]]
function Serialization.GetProperties(self: Serialization, ClassName: string): {PropertiesEntry}
    if not self._PropertiesCache[ClassName] then
        local Properties = {}
        for _, Property in ReflectionService:GetPropertiesOfClass(ClassName) do
            if not Property.Type.ScriptType then continue end
            if not Property.Permits or not Property.Permits.Read or not Property.Permits.Write then continue end
            table.insert(Properties, {
                Name = Property.Name,
                Type = Property.Type.ScriptType,
            })
        end
        self._PropertiesCache[ClassName] = Properties
    end
    return self._PropertiesCache[ClassName]
end

--[[
Checks that the needed DataType serializers and deserializers exist.
--]]
function Serialization.CheckSerializers(self: Serialization): ()
    --Get the types.
    local Types = {}
    for _, Class in ReflectionService:GetClasses() do
        if not Class.Permits or not Class.Permits.New then continue end
        for _, Property in ReflectionService:GetPropertiesOfClass(Class.Name) do
            if not Property.Permits or not Property.Permits.Read or not Property.Permits.Write then continue end
            local TypeName = Property.Type.ScriptType
            if not TypeName then continue end
            if TypeName == "Instance" then continue end
            if DIRECT_SERIALIZE_TYPES[TypeName] then continue end
            if IGNORED_TYPES[TypeName] then continue end
            Types[TypeName] = true
        end
    end

    --Determine the types that don't have serializers and deserializers.
    local MissingSerializers = {}
    local MissingDeserializers = {}
    for TypeName, _ in Types do
        if not DataTypeSerializers[TypeName] then
            table.insert(MissingSerializers, TypeName)
        end
        if not DataTypeDeserializers[TypeName] then
            table.insert(MissingDeserializers, TypeName)
        end
    end
    if #MissingSerializers > 0 or #MissingDeserializers > 0 then
        error(`DataType serializers or deserializers found:\n\tSerializers: {HttpService:JSONEncode(MissingSerializers)}\n\tDeserializers: {HttpService:JSONEncode(MissingDeserializers)}`)
    end
end

--[[
Serializes a list of instances.
--]]
function Serialization.Serialize(self: Serialization, Instances: {Instance}, ExcludeCallback: ((Instance) -> (boolean))?): {{[string]: any}}
    --Create a list of instances to serialize.
    local CurrentIndex = 1
    local InstancesToSerialize = {}
    local InstancesToAddQueue = {}
    for _, Ins in Instances do
        table.insert(InstancesToAddQueue, Ins)
    end
    while #InstancesToAddQueue > 0 do
        --Get the next instance and ignore it if it is not creatable or ignored.
        local Ins = table.remove(InstancesToAddQueue, 1) :: Instance
        if IGNORED_INSTANCES[Ins.ClassName] or not self:CanCreate(Ins.ClassName) then
            continue
        end
        if ExcludeCallback and ExcludeCallback(Ins) then
            continue
        end

        --Add the instance and enqueue the children.
        InstancesToSerialize[Ins] = CurrentIndex
        CurrentIndex += 1
        for _, SubIns in Ins:GetChildren() do
            table.insert(InstancesToAddQueue, SubIns)
        end
    end

    --Serialize the instances.
    local SerializedInstances = {}
    for Ins, Id in InstancesToSerialize do
        --Create and store the base data.
        local SerializedInstance = {
            ClassName = Ins.ClassName
        }
        SerializedInstances[Id] = SerializedInstance

        --Serialize the properties.
        for _, Property in self:GetProperties(Ins.ClassName) do
            local PropertyName = Property.Name
            local PropertyValue = (Ins :: any)[PropertyName]
            if PropertyValue == nil then continue end
            local PropertyType = Property.Type
            if PropertyType == "EnumItem" then
                PropertyValue = PropertyValue.Name
            elseif PropertyType == "Instance" then
                if PropertyValue then
                    PropertyValue = InstancesToSerialize[PropertyValue]
                end
            elseif not DIRECT_SERIALIZE_TYPES[PropertyType] then
                if PropertyValue then
                    if DataTypeSerializers[PropertyType] then
                        PropertyValue = DataTypeSerializers[PropertyType](PropertyValue)
                    elseif not IGNORED_TYPES[PropertyType] then
                        warn(`Unsupported property serialization type: {PropertyType}`)
                        PropertyValue = nil
                    end
                end
            end
            SerializedInstance[PropertyName] = PropertyValue
        end
    end

    --Return the serialized instances.
    return SerializedInstances
end

--[[
Deserializes a list of instances.
--]]
function Serialization.Deserialize(self: Serialization, SerializedInstances: {{[string]: any}}): {Instance}
    --Create the instances.
    local Instances = {}
    for i, SerializedInstance in SerializedInstances do
        Instances[i] = Instance.new(SerializedInstance.ClassName)
    end

    --Set the properties.
    for i, SerializedInstance in SerializedInstances do
        --Determine the properties to set.
        local Ins = Instances[i]
        local Properties = {}
        for _, Property in self:GetProperties(Ins.ClassName) do
            local PropertyName = Property.Name
            local PropertyValue = SerializedInstance[PropertyName]
            local PropertyType = Property.Type
            if PropertyValue then
                if PropertyType == "Instance" then
                    if PropertyValue then
                        PropertyValue = Instances[PropertyValue]
                    end
                elseif not DIRECT_SERIALIZE_TYPES[PropertyType] then
                    if PropertyValue then
                        if DataTypeDeserializers[PropertyType] then
                            PropertyValue = DataTypeDeserializers[PropertyType](PropertyValue)
                        elseif not IGNORED_TYPES[PropertyType] then
                            warn(`Unsupported property deserialization type: {PropertyType}`)
                            PropertyValue = nil
                        end
                    end
                end
                Properties[PropertyName] = PropertyValue
            end
        end

        --Set the properties.
        --Some properties are dependent on others, so they are set twice.
        for PropertyName, PropertyValue in Properties do
            (Ins :: any)[PropertyName] = PropertyValue
        end
        for PropertyName, _ in DEPENDENT_PROPERTIES do
            if Properties[PropertyName] then
                (Ins :: any)[PropertyName] = Properties[PropertyName]
            end
        end
    end

    --Return the instances with no parents.
    local NoParentInstances = {}
    for _, Ins in Instances do
        if Ins.Parent then continue end
        table.insert(NoParentInstances, Ins)
    end
    return NoParentInstances
end

return Serialization


--Implementation of a command.
--!strict

local IncludedCommandUtil = require(script.Parent.Parent:WaitForChild("IncludedCommandUtil"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "pbanlogs",
    Category = "PersistentCommands",
    Description = "Displays the Persistent Bans and Unban Actions done through NexusAdmin.",
    Arguments = {},
    ServerLoad = function(Api: Types.NexusAdminApiServer)
        local PersistentBans = require(script.Parent.Parent:WaitForChild("Resources"):WaitForChild("PersistentBans")).GetInstance(Api)

        local GetPersistentBanLogsFunction = Instance.new("RemoteFunction")
        GetPersistentBanLogsFunction.Name = "GetPersistentBanLogs"
        GetPersistentBanLogsFunction.Parent = Api.EventContainer

        function GetPersistentBanLogsFunction.OnServerInvoke(Player): {string}
            if Api.Authorization:IsPlayerAuthorized(Player, Api.Configuration:GetCommandAdminLevel("PersistentCommands", "pbanlogs")) then
                --Return if the persistent bans wasn't initialized.
                if not PersistentBans:WasInitialized() then
                    if PersistentBans.Enabled then
                        return {"Persistent bans failed to initialize."}
                    else
                        return {"Roblox Ban API is disabled within this experience."}
                    end
                end

                --Assembly the log entries.
                --Moderator Values: #>0 = User, #<=0 = Specified By Script
                --Action Values: 0 = Ban, 1 = Unban
                local LogEntries = PersistentBans:GetLogs()
                local Logs = {}
                for i = #LogEntries, 1, -1 do
                    local Log = LogEntries[i]
                    if typeof(Log) == "string" then
                        table.insert(Logs, Log)
                    else
                        local ModeratorString = ""
                        if Log.Id then
                            if Log.Id <= 0 then
                                ModeratorString = Log.Name or "Nexus Admin"
                            else
                                ModeratorString = `@{Log.Name} ({Log.Id})`
                            end
                        else
                            ModeratorString = "Nexus Admin"
                        end
                        if Log.Action == 0 then
                            table.insert(Logs, `{ModeratorString} banned User Ids: \{{table.concat(Log.EffectedUserIds,", ")}\} at {Api.Time:GetDateTimeString(Log.Time)}, with a duration of ({Log.Duration == -1 and "Permanent" or Api.Time:GetDurationString(Log.Duration)}) {Log.ExperienceWide and "across the entire experience" or "in a single place"}, {Log.IncludeAlts and "including possible alt accounts" or "excluding possible alt accounts"}.`)
                        else
                            table.insert(Logs, `{ModeratorString} unbanned User Ids: \{{table.concat(Log.EffectedUserIds,", ")}\} at {Api.Time:GetDateTimeString(Log.Time)}, {Log.ExperienceWide and "across the entire experience" or "in a single place"}.`)
                        end
                    end
                end
                return Logs
            else
                return {"Unauthorized"}
            end
        end
    end,
    ClientRun = function(CommandContext: Types.CmdrCommandContext): ()
        local Util = IncludedCommandUtil.ForContext(CommandContext)
        local Api = Util:GetClientApi()

        --Show the window.
        local Window = Api.Window:CreateWindow("Persistent Ban Logs")
        local TextList = Window:AddTextList()
        TextList:EnableSearching()

        local function UpdateText()
            TextList:SetLines({"Loading..."})
            TextList:SetLines((Api.EventContainer:WaitForChild("GetPersistentBanLogs") :: RemoteFunction):InvokeServer())
        end

        task.spawn(UpdateText)
        Window:EnableRefreshing(UpdateText)
        Window:EnableClosing()
        Window:EnableResizing()
        Window:Show()
    end,
}


--Helper function for getting the data for checking for cosistency.
--!strict

local HUMANOID_PROPERTIES_TO_CHECK = {
    "AutoJumpEnabled",
    "AutoRotate",
    "BreakJointsOnDeath",
    "CameraOffset",
    "DisplayDistanceType",
    "DisplayName",
    "Health",
    "HealthDisplayDistance",
    "HipHeight",
    "Jump",
    "JumpHeight",
    "JumpPower",
    "MaxHealth",
    "MaxSlopeAngle",
    "Name",
    "NameDisplayDistance",
    "NameOcclusion",
    "PlatformStand",
    "RequiresNeck",
    "RigType",
    "RootPart",
    "SeatPart",
    "Sit",
    "UseJumpPower",
    "WalkSpeed",
}

export type InstanceTreeNode = {
    Name: string,
    ClassName: string,
    Children: {InstanceTreeNode},
}

--[[
Gets the descendants of an instance.
--]]
local function GetInstanceTree(ParentInstance: Instance): {InstanceTreeNode}
    local Instances = {}
    for _, Child in ParentInstance:GetChildren() do
        table.insert(Instances, {
            Name = Child.Name,
            ClassName = Child.ClassName,
            Children = GetInstanceTree(Child),
        })
    end
    return Instances
end

return function (Player: Player): {{Description: string, CompareMode: string, Data: any}}
    local Backpack = Player:FindFirstChild("Backpack")
    local StarterGear = Player:FindFirstChild("StarterGear")
    local Character = Player.Character
    local Humanoid = Character and Character:FindFirstChildOfClass("Humanoid")
    local HumanoidProperties = nil
    if Humanoid then
        HumanoidProperties = {}
        for _, PropertyName in HUMANOID_PROPERTIES_TO_CHECK do
            HumanoidProperties[PropertyName] = (Humanoid :: any)[PropertyName]
        end
    end
    return {
        {
            Description = "Humanoid",
            CompareMode = "KeyValue",
            Data = HumanoidProperties,
        },
        {
            Description = "Character",
            CompareMode = "InstanceTree",
            Data = Character and GetInstanceTree(Character),
        },
        {
            Description = "Backpack",
            CompareMode = "InstanceTree",
            Data = Backpack and GetInstanceTree(Backpack),
        },
        {
            Description = "StarterGear",
            CompareMode = "InstanceTree",
            Data = StarterGear and GetInstanceTree(StarterGear),
        },
    }
end


--Manages the tool enum.
--!strict

local TOOL_CONTAINERS = {
    game:GetService("Lighting"),
    game:GetService("ReplicatedStorage"),
    game:GetService("ServerStorage"),
    game:GetService("StarterPack"),
}

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

local ToolListEnum = {}
ToolListEnum.NexusAdminRegistry = nil :: Types.Registry?
ToolListEnum.ToolsLookup = {}
ToolListEnum.ToolChangedEvents = {} :: {RBXScriptConnection}

export type ToolListEnum = typeof(ToolListEnum)

--[[
Updates the tools lookup map and enum.
--]]
function ToolListEnum.UpdateEnum(self: ToolListEnum): ()
    --Disconnect the changed events.
    for _, Event in self.ToolChangedEvents do
        Event:Disconnect()
    end
    self.ToolChangedEvents = {}

    --Iterate over the tools and create the new lookup table.
    local ToolsLookup = {}
    local ToolNames = {}
    for _, Container in TOOL_CONTAINERS do
        for _, Tool in Container:GetDescendants() do
            if not Tool:IsA("BackpackItem") then continue end
            if not ToolsLookup[Tool.Name] then
                ToolsLookup[Tool.Name] = {}
                table.insert(ToolNames, Tool.Name)
            end
            table.insert(ToolsLookup[Tool.Name], Tool)

            --Connect the tool changing.
            table.insert(self.ToolChangedEvents, Tool.Changed:Connect(function(PropertyName)
                if PropertyName ~= "Parent" and PropertyName ~= "Name" then return end
                self:UpdateEnum()
            end))
        end
    end

    --Register the enum.
    table.sort(ToolNames, function(a, b) return string.lower(a) < string.lower(b) end)
    table.insert(ToolNames, 1, "all")
    if self.NexusAdminRegistry then
        self.NexusAdminRegistry:AddEnumType("nexusAdminTool", ToolNames)
    end

    --Create the lookup for all.
    local AllLookup = {}
    for _, ToolList in ToolsLookup do
        for _, Tool in ToolList do
            table.insert(AllLookup, Tool)
        end
    end
    ToolsLookup["all"] = AllLookup
    self.ToolsLookup = ToolsLookup
end

--[[
Returns the tools for the given names.
--]]
function ToolListEnum.GetTools(self: ToolListEnum, ToolNames: {string}): {Tool}
    local ToolSet = {}
    local ToolSetLookup = {}
    for _, ToolName in ToolNames do
        if not self.ToolsLookup[ToolName] then continue end
        for _, Tool in self.ToolsLookup[ToolName] do
            if ToolSetLookup[Tool] then continue end
            table.insert(ToolSet, Tool)
            ToolSetLookup[Tool] = true
        end
    end
    return ToolSet
end

--[[
Sets up the enum with Nexus Admin.
--]]
function ToolListEnum.SetUp(self: ToolListEnum, NexusAdminRegistry: Types.Registry): ()
    if self.NexusAdminRegistry then return end
    self.NexusAdminRegistry = NexusAdminRegistry

    --Set the initial enum.
    self:UpdateEnum()

    --Connect tools appearing and disappearing.
    for _, Container in TOOL_CONTAINERS do
        Container.DescendantAdded:Connect(function(Tool)
            if not Tool:IsA("BackpackItem") then return end
            self:UpdateEnum()
        end)
    end
end

return ToolListEnum


--Implementation of a command.
--!strict

local IncludedCommandUtil = require(script.Parent.Parent:WaitForChild("IncludedCommandUtil"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "clone",
    Category = "UsefulFunCommands",
    Description = "Clones the character of the given players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to clone.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        local Util = IncludedCommandUtil.ForContext(CommandContext)
        local Api = Util:GetApi()

        --Clone the players.
        for _,Player in Players do
            if Player.Character then
                Player.Character.Archivable = true

                local NewCharacter = Player.Character:Clone()
                NewCharacter:TranslateBy(Vector3.new(0, 6, 0))
                NewCharacter.Parent = Api.AdminItemContainer
            end
        end
    end,
}


--Implementation of a command.
--!strict

local IncludedCommandUtil = require(script.Parent.Parent:WaitForChild("IncludedCommandUtil"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "collide",
    Category = "UsefulFunCommands",
    Description = "Makes a set of players able to collide with each other.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to make collidable with each other.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        local Util = IncludedCommandUtil.ForContext(CommandContext)
        local Api = Util:GetApi()

        --Make the players collidable.
        for _, Player in Players do
            --Disconnect the events.
            if Api.CommandData.PlayerCollisionEvents[Player] then
                for _,Event in Api.CommandData.PlayerCollisionEvents[Player] do
                    Event:Disconnect()
                end
                Api.CommandData.PlayerCollisionEvents[Player] = {}
            end

            --Make the character collidable.
            if Player.Character then
                for _, Part in Player.Character:GetDescendants() do
                    if Part:IsA("BasePart") then
                        Part.CollisionGroup = "Default"
                    end
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "damage",
    Category = "UsefulFunCommands",
    Description = "Damages a given set of players, ignoring force fields.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to kill.",
        },
        {
            Type = "number",
            Name = "Damage",
            Description = "Amount of damage.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, Damage: number)
        for _, Player in Players do
            local Character = Player.Character
            if Character then
                local Humanoid = Character:FindFirstChildOfClass("Humanoid")
                if Humanoid then
                    Humanoid.Health = Humanoid.Health - Damage
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Workspace = game:GetService("Workspace")

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "explode",
    Category = "UsefulFunCommands",
    Description = "Explodes a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to explode.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                local HumanoidRootPart = Player.Character:FindFirstChild("HumanoidRootPart") :: BasePart
                if HumanoidRootPart then
                    local Explosion = Instance.new("Explosion")
                    Explosion.Name = "NexusAdminExplosion"
                    Explosion.Position = HumanoidRootPart.Position
                    Explosion.Parent = Workspace
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "ff",
    Category = "UsefulFunCommands",
    Description = "Adds a force field to the given players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to give force fields.",
        },
        {
            Type = "boolean",
            Name = "Invisible",
            Optional = true,
            Description = "Whether to make the forcefield invisible. Defaults to false.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, Invisible: boolean?)
        for _, Player in Players do
            local Character = Player.Character
            if Character then
                local ForceField = Instance.new("ForceField")
                ForceField.Name = "NexusAdminForceField"
                if Invisible == true then
                    ForceField.Visible = false
                end
                ForceField.Parent = Character
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Players = game:GetService("Players")

local IncludedCommandUtil = require(script.Parent.Parent:WaitForChild("IncludedCommandUtil"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "fling",
    Category = "UsefulFunCommands",
    Description = "Flings a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to fling.",
        },
        {
            Type = "number",
            Name = "SpeedMultiplier",
            Description = "Speed multiplier to apply to the fling speed.",
            Optional = true,
        },
    },
    ClientLoad = function(Api: Types.NexusAdminApiClient)
        (IncludedCommandUtil:GetRemote("FlingPlayer") :: RemoteEvent).OnClientEvent:Connect(function(RandomVelocity: Vector3)
            local Character = Players.LocalPlayer.Character
            if not Character then return end
            local HumanoidRootPart = Character:FindFirstChild("HumanoidRootPart") :: BasePart
            local Humanoid = Character:FindFirstChildOfClass("Humanoid")
            if not HumanoidRootPart or not Humanoid then return end
            Humanoid.Sit = true
            HumanoidRootPart.AssemblyLinearVelocity = RandomVelocity
        end)
    end,
    ServerLoad = function(Api: Types.NexusAdminApiServer)
        IncludedCommandUtil:CreateRemote("RemoteEvent", "FlingPlayer")
    end,
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, Multiplier: number?)
        local Util = IncludedCommandUtil.ForContext(CommandContext)
        local FlingPlayerEvent = Util:GetRemote("FlingPlayer") :: RemoteEvent

        --Fling the players.
        for _, Player in Players do
            local Character = Player.Character
            if not Character then continue end
            local HumanoidRootPart = Character:FindFirstChild("HumanoidRootPart") :: BasePart
            local Humanoid = Character:FindFirstChildOfClass("Humanoid")
            if not HumanoidRootPart or not Humanoid then continue end
            local RandomVelocity = (Multiplier or 1) *Vector3.new(math.random(-200, 200), 500, math.random(-200, 200))
            Humanoid.Sit = true
            HumanoidRootPart.AssemblyLinearVelocity = RandomVelocity
            FlingPlayerEvent:FireClient(Player, RandomVelocity)
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "flip",
    Category = "UsefulFunCommands",
    Description = "Flips a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to flip.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                local HumanoidRootPart = Player.Character:FindFirstChild("HumanoidRootPart") :: BasePart
                if HumanoidRootPart then
                    HumanoidRootPart.CFrame = HumanoidRootPart.CFrame * CFrame.Angles(0, 0, math.pi)
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local UserInputService = game:GetService("UserInputService")

local FlyState = require(script.Parent.Parent:WaitForChild("Resources"):WaitForChild("FlyState"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "fly",
    Category = "UsefulFunCommands",
    Description = `Gives a set of players the ability to fly. Use E on keyboard or {string.sub(UserInputService:GetStringForKeyCode(Enum.KeyCode.ButtonX), 7)} on controller to toggle on/off.`,
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to fly.",
        },
        {
            Type = "number",
            Name = "SpeedMultiplier",
            Description = "Speed multiplier to apply to the fly speed.",
            Optional = true,
        },
    },
    ClientLoad = function()
        --Empty, but forces this to be set up for the Description and FlyState.
    end,
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, SpeedMultiplier: number?)
        for _, Player in Players do
            FlyState.AddToPlayer(Player, SpeedMultiplier)
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "freeze",
    Category = "UsefulFunCommands",
    Description = "Freezes the character of the given players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to freeze.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                for _, Ins in Player.Character:GetDescendants() do
                    if Ins:IsA("BasePart") then
                        Ins.Anchored = true
                    end
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "god",
    Category = "UsefulFunCommands",
    Description = "Heals a set of players, and makes their health infinite.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to god.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            local Character = Player.Character
            if Character then
                local Humanoid = Character:FindFirstChildOfClass("Humanoid") :: Humanoid
                if Humanoid then
                    Humanoid.MaxHealth = math.huge
                    Humanoid.Health = math.huge
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Workspace = game:GetService("Workspace")

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = {"grav", "setgrav"},
    Category = "UsefulFunCommands",
    Description = "Sets the gravity of a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to change the gravity for.",
        },
        {
            Type = "number",
            Name = "Multiplier",
            Description = "Multiplifer of the gravity.",
            Optional = true,
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, Multiplier: number?)
        for _, Player in Players do
            local Character = Player.Character
            if Character then
                local HumanoidRootPart = Character:FindFirstChild("HumanoidRootPart")
                if HumanoidRootPart then
                    --Destroy the existing gravity effect.
                    local ExistingNexusAdminGravityEffect = HumanoidRootPart:FindFirstChild("NexusAdminGravityEffect")
                    if ExistingNexusAdminGravityEffect then
                        ExistingNexusAdminGravityEffect:Destroy()
                    end

                    if Multiplier and Multiplier ~= 1 then
                        --Calculate the gravity of the player.
                        local Mass = 0
                        for _,Ins in Character:GetDescendants() do
                            if Ins:IsA("BasePart") then
                                Mass = Mass + (Ins:GetMass() * Workspace.Gravity)
                            end
                        end

                        --Create the gravity effect.
                        local NexusAdminGravityEffect = Instance.new("BodyForce")
                        NexusAdminGravityEffect.Name = "NexusAdminGravityEffect"
                        NexusAdminGravityEffect.Force = Vector3.new(0, Mass * -(Multiplier - 1), 0)
                        NexusAdminGravityEffect.Parent = HumanoidRootPart
                    end
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "heal",
    Category = "UsefulFunCommands",
    Description = "Heals a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to heal.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            local Character = Player.Character
            if Character then
                local Humanoid = Character:FindFirstChildOfClass("Humanoid") :: Humanoid
                if Humanoid then
                    Humanoid.Health = Humanoid.MaxHealth
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "health",
    Category = "UsefulFunCommands",
    Description = "Heals a set of players, and sets their max health.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to set the health.",
        },
        {
            Type = "number",
            Name = "Health",
            Description = "Health to set.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, Health: number)
        for _, Player in Players do
            local Character = Player.Character
            if Character then
                local Humanoid = Character:FindFirstChildOfClass("Humanoid") :: Humanoid
                if Humanoid then
                    Humanoid.MaxHealth = Health
                    Humanoid.Health = Health
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local IncludedCommandUtil = require(script.Parent.Parent:WaitForChild("IncludedCommandUtil"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "jail",
    Category = "UsefulFunCommands",
    Description = "Creates a jail around a set of players. Each player can only have one jail.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to jail.",
        },
    },
    ServerLoad = function(Api: Types.NexusAdminApiServer)
        Api.CommandData.PlayerJails = {}
    end,
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        local Util = IncludedCommandUtil.ForContext(CommandContext)
        local Api = Util:GetApi()

        --Create the jails.
        for _, Player in Players do
            local Character = Player.Character
            if not Api.CommandData.PlayerJails[Player] and Character then
                local HumanoidRootPart = Character:FindFirstChild("HumanoidRootPart") :: BasePart
                if HumanoidRootPart then
                    --Create the jail.
                    local Center = HumanoidRootPart.CFrame
                    local Jail = Instance.new("Model")
                    Jail.Name = `Jail_{Player.Name}`
                    Jail.Parent = Api.AdminItemContainer

                    local Bottom = Instance.new("Part")
                    Bottom.Size = Vector3.new(5.2, 1, 5.2)
                    Bottom.Anchored = true
                    Bottom.Material = Enum.Material.SmoothPlastic
                    Bottom.BrickColor = BrickColor.new("Black")
                    Bottom.CFrame = Center * CFrame.new(0, -3.4, 0)
                    Bottom.Parent = Jail

                    local Top = Instance.new("Part")
                    Top.Size = Vector3.new(5.2, 1, 5.2)
                    Top.Anchored = true
                    Top.Material = Enum.Material.SmoothPlastic
                    Top.BrickColor = BrickColor.new("Black")
                    Top.CFrame = Center * CFrame.new(0, 3.6, 0)
                    Top.Parent = Jail

                    local Front = Instance.new("Part")
                    Front.Size = Vector3.new(5.2,6,0.6)
                    Front.Anchored = true
                    Front.Material = Enum.Material.SmoothPlastic
                    Front.BrickColor = BrickColor.new("White")
                    Front.CFrame = Center * CFrame.new(0, 0.1, 2.3)
                    Front.Transparency = 1
                    Front.Parent = Jail

                    local Back = Instance.new("Part")
                    Back.Size = Vector3.new(5.2, 6, 0.6)
                    Back.Anchored = true
                    Back.Material = Enum.Material.SmoothPlastic
                    Back.BrickColor = BrickColor.new("White")
                    Back.CFrame = Center * CFrame.new(0, 0.1, -2.3)
                    Back.Transparency = 1
                    Back.Parent = Jail

                    local Left = Instance.new("Part")
                    Left.Size = Vector3.new(0.6, 6, 4)
                    Left.Anchored = true
                    Left.Material = Enum.Material.SmoothPlastic
                    Left.BrickColor = BrickColor.new("White")
                    Left.CFrame = Center * CFrame.new(2.3, 0.1, 0)
                    Left.Transparency = 1
                    Left.Parent = Jail

                    local Right = Instance.new("Part")
                    Right.Size = Vector3.new(0.6,6,4)
                    Right.Anchored = true
                    Right.Material = Enum.Material.SmoothPlastic
                    Right.BrickColor = BrickColor.new("White")
                    Right.CFrame = Center * CFrame.new(-2.3, 0.1, 0)
                    Right.Transparency = 1
                    Right.Parent = Jail

                    local OuterGlass = Instance.new("Part")
                    OuterGlass.Size = Vector3.new(2, 2, 2)
                    OuterGlass.Anchored = true
                    OuterGlass.CanCollide = false
                    OuterGlass.Material = Enum.Material.SmoothPlastic
                    OuterGlass.BrickColor = BrickColor.new("White")
                    OuterGlass.CFrame = Center * CFrame.new(0, 0.1, 0)
                    OuterGlass.Transparency = 0.5
                    OuterGlass.Parent = Jail

                    local OuterMesh = Instance.new("SpecialMesh")
                    OuterMesh.MeshType = Enum.MeshType.FileMesh
                    OuterMesh.MeshId = "rbxassetid://9856898"
                    OuterMesh.Scale = Vector3.new(10.4, 12, 10.4)
                    OuterMesh.Parent = OuterGlass

                    local InnerGlass = Instance.new("Part")
                    InnerGlass.Size = Vector3.new(2, 2, 2)
                    InnerGlass.Anchored = true
                    InnerGlass.CanCollide = false
                    InnerGlass.Material = Enum.Material.SmoothPlastic
                    InnerGlass.BrickColor = BrickColor.new("White")
                    InnerGlass.CFrame = Center * CFrame.new(0, 0.1, 0)
                    InnerGlass.Transparency = 0.5
                    InnerGlass.Parent = Jail

                    local InnerMesh = Instance.new("SpecialMesh")
                    InnerMesh.MeshType = Enum.MeshType.FileMesh
                    InnerMesh.MeshId = "rbxassetid://9856898"
                    InnerMesh.Scale = Vector3.new(-8, -13, -8)
                    InnerMesh.Parent = InnerGlass

                    --Connect the event.
                    local CharacterAddedEvent = Player.CharacterAdded:Connect(function(Character)
                        if Jail.Parent then
                            local Root = Character:WaitForChild("HumanoidRootPart") :: BasePart
                            task.wait()
                            Root.CFrame = Center
                        end
                    end)

                    --Add the object.
                    local JailObject = {}
                    JailObject.Jail = Jail
                    JailObject.CharacterAddedEvent = CharacterAddedEvent
                    function JailObject:Destroy()
                        self.Jail:Destroy()
                        self.CharacterAddedEvent:Disconnect()
                        Api.CommandData.PlayerJails[Player] = nil
                    end
                    Api.CommandData.PlayerJails[Player] = JailObject
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "jump",
    Category = "UsefulFunCommands",
    Description = "Jumps a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to jump.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            local Character = Player.Character
            if Character then
                local Humanoid = Character:FindFirstChildOfClass("Humanoid") :: Humanoid
                if Humanoid then
                    Humanoid.Jump = true
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "jumpheight",
    Category = "UsefulFunCommands",
    Description = "Sets the jump height of the given players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to set the jump height.",
        },
        {
            Type = "number",
            Name = "JumpHeight",
            Description = "Jump height to set.",
            Optional = true,
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, JumpHeight: number?)
        for _, Player in Players do
            local Character = Player.Character
            if Character then
                local Humanoid = Character:FindFirstChildOfClass("Humanoid") :: Humanoid
                if Humanoid then
                    Humanoid.UseJumpPower = false
                    Humanoid.JumpHeight = JumpHeight or 7.2
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "jumppower",
    Category = "UsefulFunCommands",
    Description = "Sets the jump power of the given players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to set the jump power.",
        },
        {
            Type = "number",
            Name = "JumpPower",
            Description = "Jump power to set.",
            Optional = true,
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, JumpPower: number?)
        for _, Player in Players do
            local Character = Player.Character
            if Character then
                local Humanoid = Character:FindFirstChildOfClass("Humanoid") :: Humanoid
                if Humanoid then
                    Humanoid.UseJumpPower = true
                    Humanoid.JumpPower = JumpPower or 50
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "kill",
    Category = "UsefulFunCommands",
    Description = "Kills a given set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to kill.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            local Character = Player.Character
            if Character then
                local Humanoid = Character:FindFirstChildOfClass("Humanoid") :: Humanoid
                if Humanoid then
                    Humanoid.Health = 0
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "lock",
    Category = "UsefulFunCommands",
    Description = "Locks the character of the given players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to lock.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                for _,Ins in Player.Character:GetDescendants() do
                    if Ins:IsA("BasePart") then
                        Ins.Locked = true
                    end
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local TeleportService = game:GetService("TeleportService")

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "place",
    Category = "UsefulFunCommands",
    Description = "Teleports a set of players to the given place.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to teleport.",
        },
        {
            Type = "integer",
            Name = "PlaceId",
            Description = "Place to teleport to.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, PlaceId: number)
        for _, Player in Players do
            TeleportService:Teleport(PlaceId,Player)
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "sit",
    Category = "UsefulFunCommands",
    Description = "Sits a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to sit.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            local Character = Player.Character
            if Character then
                local Humanoid = Character:FindFirstChildOfClass("Humanoid") :: Humanoid
                if Humanoid then
                    Humanoid.Sit = true
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "stun",
    Category = "UsefulFunCommands",
    Description = "Stuns a set of players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to stun.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            local Character = Player.Character
            if Character then
                local Humanoid = Character:FindFirstChildOfClass("Humanoid") :: Humanoid
                if Humanoid then
                    Humanoid.PlatformStand = true
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = {"thaw", "unfreeze"},
    Category = "UsefulFunCommands",
    Description = "Thaws the character of the given players.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to thaw.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player})
        for _, Player in Players do
            if Player.Character then
                for _,Ins in Player.Character:GetDescendants() do
                    if Ins:IsA("BasePart") then
                        Ins.Anchored = false
                    end
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "thru",
    Category = "UsefulFunCommands",
    Description = "Teleports a set of players forward a given amount of studs.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Player",
            Description = "Players to move.",
        },
        {
            Type = "number",
            Name = "Distance",
            Description = "Distance to move forward.",
            Optional = true,
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, Distance: number?)
        for _, Player in Players do
            local Character = Player.Character :: Model
            if Player.Character then
                local HumanoidRootPart = Character:FindFirstChild("HumanoidRootPart") :: BasePart
                if HumanoidRootPart then
                    HumanoidRootPart.CFrame = HumanoidRootPart.CFrame * CFrame.new(0, 0, -(Distance or 0))
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local IncludedCommandUtil = require(script.Parent.Parent:WaitForChild("IncludedCommandUtil"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "tp",
    Category = "UsefulFunCommands",
    Description = "Teleports a set of players to another player.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to teleport.",
        },
        {
            Type = "nexusAdminPlayers",
            Name = "TargetPlayer",
            Description = "Player to teleport to",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, TargetPlayers: {Player})
        local Util = IncludedCommandUtil.ForContext(CommandContext)

        --Get the target location.
        local TargetLocation
        local TargetPlayer
        for _, NewTargetPlayer in TargetPlayers do
            if NewTargetPlayer.Character then
                local HumanoidRootPart = NewTargetPlayer.Character:FindFirstChild("HumanoidRootPart") :: BasePart
                if HumanoidRootPart then
                    TargetPlayer = NewTargetPlayer
                    TargetLocation = HumanoidRootPart.CFrame
                    break
                end
            end
        end

        --Telelport the players.
        local Radius = math.max(10, #Players)
        if TargetLocation then
            for _, Player in Players do
                if Player ~= TargetPlayer then
                    Util:TeleportPlayer(Player, TargetLocation * CFrame.new(math.random(-Radius, Radius) / 10, 0, math.random(-Radius, Radius) / 10))
                end
            end
        end
    end,
}


--Implementation of a command.
--!strict

local IncludedCommandUtil = require(script.Parent.Parent:WaitForChild("IncludedCommandUtil"))
local Types = require(script.Parent.Parent.Parent:WaitForChild("Types"))

return {
    Keyword = "tpto",
    Category = "UsefulFunCommands",
    Description = "Teleports a set of players to a specific location.",
    Arguments = {
        {
            Type = "nexusAdminPlayers",
            Name = "Players",
            Description = "Players to teleport.",
        },
        {
            Type = "vector3",
            Name = "TargetPosition",
            Description = "Position to teleport to.",
        },
    },
    ServerRun = function(CommandContext: Types.CmdrCommandContext, Players: {Player}, TargetPosition: Vector3)
        local Util = IncludedCommandUtil.ForContext(CommandContext)

        --Telelport the players.
        local Radius = math.max(10, #Players)
        local TargetLocation = CFrame.new(TargetPosition)
        if TargetLocation then
            for _, Player in Players do
                Util:TeleportPlayer(Player, TargetLocation * CFrame.new(math.random(-Radius, Radius) / 10, 0, math.random(-Radius, Radius) / 10))
            end
        end
    end,
}