--!optimize 2
--!strict
--[=[ lunar
	about = "Builds and runs the unit tests place file."
	args = "[--dev] [<project>]"
]=]

local ArgParse = require("@packages/ArgParse")
local Chalk = require("@packages/Chalk")
local Enum = require("@packages/Enum")
local LuauPolyfill = require("@packages/LuauPolyfill")
local PathFileSystem = require("@packages/PathFileSystem")
local ReducedInstance = require("@utilities/ReducedInstance")
local Runtime = require("@utilities/Runtime")

local BrickColor = require("@contexts/BrickColor")
local Color3 = require("@contexts/Color3")
local DateTime = require("@contexts/DateTime")
local Debug = require("@contexts/Debug")
local Instance = require("@contexts/Instance")
local NumberRange = require("@contexts/NumberRange")
local Random = require("@contexts/Random")
local RaycastParams = require("@contexts/RaycastParams")
local Vector3 = require("@contexts/Vector3")

local TypeOf = require("@packages/TypeOf")

local luau = require("@lune/luau")
local process = require("@lune/process")
local roblox = require("@lune/roblox")
local serde = require("@lune/serde")
local task = require("@lune/task")

local Path = PathFileSystem.Path
local console = LuauPolyfill.console

local NULL_MARKER = `__NULL_MARKER-{math.random()}-{math.random()}-NULL_MARKER__`

local DEFAULT_PROJECT_FILE_PATH = Path.new("test.project.json")
local WARN_COLOR = Chalk.Rgb(226, 124, 21)

local function MakeJsonSafeForSerde(jsonString: string): string
	return (string.gsub(string.gsub(string.gsub(jsonString, "/%*.-%*/", ""), "//[^\n]*", ""), ",%s*([}%]])", "%1"))
end
local function Warn(...: unknown): ()
	local length = select("#", ...)
	local arguments = table.create(length)
	for index = 1, length do
		arguments[index] = tostring(select(index, ...))
	end
	warn(WARN_COLOR(table.concat(arguments, " ")))
end

local parser =
	ArgParse("run-unit-tests-local", "Runs the Jest unit tests within Lune. Faster, but not fully implemented.")
parser:flag("--dev", "Sets __DEV__ to true.")
parser:argument(
	"project",
	"The Rojo project file to build and run.",
	DEFAULT_PROJECT_FILE_PATH:toString(),
	function(value: string): string?
		return if PathFileSystem.IsFileSafeSilent(value) then value else nil
	end
)

local arguments: {
	dev: boolean,
	project: string?,
} = parser:parse()

if arguments.dev then
	_G.__DEV__ = true
end

type Path = PathFileSystem.Path
type RojoProject = {
	name: string,
	tree: any,
}

local function ReadRojoProject(filePath: PathFileSystem.Path): RojoProject
	assert(
		PathFileSystem.IsFile(filePath),
		`Rojo project file {filePath} not found. Please create it or specify a different file as an argument.`
	)

	local success, value =
		pcall(serde.decode, "json" :: "json", MakeJsonSafeForSerde(PathFileSystem.ReadFile(filePath)))
	assert(success, `Failed to read Rojo project file {filePath}: {value}`)
	assert(value.name, "Rojo project name is required in the project file")
	return value
end
local function BuildProject(rojoProjectFilePath: PathFileSystem.Path)
	local rojoProject = ReadRojoProject(rojoProjectFilePath)
	local builtProjectFilePath = `{rojoProject.name}.rbxl`
	local root = process.env.HOME or process.env.USERPROFILE

	local rojoPath = Path.new(root):join(".rokit"):join("bin"):join("rojo")

	-- console.log(`Building project {rojoProjectFilePath} into {builtProjectFilePath} with Rojo...\n`)
	local spawnResult =
		process.exec(rojoPath:toString(), {"build", rojoProjectFilePath:toString(), "--output", builtProjectFilePath})
	assert(spawnResult.ok, `Failed to build project [{builtProjectFilePath}]: {spawnResult.stderr}`)

	-- console.log(`Deserializing {builtProjectFilePath}...`)
	local success, result = pcall(roblox.deserializePlace, PathFileSystem.ReadFile(builtProjectFilePath))
	assert(success, `Failed to deserialize built project [{builtProjectFilePath}]: {result}`)

	return result
end

local function ImplementRobloxMethods(): ()
	roblox.implementMethod("Instance", "WaitForChild", function(self, ...)
		local child = self:FindFirstChild(...)
		assert(
			child,
			`WaitForChild is not implemented in Lune, so FindFirstChild was substituted but {self:GetFullName()} does not contain child {(...)} at the time of calling.`
		)
		return child
	end)
	roblox.implementMethod("Instance", "isA", function(self, className: string)
		return self:IsA(className)
	end)

	roblox.implementMethod("Instance", "GetActor", function()
		return nil
	end)
	roblox.implementMethod("Instance", "GetAttributeChangedSignal", function()
		return {
			Connect = function()
				return {
					Connected = true;
					Disconnect = function(self)
						self.Connected = false
					end;
				}
			end;
			Wait = function() end;
		}
	end)

	local function postSimulation()
		return {
			Connect = Runtime.Connect;
			Wait = function()
				local thread = coroutine.running()
				local connection: Runtime.Connection = nil
				connection = Runtime:Connect(function(deltaTime)
					connection:Disconnect()
					coroutine.resume(thread, deltaTime)
				end)
				return coroutine.yield()
			end;
		}
	end
	roblox.implementProperty("RunService", "Heartbeat", postSimulation)
	roblox.implementProperty("RunService", "PostSimulation", postSimulation)
	roblox.implementMethod("RunService", "IsStudio", function()
		return true
	end)
	roblox.implementMethod("RunService", "IsServer", function()
		return true
	end)
end

local rojoProjectFilePath = Path.from(arguments.project or DEFAULT_PROJECT_FILE_PATH)

local game = BuildProject(rojoProjectFilePath)
ImplementRobloxMethods()

-- Declaring because it's needed by `loadScript`, but `loadScript` is also needed in `requireModule`. Defined later.
local RequireModule

local BAD_TYPES = {
	["function"] = true;
	thread = true;
	userdata = true;
}

local function DeshitifyJsonTable(object: {[any]: any}): {[any]: any}
	local newObject = table.clone(object)
	for key, value in newObject do
		local typeOf = type(value)
		if typeOf == "table" then
			newObject[key] = DeshitifyJsonTable(value)
		elseif BAD_TYPES[typeOf] then
			newObject[key] = NULL_MARKER
		end
	end
	return newObject
end

-- DEPENDENTS: [TestService/Source/run.server.luau]
-- ProcessService isn't implemented in Lune, so this creates a workable implementation of it by mapping it to process.exit
local gameWithContext = setmetatable({
	GetService = function(_self, serviceName: string)
		if serviceName == "ProcessService" then
			return {
				ExitAsync = function(_, code: number)
					process.exit(code)
				end;
			} :: any
		end

		if serviceName == "HttpService" then
			return {
				JSONEncode = function(_, data: any): string
					if type(data) == "table" then
						data = DeshitifyJsonTable(data)
					end

					return (string.gsub(serde.encode("json", data, false), string.format("%q", NULL_MARKER), "null"))
				end;
				JSONDecode = function(_, data: string): unknown
					return serde.decode("json", data)
				end;
			}
		end

		if serviceName == "CoreScriptSyncService" then
			return nil
		end

		return game:GetService(serviceName)
	end;
}, {__index = game})

local function LoadScript(script: roblox.Instance): (((...any) -> ...any)?, string?)
	script = ReducedInstance.Once(script)
	if not script:IsA("LuaSourceContainer") then
		return nil, "Attempt to load a non LuaSourceContainer"
	end

	local bytecodeSuccess, bytecode = pcall(luau.compile, (script :: any).Source)
	if not bytecodeSuccess then
		return nil, bytecode
	end

	local callableFunction = luau.load(bytecode, {
		debugName = script:GetFullName();
		environment = setmetatable({
			BrickColor = BrickColor;
			Color3 = Color3;
			DateTime = DateTime;
			Enum = Enum;
			Instance = Instance;
			NumberRange = NumberRange;
			Random = Random;
			RaycastParams = RaycastParams;
			Vector3 = Vector3;

			Axes = require("@contexts/Unimplemented/Axes");
			CatalogSearchParams = require("@contexts/Unimplemented/CatalogSearchParams");
			ColorSequence = require("@contexts/Unimplemented/ColorSequence");
			Faces = require("@contexts/Unimplemented/Faces");
			NumberSequence = require("@contexts/Unimplemented/NumberSequence");
			OverlapParams = require("@contexts/Unimplemented/OverlapParams");
			Path2DControlPoint = require("@contexts/Unimplemented/Path2DControlPoint");
			PhysicalProperties = require("@contexts/Unimplemented/PhysicalProperties");

			debug = Debug;
			task = task;

			require = RequireModule;
			tick = os.clock;
			typeof = TypeOf;
			warn = Warn;

			game = gameWithContext;
			script = script;

			-- idiot garbage
			fs = require("@lune/fs");
			LuneDateTime = require("@lune/datetime");
		}, {__index = roblox}) :: any;
	})

	return callableFunction
end

-- Override the unimplemented _loader function with the above implementation
Debug._loader = LoadScript

local MODULE_REGISTRY = {}

function RequireModule(moduleScript: roblox.Instance)
	assert(moduleScript and moduleScript:IsA("ModuleScript"), `Attempt to require a non ModuleScript {moduleScript}`)

	local cached = MODULE_REGISTRY[moduleScript]
	if cached then
		return cached
	end

	local callback, exception = LoadScript(moduleScript)
	assert(callback, exception)

	local result = callback()
	MODULE_REGISTRY[moduleScript] = result
	return result
end

console.log("\n")
-- console.log("Starting main...\n")
local TestService = game:GetService("TestService")

local execute = TestService:FindFirstChild("Execute")
assert(execute, "game.TestService.Execute not found")

local callback, exception = LoadScript(ReducedInstance.Once(execute))
assert(callback, exception)

_G.__UNIT_TEST_CLEANUP__ = function(): ()
	local withBenchmarks = PathFileSystem.CWD:join("WithBenchmarks.rbxl")
	if PathFileSystem.IsFileSafe(withBenchmarks) then
		PathFileSystem.RemoveFile(withBenchmarks)
	end
end

-- console.log("Running tests from game.TestService.Execute...\n")
callback()


--!optimize 2
--!strict
--[=[ lunar
	about = "Transforms the bad function declaration to the good one."
	args = "[--verbose]"
]=]

local ArgParse = require("@packages/ArgParse")
local FormatUtilities = require("@utilities/FormatUtilities")
local LuauLexer = require("@packages/LuauLexer")
local LuauPolyfill = require("@packages/LuauPolyfill")
local PathFileSystem = require("@packages/PathFileSystem")
local ThreadUtilities = require("@packages/ThreadUtilities")
local process = require("@lune/process")

local Set = LuauPolyfill.Set
local console = LuauPolyfill.console

type Path = PathFileSystem.Path
type Set<T> = LuauPolyfill.Set<T>
type TokenType = LuauLexer.TokenType

local parser = ArgParse("transform-functions", "Transforms the bad function declaration to the good one.")
parser:flag("verbose", "Prints more information.")

local arguments: {verbose: boolean?} = parser:parse()
local isVerbose = not not arguments.verbose

local OUT_DIRECTORY = PathFileSystem.CWD:join("out")

if not PathFileSystem.IsDirectory(OUT_DIRECTORY) then
	console.error("Could not find out directory")
	process.exit(1)
end

local CAN_TRANSFORM: Set<string> = Set.new({"luau", "lua"})

local toTransform: {Path} = {}
local totalTransformed = 0

for _, filePath in PathFileSystem.GetDescendants(OUT_DIRECTORY) do
	if not PathFileSystem.IsFile(filePath) then
		if isVerbose then
			console.log(`Skipping directory {filePath}`)
		end
		continue
	end

	local fileExtension = filePath:extension()
	if not fileExtension then
		if isVerbose then
			console.log(`Skipping file {filePath} (missing extension?)`)
		end
		continue
	end

	if not CAN_TRANSFORM:has(fileExtension) then
		if isVerbose then
			console.log(`Skipping file {filePath} (not a Luau file)`)
		end
		continue
	end

	local navigator = LuauLexer.Navigator()
	navigator.SetSource(PathFileSystem.ReadFile(filePath))

	local newFileSource = {}
	local length = 0
	local wasChanged = false

	while true do
		local tokenType: TokenType, content = navigator.Next()
		if tokenType == nil then
			if isVerbose then
				console.log("Breaking the navigation loop.")
			end
			break
		end

		local addContent = content

		if tokenType == "keyword" then
			local functionName: string? = nil
			local skipAmount = 0

			if content == "local " then
				local identifierTokenType: TokenType, identifierContent = navigator.Peek(1)
				if identifierTokenType == "iden" then
					functionName = string.gsub(identifierContent, "%s+$", "")
					skipAmount += 1

					local operatorTokenType: TokenType, operatorContent = navigator.Peek(2)
					if operatorTokenType == "operator" and operatorContent == "= " then
						skipAmount += 1
						local keywordTokenType: TokenType, keywordContent = navigator.Peek(3)
						if keywordTokenType == "keyword" and keywordContent == "function" then
							skipAmount += 1
						else
							skipAmount = 0
							functionName = nil
						end
					else
						skipAmount = 0
						functionName = nil
					end
				end
			end

			if skipAmount ~= 0 and functionName then
				addContent = string.format("local function %*", functionName)
				wasChanged = true
				for _ = 1, skipAmount do
					navigator.Next()
				end
			end
		end

		length += 1
		newFileSource[length] = addContent
	end

	if wasChanged then
		PathFileSystem.WriteFile(filePath, table.concat(newFileSource))
		totalTransformed += 1
		toTransform[totalTransformed] = filePath
	end
end

for _, filePath in toTransform do
	if isVerbose then
		console.log(`Formatting {filePath}...`)
	end
	ThreadUtilities.FastDefer(function()
		FormatUtilities.FormatAsync(filePath:toString(), {
			FormatAmount = 5;
		}):Expect()
	end)
end


--!optimize 2
--!strict

local process = require("@lune/process")
local roblox = require("@lune/roblox")

local robloxCookie = roblox.getAuthCookie(true)
if not robloxCookie then
	warn("Failed to get Roblox auth cookie!")
	process.exit(1)
	error("unreachable")
end

local result = process.exec("tarmac", {
	"--auth";
	string.format("%q", robloxCookie);
	"sync";
	"--target";
	"roblox";
})

if not result.ok or result.stderr then
	warn(`Failed to upload to Roblox: ({result.code}) {result.stderr}`)
end


--!optimize 2
--!strict

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local StarterPlayer = game:GetService("StarterPlayer")
local TestService = game:GetService("TestService")
local Jest = (require :: any)(ReplicatedStorage.rbxts_include.node_modules:FindFirstChild("@rbxts").JestLua.Jest)

local processServiceExists, ProcessService = pcall(function()
	local processServiceName = "ProcessService"
	return game:GetService(processServiceName)
end)

local roots: {Instance} = {}
local function AddRoot(parent: Instance, name: string): ()
	local child = parent:FindFirstChild(name)
	if child then
		table.insert(roots, child)
	end
end
AddRoot(ReplicatedStorage, "TS")
AddRoot(ServerScriptService, "TS")
AddRoot(StarterPlayer.StarterPlayerScripts, "TS")

if #roots == 0 then
	warn("No test roots found. Please ensure the script is running in a valid environment.")
	ProcessService:ExitAsync(0)
	return
end

local status, result = Jest.runCLI(script, {
	all = true;
	ci = false;
	verbose = true;
	setupFiles = {TestService:FindFirstChild("setup")};
}, roots):awaitStatus()

if status == "Rejected" then
	warn(result)
end

if
	status == "Resolved"
	and result.results.numFailedTestSuites == 0
	and result.results.numFailedTests == 0
	and processServiceExists
then
	ProcessService:ExitAsync(0)
	return
end

if processServiceExists then
	ProcessService:ExitAsync(1)
	return
end

return false


//!optimize 2

import type { Storybook } from "@rbxts/ui-labs";

const ClientStorybook: Storybook = {
	groupRoots: true,
	name: "Client",
	storyRoots: [script.Parent!.FindFirstChild("__stories__")!],
};

export = ClientStorybook;


import type { Config } from "@rbxts/jest";

export = {
	displayName: "🔵 CLIENT",
	testMatch: ["**/__tests__/*.test"],
} satisfies Config;


import type { Config } from "@rbxts/jest";

export = {
	displayName: "🟢 SERVER",
	testMatch: ["**/__tests__/*.test"],
} satisfies Config;


//!optimize 2

import type { Storybook } from "@rbxts/ui-labs";

const ServerStorybook: Storybook = {
	groupRoots: true,
	name: "Server",
	storyRoots: [script.Parent!.FindFirstChild("__stories__")!],
};

export = ServerStorybook;


import type { Config } from "@rbxts/jest";

export = {
	displayName: "⚪ SHARED",
	testMatch: ["**/__tests__/*.test"],
} satisfies Config;


//!optimize 2

import ForcedPlatformProvider from "../providers/forced-platform-provider";
import ContextStack from "@rbxts/context-stack";
import React, { StrictMode, useMemo } from "@rbxts/react";
import { RunService } from "@rbxts/services";
import type DevicePlatform from "shared/modules/meta/device-platform";
import type { AnyArray } from "shared/modules/types/utility-types";

const IS_STUDIO = RunService.IsStudio();

export interface BaseAppProperties extends React.PropsWithChildren {
	readonly forcedPlatform?: DevicePlatform;
	readonly providers?: AnyArray<React.ReactElement>;
	readonly usingStrictMode?: boolean;
}

export function BaseAppNoMemo({
	children,
	forcedPlatform,
	providers,
	usingStrictMode = IS_STUDIO,
}: BaseAppProperties): React.Element {
	const newProviders = useMemo((): Array<React.Element> => {
		const newProviders: Array<React.Element> = [];
		let length = newProviders.size();

		if (forcedPlatform !== undefined)
			newProviders[length++] = (
				<ForcedPlatformProvider forcedPlatform={forcedPlatform} key="ForcedPlatformProvider" />
			);

		if (providers) {
			const providersLength = providers.size();
			providers.move(0, providersLength - 1, length, newProviders);
			length += providersLength;
		}

		return newProviders;
	}, [forcedPlatform, providers]);

	const stackElement = (
		<ContextStack key="ContextStack" providers={newProviders}>
			{children}
		</ContextStack>
	);

	return usingStrictMode ? <StrictMode>{stackElement}</StrictMode> : stackElement;
}

export const BaseApp = React.memo(BaseAppNoMemo);
BaseApp.displayName = "BaseApp";
export default BaseApp;


//!optimize 2

import { useErrorBoundary } from "../packages/react-error-boundary";
import React, { useEffect } from "@rbxts/react";

export function FallbackResetBoundaryNoMemo(): React.Element {
	const { resetBoundary } = useErrorBoundary();

	function resetEffect() {
		resetBoundary();
	}
	useEffect(resetEffect, [resetBoundary]);

	return <></>;
}

export const FallbackResetBoundary = React.memo(FallbackResetBoundaryNoMemo);
FallbackResetBoundary.displayName = "FallbackResetBoundary";
export default FallbackResetBoundary;


//!optimize 2

import React from "@rbxts/react";
import ForcedPlatformContext from "shared/modules/contexts/forced-platform-context";
import type DevicePlatform from "shared/modules/meta/device-platform";

export interface ForcedPlatformProviderProperties extends React.PropsWithChildren {
	readonly forcedPlatform?: DevicePlatform;
}

export function ForcedPlatformProviderNoMemo({
	children,
	forcedPlatform,
}: ForcedPlatformProviderProperties): React.Element {
	return forcedPlatform === undefined ? (
		<>{children}</>
	) : (
		<ForcedPlatformContext.Provider value={forcedPlatform}>{children}</ForcedPlatformContext.Provider>
	);
}

export const ForcedPlatformProvider = React.memo(ForcedPlatformProviderNoMemo);
ForcedPlatformProvider.displayName = "ForcedPlatformProvider";
export default ForcedPlatformProvider;


//!optimize 2

import React from "@rbxts/react";
import { createPortal } from "@rbxts/react-roblox";

export interface PortalProperties extends React.PropsWithChildren {
	readonly target: Instance;
}

export function PortalNoMemo({ children, target }: PortalProperties): React.Element {
	return createPortal(children, target);
}

export const Portal = React.memo(PortalNoMemo);
Portal.displayName = "Portal";
export default Portal;


//!optimize 2

import type DevicePlatform from "../meta/device-platform";
import { createContext } from "@rbxts/react";

export const ForcedPlatformContext = createContext<DevicePlatform | undefined>(undefined);
ForcedPlatformContext.displayName = "ForcedPlatformContext";
export default ForcedPlatformContext;


//!optimize 2

import { useContext } from "@rbxts/react";
import ForcedPlatformContext from "shared/modules/contexts/forced-platform-context";
import type DevicePlatform from "shared/modules/meta/device-platform";

export default function useForcedPlatform(): DevicePlatform | undefined {
	return useContext(ForcedPlatformContext);
}


//!optimize 2

import useForcedPlatform from "../contexts/use-forced-platform";
import { type Binding, useBinding } from "@rbxts/react";
import { useEventConnection } from "@rbxts/react-hooks";
import { UserInputService } from "@rbxts/services";
import type DevicePlatform from "shared/modules/meta/device-platform";
import { getDevicePlatform } from "shared/modules/utilities/device-utilities";
import isTrulyStudio from "shared/modules/utilities/is-truly-studio";

const IS_STUDIO = isTrulyStudio();

export default function useDevicePlatform(forcedDevicePlatform?: DevicePlatform): Binding<DevicePlatform> {
	const forcedPlatform = useForcedPlatform();
	const [platform, setPlatform] = useBinding(
		IS_STUDIO ? (forcedPlatform ?? forcedDevicePlatform ?? getDevicePlatform()) : getDevicePlatform(),
	);

	useEventConnection(
		UserInputService.LastInputTypeChanged,
		() => {
			const newPlatform = IS_STUDIO
				? (forcedPlatform ?? forcedDevicePlatform ?? getDevicePlatform())
				: getDevicePlatform();
			if (newPlatform !== platform.getValue()) setPlatform(newPlatform);
		},
		[forcedDevicePlatform, forcedPlatform],
	);

	return platform;
}


//!optimize 2

import useDevicePlatform from "./use-device-platform";
import { type Binding, joinBindings } from "@rbxts/react";
import { useViewportSize } from "@rbxts/react-hooks";
import { GuiService } from "@rbxts/services";
import DevicePlatform from "shared/modules/meta/device-platform";

const [TOP_LEFT, BOTTOM_RIGHT] = GuiService.GetGuiInset();

type Platforms = { readonly [devicePlatform in DevicePlatform]?: number };
export interface ScaleParameters extends Platforms {
	readonly baseScale: number;
}

export default function useScalePlatform(
	scaleParameters: ScaleParameters,
	goalSize: Vector2 | Vector3,
	forcedDevicePlatform?: DevicePlatform,
): Binding<number> {
	return joinBindings({
		devicePlatform: useDevicePlatform(forcedDevicePlatform),
		viewportSize: useViewportSize(),
	}).map(({ devicePlatform, viewportSize }) => {
		const size = viewportSize.sub(TOP_LEFT).add(BOTTOM_RIGHT);
		const scale = scaleParameters[devicePlatform] ?? scaleParameters.baseScale;
		return (1 / math.max(goalSize.X / size.X, goalSize.Y / size.Y)) * scale;
	});
}


//!optimize 2

import useScalePlatform from "./use-scale-platform";
import type { Binding } from "@rbxts/react";
import DevicePlatform from "shared/modules/meta/device-platform";

export type ModifyWith = { readonly [devicePlatform in DevicePlatform]?: number };

export default function useStandardScale(modifyWith?: ModifyWith): Binding<number> {
	return useScalePlatform(
		{
			[DevicePlatform.Desktop]: 1,
			[DevicePlatform.Mobile]: 2,
			[DevicePlatform.Tablet]: 1.85,
			baseScale: 1,
			...modifyWith,
		},
		new Vector3(1920, 1080),
	);
}


import type { LogConfig } from "@rbxts/rbxts-sleitnick-log";

const logConfiguration: LogConfig = {
	Default: "Warning",
	Development: {
		Client: "Warning",
		PlaceIds: [],
		Server: "Warning",
	},
	Studio: "Debug",
};

export = logConfiguration;


//!optimize 2

import type { ErrorBoundaryContextType } from "./error-boundary-context";
import { t } from "@rbxts/t";

const isErrorBoundaryContext = t.interface({
	didCatch: t.boolean,
	resetErrorBoundary: t.callback,
}) as t.check<ErrorBoundaryContextType>;

export function assertErrorBoundaryContext(value: unknown): ErrorBoundaryContextType {
	assert(isErrorBoundaryContext(value), "ErrorBoundaryContext not found");
	return value;
}

export default assertErrorBoundaryContext;


//!optimize 2

import React from "@rbxts/react";

export interface ErrorBoundaryContextType {
	readonly didCatch: boolean;
	readonly error: unknown;
	readonly resetErrorBoundary: Callback;
}

export const ErrorBoundaryContext = React.createContext<ErrorBoundaryContextType | undefined>(undefined);
export default ErrorBoundaryContext;


--!optimize 2
--!strict

return function(object: any)
	return type(object) == "table" and object["$$typeof"] == 0xeac7
end


//!optimize 2
/* eslint-disable unicorn/prefer-export-from */

import LuauPolyfill from "@rbxts/luau-polyfill";
import ReactPackage from "@rbxts/react";

export const React = ReactPackage;
export { LuauPolyfill };


--!optimize 2

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TS = require(ReplicatedStorage:WaitForChild("rbxts_include"):WaitForChild("RuntimeLib"))
local Log = TS.import(
	script,
	ReplicatedStorage,
	"rbxts_include",
	"node_modules",
	"@rbxts",
	"rbxts-sleitnick-log",
	"out"
).default

local log = Log.new()
local function concat(...: unknown)
	local length = select("#", ...)
	if length == 0 then
		return ""
	end

	if length == 1 then
		return tostring(...)
	end

	if length == 2 then
		local first, second = ...
		return tostring(first) .. " " .. tostring(second)
	end

	if length == 3 then
		local first, second, third = ...
		return tostring(first) .. " " .. tostring(second) .. " " .. tostring(third)
	end

	local array = table.create(length)
	for index = 1, length do
		array[index] = tostring(select(index, ...))
	end

	return table.concat(array, " ")
end

local function catchFactory(functionName: string, logFunction: nil | (...any) -> ())
	local trueLogFunction: (...any) -> () = if logFunction then logFunction else log.Warning
	return function(...)
		trueLogFunction(string.format("Error in function %*: %*", functionName, concat(...)))
	end
end

return catchFactory


--!nonstrict
--!optimize 2

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TS = require(ReplicatedStorage:WaitForChild("rbxts_include"):WaitForChild("RuntimeLib"))
return TS.Promise.all


--!nonstrict
--!optimize 2

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TS = require(ReplicatedStorage:WaitForChild("rbxts_include"):WaitForChild("RuntimeLib"))
local Promise = TS.Promise

local function Pack(...)
	return {...}
end

local function disconnectIt(connection)
	if type(connection) == "function" then
		connection()
	elseif type(connection) == "table" then
		if type(connection.Disconnect) == "function" then
			connection:Disconnect()
		elseif type(connection.disconnect) == "function" then
			connection:disconnect()
		end
	elseif typeof(connection) == "RBXScriptConnection" then
		connection:Disconnect()
	end
end

local BASIC_CONNECTION = {
	Disconnect = function() end;
}

local function connectIt(event, callback)
	local pascalConnect = event.Connect
	if pascalConnect then
		assert(type(pascalConnect) == "function", "not a function")
		return pascalConnect(event, callback)
	end

	local camelConnect = event.connect
	if camelConnect then
		assert(type(camelConnect) == "function", "not a function")
		return camelConnect(event, callback)
	end

	return BASIC_CONNECTION
end

local function fromEvent(event, predicate)
	predicate = predicate or function()
		return true
	end

	return Promise._new(debug.traceback(nil, 2), function(resolve, _, onCancel)
		local connection
		local shouldDisconnect = false

		local function disconnect()
			disconnectIt(connection)
			connection = nil
		end

		-- We use shouldDisconnect because if the callback given to Connect is called before
		-- Connect returns, connection will still be nil. This happens with events that queue up
		-- events when there's nothing connected, such as RemoteEvents

		connection = connectIt(event, function(...)
			local callbackValue = predicate(...)

			if callbackValue == true then
				resolve(...)

				if connection then
					disconnect()
				else
					shouldDisconnect = true
				end
			elseif type(callbackValue) ~= "boolean" then
				error("Promise.fromEvent predicate should always return a boolean")
			end
		end)

		if shouldDisconnect and connection then
			disconnect()
			return
		end

		onCancel(disconnect)
	end)
end

return function(...)
	return fromEvent(...):andThen(Pack)
end


--!nonstrict
--!optimize 2

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TS = require(ReplicatedStorage:WaitForChild("rbxts_include"):WaitForChild("RuntimeLib"))
local Promise = TS.Promise

local ERROR_NON_FUNCTION = "Please pass a handler function to %*!"

local function isCallable(value)
	if type(value) == "function" then
		return true
	end

	if type(value) == "table" then
		local metatable = getmetatable(value)
		if metatable and type(rawget(metatable, "__call")) == "function" then
			return true
		end
	end

	return false
end

local function createTapper(callback, isError)
	return if isError
		then function(...)
			local callbackReturn = callback(...)

			if Promise.is(callbackReturn) then
				local values = table.pack(...)
				return callbackReturn:andThen(function()
					return Promise.reject(table.unpack(values, 1, values.n))
				end)
			end

			return Promise.reject(...)
		end
		else function(...)
			local callbackReturn = callback(...)

			if Promise.is(callbackReturn) then
				local values = table.pack(...)
				return callbackReturn:andThen(function()
					return table.unpack(values, 1, values.n)
				end)
			end

			return ...
		end
end

local function tapWithCatch(self, tapCallback, tapCatch)
	assert(isCallable(tapCallback), string.format(ERROR_NON_FUNCTION, "tapWithCatch"))
	assert(tapCatch == nil or isCallable(tapCatch), string.format(ERROR_NON_FUNCTION, "tapWithCatch"))
	tapCallback = createTapper(tapCallback, false)

	if tapCatch then
		return self:_andThen(debug.traceback(nil :: any, 2), tapCallback, createTapper(tapCatch, true))
	end

	return self:_andThen(debug.traceback(nil :: any, 2), tapCallback)
end

return tapWithCatch


//!optimize 2

import DevicePlatform from "../meta/device-platform";
import { GuiService, UserInputService, Workspace } from "@rbxts/services";

const [TOP_LEFT, BOTTOM_RIGHT] = GuiService.GetGuiInset();

export function getViewportSize(): Vector2 {
	const currentCamera = Workspace.CurrentCamera;
	return currentCamera?.ViewportSize ?? Vector2.zero;
}

export function getViewportSizeWithInset(): Vector2 {
	const currentCamera = Workspace.CurrentCamera;
	return (currentCamera?.ViewportSize ?? new Vector2(1280, 720)).sub(TOP_LEFT).sub(BOTTOM_RIGHT);
}

export function getDevicePlatform(): DevicePlatform {
	if (UserInputService.GamepadEnabled && GuiService.IsTenFootInterface()) return DevicePlatform.Console;

	if (UserInputService.TouchEnabled) {
		const currentCamera = Workspace.CurrentCamera;
		const viewportSize = currentCamera?.ViewportSize ?? Vector2.zero;
		return viewportSize.X >= 1023 && viewportSize.Y >= 767 ? DevicePlatform.Tablet : DevicePlatform.Mobile;
	}

	return UserInputService.KeyboardEnabled ? DevicePlatform.Desktop : DevicePlatform.Unknown;
}


/// <reference types="@rbxts/types/plugin" />
//!optimize 2

import { RunService } from "@rbxts/services";

function getNetworkClient(): NetworkClient | undefined {
	return game.FindService("NetworkClient") as NetworkClient | undefined;
}
function getClientReplicator(networkClient: NetworkClient): ClientReplicator | undefined {
	return networkClient.FindFirstChildOfClass("ClientReplicator");
}
function hasClientReplicator(): boolean {
	const [serviceSuccess, networkClient] = pcall(getNetworkClient);
	if (!serviceSuccess || !networkClient) return false;

	const [findSuccess, clientReplicator] = pcall(getClientReplicator, networkClient);
	return findSuccess && clientReplicator !== undefined;
}

export default function isTrulyStudio(): boolean {
	if (!RunService.IsStudio()) return false;
	if (!RunService.IsRunning() && hasClientReplicator()) return true;
	return !RunService.IsRunning() && RunService.IsClient() && RunService.IsServer();
}


//!native
//!optimize 2

import { LFUCache, LRUCache } from "@rbxts/data-structures";

export function memoize<T, U>(memoizeFunction: (index: T) => U): (index: T) => U {
	const cache = new Map<T, U>();

	function memoized(index: T): U {
		const cached = cache.get(index);
		if (cached !== undefined) return cached;

		const result = memoizeFunction(index);
		cache.set(index, result);
		return result;
	}

	return memoized;
}

export function memoizeMemorySafe<T, U extends defined>(
	memoizeFunction: (index: T) => U,
	capacity = 15,
): (index: T) => U {
	const cache = new LFUCache<T, U>(capacity);

	function memoized(index: T): U {
		const cached = cache.get(index);
		if (cached !== undefined) return cached;

		const result = memoizeFunction(index);
		cache.set(index, result);
		return result;
	}

	return memoized;
}

export function memoizeMemorySafeRecent<T extends defined, U extends defined>(
	memoizeFunction: (index: T) => U,
	capacity = 15,
): (index: T) => U {
	const cache = new LRUCache<T, U>(capacity);

	function memoized(index: T): U {
		const cached = cache.get(index);
		if (cached !== undefined) return cached;

		const result = memoizeFunction(index);
		cache.set(index, result);
		return result;
	}

	return memoized;
}


//!optimize 2

import { stableLerp } from "../primitives/number-utilities";
import { type Binding, createBinding, joinBindings } from "@rbxts/react";
import type { BindingOrValue } from "types/react-types";

export interface BindingApi<T> {
	readonly getValue: () => T;
	readonly subscribe: (callback: (newValue: T) => void) => () => void;
	readonly update: (newValue: T) => void;
}

export interface Lerpable<T> {
	readonly Lerp: (this: T, to: T, alpha: number) => T;
}

type Bindable<T = unknown> = Binding<T> | NonNullable<T>;

type ComposeBindings<T extends Array<Bindable>> = {
	readonly [K in keyof T]: T[K] extends Bindable<infer U> ? U : T[K];
};

type BindingCombiner<T extends Array<Bindable>, U> = (...values: ComposeBindings<T>) => U;

/**
 * Returns whether the given value is a binding.
 * @param value The value to check.
 * @returns Whether the value is a binding.
 */
export function isBinding<T>(value: Binding<T> | T): value is Binding<T>;
export function isBinding<T = unknown>(value: unknown): value is Binding<T>;
export function isBinding(value: unknown): value is Binding<unknown> {
	return typeIs(value, "table") && "getValue" in value && "map" in value;
}

/**
 * Converts a value to a binding. If the given value is already a binding, it
 * will be returned as-is.
 * @param value The value to convert.
 * @returns The converted binding.
 */
export function toBinding<T>(value: Binding<T> | T): Binding<T> {
	if (isBinding(value)) return value;

	const [result] = createBinding(value);
	return result;
}

/**
 * Returns the value of a binding. If the given value is not a binding, it will
 * be returned as-is.
 * @param binding The binding to get the value of.
 * @returns The value of the binding.
 */
export function getBindingValue<T>(binding: Binding<T> | T): T {
	return isBinding(binding) ? binding.getValue() : binding;
}

/**
 * Maps a binding to a new binding. If the given value is not a binding, it will
 * be passed to the mapper function and returned as a new binding.
 * @param binding The binding to map.
 * @param callback The mapper function.
 * @returns The mapped binding.
 */
export function mapBinding<T, U>(binding: Binding<T> | T, callback: (value: T) => U): Binding<U> {
	if (isBinding(binding)) return binding.map(callback);

	const [result] = createBinding(callback(binding as T));
	return result;
}

/**
 * Joins a map of bindings into a single binding. If any of the given values
 * are not bindings, they will be wrapped in a new binding.
 * @param bindings The bindings to join.
 * @returns The joined binding.
 */
export function joinAnyBindings<T extends Readonly<Record<string, unknown>>>(
	bindings: T,
): Binding<{ [K in keyof T]: T[K] extends BindingOrValue<infer U> ? U : T[K] }>;
export function joinAnyBindings<T extends ReadonlyArray<unknown>>(
	bindings: readonly [...T],
): Binding<{ [K in keyof T]: T[K] extends BindingOrValue<infer U> ? U : T[K] }>;
export function joinAnyBindings(bindings: object): Binding<unknown> {
	const bindingsToMap = {} as Record<number | string, Binding<unknown>>;
	for (const [k, v] of pairs(bindings)) bindingsToMap[k as keyof object] = toBinding(v);
	return joinBindings(bindingsToMap);
}

/**
 * Gets the internal API of a binding. This is a hacky way to get access to the
 * `BindingInternalApi` object of a binding, which is not exposed by React.
 * @param binding The binding to get the internal API of.
 * @returns The binding's API.
 */
export function getBindingApi<T>(binding: Binding<T>): BindingApi<T> | undefined {
	for (const [key, value] of pairs(binding)) {
		const name = `${key}`;
		if (name === "Symbol(BindingImpl)" || name.sub(1, 12) === "RoactBinding")
			return value as unknown as BindingApi<T>;
	}

	return undefined;
}

/**
 * Returns a binding that lerps between two values using the given binding as
 * the alpha.
 * @param binding The binding to use as the alpha.
 * @param from The value to lerp from.
 * @param to The value to lerp to.
 * @returns A binding that lerps between two values.
 */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function lerpBinding<T extends Lerpable<any> | number>(
	binding: Binding<number> | number,
	from: T,
	to: T,
): Binding<T> {
	return mapBinding(binding, (alpha) =>
		typeIs(from, "number") ? stableLerp(from, to as number, alpha) : from.Lerp(to, alpha),
	);
}

/**
 * Composes multiple bindings or values together into a single binding.
 * Calls the combiner function with the values of the bindings when any
 * of the bindings change.
 * @param ...bindings A list of bindings or values.
 * @param combiner The function that maps the bindings to a new value.
 * @returns A binding that returns the result of the combiner.
 */
export function composeBindings<T extends Array<Bindable>, U>(...bindings: [...T, BindingCombiner<T, U>]): Binding<U>;

export function composeBindings<T>(
	...values: [...ReadonlyArray<Bindable>, BindingCombiner<Array<Bindable>, T>]
): Binding<T> {
	const combiner = values.pop() as BindingCombiner<Array<Bindable>, T>;
	const bindings = values.map(toBinding);

	return joinBindings(bindings).map((bindings) => combiner(...bindings));
}


//!optimize 2

import type { Storybook } from "@rbxts/ui-labs";

const SharedStorybook: Storybook = {
	groupRoots: true,
	name: "Shared",
	storyRoots: [script.Parent!.FindFirstChild("__stories__")!],
};

export = SharedStorybook;


local fs = require("@lune/fs")
local roblox = require("@lune/roblox")

local placeFile = fs.readFile("place.rbxl")
local gameFile = roblox.deserializePlace(placeFile)

local Packages = gameFile.ReplicatedStorage.Packages
local packageModel = roblox.serializeModel({Packages})
fs.writeFile("Inputter.rbxm", packageModel)


local UserInputService = game:GetService("UserInputService")

local Signal = require(script.Parent.Parent.Signal)
local Types = require(script.Parent.Types)

type Binding = Types.Binding
type BindingInfo = Types.BindingInfo

local Binding = {}
Binding.__index = Binding

local function matchesKeyboardInput(input: any, userInput: InputObject): boolean
	if input.EnumType == Enum.UserInputType then
		return input == userInput.UserInputType
	elseif input.EnumType == Enum.KeyCode then
		return input == userInput.KeyCode
	end
	return false
end

-- Constructor for Binding class
function Binding.new(BindingInfo: BindingInfo): Binding
	local self = setmetatable({}, Binding)
	local input = BindingInfo.Input or error("Input not provided")
	if BindingInfo.IgnoreGameProcessedEvent == nil then
		BindingInfo.IgnoreGameProcessedEvent = true
	end

	self.Input = input
	self.IgnoreGameProcessedEvent = BindingInfo.IgnoreGameProcessedEvent
	self.Pressed = false
	self.OnActivated = Signal.new()
	self.OnDeactivated = Signal.new()
	self._connections = {}
	self:_setup()

	return self
end

-- Function called when the binding is pressed
function Binding:_pressed(...)
	self.Pressed = true
	self.OnActivated:Fire(...)
end

-- Function called when the binding is released
function Binding:_released(...)
	self.Pressed = false
	self.OnDeactivated:Fire(...)
end

-- Initialise the connections for the object.
-- Shouldn't be called by any user.
function Binding:_setup()
	if typeof(self.Input) == "Instance" and self.Input:IsA("GuiButton") then
		local connection1 = self.Input.InputBegan:Connect(function(input)
			if input.UserInputState == Enum.UserInputState.Begin then
				self:_pressed(input)
			end
		end)
		local connection2 = self.Input.InputEnded:Connect(function(input)
			if input.UserInputState == Enum.UserInputState.End then
				self:_released(input)
			end
		end)
		table.insert(self._connections, connection1)
		table.insert(self._connections, connection2)
	elseif typeof(self.Input) == "EnumItem" then
		local connection1 = UserInputService.InputBegan:Connect(function(input, gameProcessedEvent)
			if not self.IgnoreGameProcessedEvent then
				if gameProcessedEvent then
					return
				end
			end
			if matchesKeyboardInput(self.Input, input) then
				self:_pressed(input, gameProcessedEvent)
			end
		end)
		local connection2 = UserInputService.InputEnded:Connect(function(input, gameProcessedEvent)
			if not self.IgnoreGameProcessedEvent then
				if gameProcessedEvent then
					return
				end
			end
			if matchesKeyboardInput(self.Input, input) then
				self:_released(input, gameProcessedEvent)
			end
		end)
		table.insert(self._connections, connection1)
		table.insert(self._connections, connection2)
	else
		error("Unsupported input type: " .. tostring(self.Input))
	end
end

-- Destroy the object
function Binding:Destroy()
	self.OnActivated:Destroy()
	self.OnDeactivated:Destroy()
	for i = #self._connections, 1, -1 do
		local connection = self._connections[i]
		if connection then
			connection:Disconnect()
			table.remove(self._connections, i)
		end
	end
	self._connections = nil
end

return Binding


local TableUtil = require(script.Parent.Parent.TableUtil)
local HttpService = game:GetService("HttpService")

local Serializer = {}

local function serializeEnums(tbl: any): boolean
	if type(tbl) ~= "table" then
		return false
	end
	for key, value in pairs(tbl) do
		if type(value) == "table" then
			if not serializeEnums(value) then
				return false
			end
		elseif type(value) == "function" or type(value) == "userdata" then
			tbl[key] = tostring(value)
		end
	end
	return true
end

local function deserializeEnums(tbl: any): boolean
	if type(tbl) ~= "table" then
		return false
	end
	for key, value in pairs(tbl) do
		if type(value) == "table" then
			if not deserializeEnums(value) then
				return false
			end
		elseif type(value) == "string" and value:match("^Enum%.") then
			local rootEnums = Enum:GetEnums()
			for _, enum: Enum in pairs(rootEnums) do
				for _, enumItem in pairs(enum:GetEnumItems()) do
					if tostring(enumItem) == value then
						tbl[key] = enumItem
						break
					end
				end
			end
		end
	end
	return true
end

Serializer.encode = function(tbl: any): string
	tbl = TableUtil.Copy(tbl, true)
	serializeEnums(tbl)
	return HttpService:JSONEncode(tbl)
end

Serializer.decode = function(json: string): any
	local tbl = HttpService:JSONDecode(json)
	if not deserializeEnums(tbl) then
		error("Failed to deserialize enums in JSON: " .. json)
	end
	return tbl
end

return Serializer


--[=[
    @class AbstractTrigger
    @ignore
    A base class for triggers. This should not be used directly, but rather as a base class for other input triggers.
]=]
local AbstractTrigger = {}
AbstractTrigger.__index = AbstractTrigger

local Signal = require(script.Parent.Parent.Parent.Signal)
local TableUtil = require(script.Parent.Parent.Parent.TableUtil)
local Types = require(script.Parent.Parent.Types)
type Trigger = Types.Trigger

--[=[
	@return Trigger -- The new AbstractTrigger object.
]=]
function AbstractTrigger.new(concreteType: string, ...: any): Trigger
	local self = setmetatable({}, AbstractTrigger)
	--[=[
        @within AbstractTrigger
        @private
        @prop OnActivated Signal -- The signal that is fired when the trigger is activated.
    ]=]
	self.OnActivated = Signal.new()
	--[=[
        @within AbstractTrigger
        @private
        @prop OnDeactivated Signal -- The signal that is fired when the trigger is deactivated.
    ]=]
	self.OnDeactivated = Signal.new()

	self.ConstructorArgs = TableUtil.Copy({ ... }, true)
	self.ConcreteType = concreteType or error("Concrete type must be provided")
	return self
end

--[=[
    @function _activated
    @private
    @within AbstractTrigger
    Fires the OnActivated signal.
]=]
function AbstractTrigger:_activated(...)
	self.OnActivated:Fire(...)
end

--[=[
    @function _deactivated
    @private
    @within AbstractTrigger
    Fires the OnDeactivated signal.
]=]
function AbstractTrigger:_deactivated(...)
	self.OnDeactivated:Fire(...)
end

--[=[
    @function _serialize
    @private
    @within AbstractTrigger
    Converts the trigger to a table representation, for serialization purposes.
]=]
function AbstractTrigger:_serialize(): { Type: string, Arguments: { any } }
	local tbl = {
		Type = self.ConcreteType,
		Arguments = self.ConstructorArgs,
	}
	return TableUtil.Copy(tbl, true)
end

return AbstractTrigger


--[[
    A form of input handler that triggers when the input is held for a specified duration.
    Author: Adam Mills
]]
local AbstractTrigger = require(script.Parent.AbstractTrigger)
local Types = require(script.Parent.Parent.Types)
local Binding = require(script.Parent.Parent.Binding)

type HOLD = Types.HOLD
type BindingInfo = Types.BindingInfo

--[=[
	@class HOLD
	A type of trigger that fires when the given input is held for a specified duration.
]=]
local HOLD = setmetatable({}, AbstractTrigger)
HOLD.__index = HOLD

--[=[
	@param BindingInfo BindingInfo -- The binding information for the input. The input index must be only a single input method (i.e. Enum.KeyCode, Enum.UserInputType, or GuiButton).
	@param HoldTime number -- The duration (in seconds) the input must be held before triggering.
	@return HOLD -- The new HOLD object.
]=]
function HOLD.new(BindingInfo: BindingInfo, HoldTime: number): HOLD
	local self = setmetatable(AbstractTrigger.new(script.Name, BindingInfo, HoldTime), HOLD)
	self.Binding = Binding.new(BindingInfo)
	self.HoldTime = HoldTime or 1.0 -- Default to 1 second if not specified
	self._active = false
	self._holdTimer = nil
	self:_setup()
	return self
end

-- Initialise the connections for the object.
function HOLD:_setup()
	local RunService = game:GetService("RunService")

	self._connectionActivated = self.Binding.OnActivated:Connect(function(...)
		local args = { ... }
		if not self._active then
			-- Start the hold timer
			local startTime = tick()
			self._holdTimer = RunService.Heartbeat:Connect(function()
				if tick() - startTime >= self.HoldTime then
					-- Hold time reached, activate
					self._active = true
					self:_activated(table.unpack(args))
					if self._holdTimer then
						self._holdTimer:Disconnect()
						self._holdTimer = nil
					end
				end
			end)
		end
	end)

	self._connectionDeactivated = self.Binding.OnDeactivated:Connect(function(...)
		local args = { ... }
		-- Input released before hold time - cancel the timer
		if self._holdTimer then
			self._holdTimer:Disconnect()
			self._holdTimer = nil
		end

		-- If we were active, deactivate
		if self._active then
			self._active = false
			self:_deactivated(table.unpack(args))
		end
	end)
end

-- Destroy the input handler
function HOLD:Destroy()
	-- Clean up the hold timer
	if self._holdTimer then
		self._holdTimer:Disconnect()
		self._holdTimer = nil
	end

	if self._connectionActivated then
		self._connectionActivated:Disconnect()
		self._connectionActivated = nil
	end
	if self._connectionDeactivated then
		self._connectionDeactivated:Disconnect()
		self._connectionDeactivated = nil
	end
	if self.Binding then
		self.Binding:Destroy()
		self.Binding = nil
	end
end

return HOLD :: HOLD


local AbstractTrigger = require(script.Parent.AbstractTrigger)
local Types = require(script.Parent.Parent.Types)
local Binding = require(script.Parent.Parent.Binding)

type MULTIPLE_PRESS = Types.MULTIPLE_PRESS
type BindingInfo = Types.BindingInfo
type Trigger = Types.Trigger

local MULTIPLE_PRESS = setmetatable({}, AbstractTrigger)
MULTIPLE_PRESS.__index = MULTIPLE_PRESS

--[=[
	@class MULTIPLE_PRESS
	A type of trigger that fires when the given input is pressed PressCount times within a time frame of TimeFrame seconds.
]=]
--[=[
	@param BindingInfo BindingInfo -- The binding information for the input. The input index must be only a single input method (i.e. Enum.KeyCode, Enum.UserInputType, or GuiButton).
	@param PressCount number -- The number of times the input must be pressed to trigger the action. Default is 2.
	@param TimeFrame number -- The time frame in seconds within which the input must be pressed. Default is 0.5 seconds.
	@return Input -- The new MULTIPLE_PRESS object.
]=]
function MULTIPLE_PRESS.new(BindingInfo: BindingInfo, PressCount: number, TimeFrame: number): Trigger
	local self = setmetatable(AbstractTrigger.new(script.Name, BindingInfo, PressCount, TimeFrame), MULTIPLE_PRESS)

	self.Binding = Binding.new(BindingInfo)
	self._MaxPresses = PressCount or warn("PressCount not provided, defaulting to 2") and 2
	self._PressWindow = TimeFrame or warn("TimeFrame not provided, defaulting to 0.5") and 0.5
	self._pressCount = 0
	self._firstPressTime = 0
	self._active = false
	self:_setup()
	return self
end

-- Initialise the connections for the object.
-- Shouldn't be called by any user.
function MULTIPLE_PRESS:_setup()
	self._connectionActivated = self.Binding.OnActivated:Connect(function(...)
		if tick() - self._firstPressTime > self._PressWindow then
			self._pressCount = 0
		end
		if self._pressCount == 0 then
			self._firstPressTime = tick()
		end
		self._pressCount += 1
		if self._pressCount == self._MaxPresses then
			self._pressCount = 0
			self._active = true
			self:_activated(...)
		end
	end)
	self._connectionDeactivated = self.Binding.OnDeactivated:Connect(function(...)
		if self._active then
			self._active = false
			self:_deactivated(...)
		end
	end)
end

-- Destroy the input handler
function MULTIPLE_PRESS:Destroy()
	if self._connectionActivated then
		self._connectionActivated:Disconnect()
		self._connectionActivated = nil
	end
	if self._connectionDeactivated then
		self._connectionDeactivated:Disconnect()
		self._connectionDeactivated = nil
	end
	if self.Binding then
		self.Binding:Destroy()
		self.Binding = nil
	end
end

return MULTIPLE_PRESS :: MULTIPLE_PRESS


--[[
    Most basic form of input handler. Triggers when the input is pressed.
    Author: Adam Mills
]]
local AbstractTrigger = require(script.Parent.AbstractTrigger)
local Types = require(script.Parent.Parent.Types)
local Binding = require(script.Parent.Parent.Binding)

type PRESS = Types.PRESS
type BindingInfo = Types.BindingInfo

--[=[
	@class PRESS
	A type of trigger that fires when the given input is pressed.
]=]
local PRESS = setmetatable({}, AbstractTrigger)
PRESS.__index = PRESS

--[=[
	@param BindingInfo BindingInfo -- The binding information for the input. The input index must be only a single input method (i.e. Enum.KeyCode, Enum.UserInputType, or GuiButton).
	@return Input -- The new PRESS object.
]=]
function PRESS.new(BindingInfo: BindingInfo): PRESS
	local self = setmetatable(AbstractTrigger.new(script.Name, BindingInfo), PRESS)
	self.Binding = Binding.new(BindingInfo)
	self._active = false
	self:_setup()
	return self
end

-- Initialise the connections for the object.
function PRESS:_setup()
	self._connectionActivated = self.Binding.OnActivated:Connect(function(...)
		if not self._active then
			self._active = true
			self:_activated(...)
		end
	end)
	self._connectionDeactivated = self.Binding.OnDeactivated:Connect(function(...)
		if self._active then
			self._active = false
			self:_deactivated(...)
		end
	end)
end

-- Destroy the input handler
function PRESS:Destroy()
	if self._connectionActivated then
		self._connectionActivated:Disconnect()
		self._connectionActivated = nil
	end
	if self._connectionDeactivated then
		self._connectionDeactivated:Disconnect()
		self._connectionDeactivated = nil
	end
	if self.Binding then
		self.Binding:Destroy()
		self.Binding = nil
	end
end

return PRESS :: PRESS


--[[
    Input handler that triggers when the input is pressed and released within a given time frame.
    Author: Adam Mills
]]
local AbstractTrigger = require(script.Parent.AbstractTrigger)
local Types = require(script.Parent.Parent.Types)
local Binding = require(script.Parent.Parent.Binding)

type SHORT_PRESS = Types.SHORT_PRESS
type BindingInfo = Types.BindingInfo

--[=[
	@class SHORT_PRESS
	A type of trigger that fires when the given input is pressed and released within a specified time frame.
]=]
local SHORT_PRESS = setmetatable({}, AbstractTrigger)
SHORT_PRESS.__index = SHORT_PRESS

--[=[
	@param BindingInfo BindingInfo -- The binding information for the input. The input index must be only a single input method (i.e. Enum.KeyCode, Enum.UserInputType, or GuiButton).
	@param MaxPressTime number -- The maximum duration (in seconds) the input can be held to still be considered a short press.
	@return SHORT_PRESS -- The new SHORT_PRESS object.
]=]
function SHORT_PRESS.new(BindingInfo: BindingInfo, MaxPressTime: number): SHORT_PRESS
	local self = setmetatable(AbstractTrigger.new(script.Name, BindingInfo, MaxPressTime), SHORT_PRESS)
	self.Binding = Binding.new(BindingInfo)
	self.MaxPressTime = MaxPressTime or error("MaxPressTime must be specified and greater than 0")
	self._pressStartTime = nil
	self._isPressed = false
	self:_setup()
	return self
end

-- Initialise the connections for the object.
function SHORT_PRESS:_setup()
	self._connectionActivated = self.Binding.OnActivated:Connect(function()
		if not self._isPressed then
			-- Record when the press started
			self._pressStartTime = tick()
			self._isPressed = true
		end
	end)

	self._connectionDeactivated = self.Binding.OnDeactivated:Connect(function(...)
		local args = { ... }
		if self._isPressed and self._pressStartTime then
			local pressDuration = tick() - self._pressStartTime

			-- Check if it was a short press
			if pressDuration <= self.MaxPressTime then
				-- It's a short press - activate the trigger
				self:_activated(table.unpack(args))
			end

			-- Reset state
			self._isPressed = false
			self._pressStartTime = nil
		end
	end)
end

-- Destroy the input handler
function SHORT_PRESS:Destroy()
	if self._connectionActivated then
		self._connectionActivated:Disconnect()
		self._connectionActivated = nil
	end
	if self._connectionDeactivated then
		self._connectionDeactivated:Disconnect()
		self._connectionDeactivated = nil
	end
	if self.Binding then
		self.Binding:Destroy()
		self.Binding = nil
	end

	-- Reset state
	self._isPressed = false
	self._pressStartTime = nil
end

return SHORT_PRESS :: SHORT_PRESS


local Signal = require(script.Parent.Parent.Signal)

export type Signal<T...> = Signal.Signal<T...>

--[=[
	@class Inputter
	The inputter class represents each individual action a player can make. It should be used to abstract away from the different input methods ROBLOX provides.
]=]
export type Inputter = {
	Name: string,
	Active: boolean,
	Enabled: boolean,
	ActiveTriggers: { Trigger }, -- The triggers that are currently active. This is used to determine if the inputter is active or not.
	OnActivated: Signal.Signal<() -> ()>, -- The signal that is fired when the inputter is activated.
	OnDeactivated: Signal.Signal<() -> ()>, -- The signal that is fired when the inputter is deactivated.

	new: (name: string, inputs: { Trigger }) -> Inputter,
	AddInput: (self: Inputter, input: Trigger) -> (),
	RemoveInput: (self: Inputter, input: Trigger) -> (),
	GetAllInputs: (self: Inputter) -> { Trigger },
	IsActive: (self: Inputter) -> boolean,
	Enable: (self: Inputter) -> (),
	Disable: (self: Inputter) -> (),
	Destroy: (self: Inputter) -> (),
	Serialize: (self: Inputter) -> string, -- Serializes the inputter to a string.
	Deserialize: (self: Inputter, serialized: string) -> Inputter, -- Rebuilds an inputter from a serialized string.
}

--[=[
	@interface BindingInfo
	.Input Enum.KeyCode | Enum.UserInputType | GuiButton | {Enum.KeyCode | Enum.UserInputType | GuiButton} -- The input that will trigger the binding. Whether this is a table or single input is contextual on the trigger being constructed.
	@within Inputter
	.IgnoreGameProcessedEvent boolean? -- By default this value is false, and inputs already processed by the game (such as when interacting with GUI) are ignored. If this flag is set to true the inputter will be triggered regardless of the context of the input.
]=]
export type BindingInfo = {
	Input: Enum.KeyCode | Enum.UserInputType | GuiButton | { Enum.KeyCode | Enum.UserInputType | GuiButton },
	IgnoreGameProcessedEvent: boolean?,
}

export type Binding = {
	Input: Enum.KeyCode | Enum.UserInputType | GuiButton,
	Pressed: boolean,
	Destroy: (self: Binding) -> (),
	new: (BindingInfo: BindingInfo) -> Binding,
}

export type Trigger = {
	OnActivated: Signal.Signal<() -> ()>,
	OnDeactivated: Signal.Signal<() -> ()>,
	_serialize: (self: Trigger) -> { Type: string, Arguments: { any } },
}
export type MULTIPLE_PRESS = Trigger & {
	new: (BindingInfo: BindingInfo, PressCount: number, TimeFrame: number) -> Trigger,
}
export type PRESS = Trigger & {
	new: (BindingInfo: BindingInfo) -> Trigger,
}
export type HOLD = Trigger & {
	new: (BindingInfo: BindingInfo, HoldTime: number) -> Trigger,
}
export type SHORT_PRESS = Trigger & {
	new: (BindingInfo: BindingInfo, MaxPressTime: number?) -> Trigger,
}

return {}


if not isfolder("CAMS") then
	makefolder("CAMS")
end

local Plugin = {
	PluginName = "Cam Maker v1.2",
	PluginDescription = "CamMaker but better!",
	Commands = {
		makecam = {
			ListName = "makecam / mc [Name]",
			Description = "Creates a camera to view.",
			Aliases = { "mc" },
			Function = function(args, speaker)
				local CamDir = "CAMS\\" .. getstring(1)
				local HRP = game:GetService("Players").LocalPlayer.Character.HumanoidRootPart
				makefolder(CamDir)
				writefile(CamDir .. "\\X.txt", HRP.CFrame.X)
				writefile(CamDir .. "\\Y.txt", HRP.CFrame.Y)
				writefile(CamDir .. "\\Z.txt", HRP.CFrame.Z)
				notify("CamMaker", "Camera successfully created!")
			end,
		},
		viewcam = {
			ListName = "viewcam / vc [Name]",
			Description = "Views a camera.",
			Aliases = { "vc" },
			Function = function(args, speaker)
				if not isfolder("CAMS\\" .. getstring(1)) then
					notify("CamMaker", "Camera not found.")
				else
					local TempDir = "CAMS\\" .. getstring(1)
					local TempPart = Instance.new("Part")
					TempPart.CanCollide = false
					TempPart.Transparency = 1
					TempPart.Anchored = true
					TempPart.CFrame = CFrame.new(
						Vector3.new(
							readfile(TempDir .. "\\X.txt"),
							readfile(TempDir .. "\\Y.txt"),
							readfile(TempDir .. "\\Z.txt")
						)
					)
					math.randomseed(os.time())
					TempPart.Name = math.random(0, 99999)
					TempPart.Parent = game:GetService("Workspace")
					writefile("CAMS\\CurrentCamName.txt", TempPart.Name)
					game.Workspace.Camera.CameraSubject = TempPart
				end
			end,
		},
		delcam = {
			ListName = "delcam / dc [Name]",
			Description = "Deletes a camera.",
			Aliases = { "dc" },
			Function = function(args, speaker)
				if not isfolder("CAMS\\" .. getstring(1)) then
					notify("CamMaker", "Camera not found.")
				else
					delfolder("CAMS\\" .. getstring(1))
				end
			end,
		},
		listcams = {
			ListName = "listcams / lc",
			Description = "Lists cameras.",
			Aliases = { "lc" },
			Function = function(args, speaker)
				local Items = ""
				for i, v in pairs(listfiles("CAMS")) do
					Items = Items .. ", " .. string.sub(v, 6)
				end
				notify("CamMaker", string.sub(Items, 3))
			end,
		},
		unviewcam = {
			ListName = "unviewcam / unvc",
			Description = "Return to original camera position.",
			Aliases = { "unvc" },
			Function = function(args, speaker)
				local TWS = game:GetService("Workspace")
				if TWS.Camera.CameraSubject ~= speaker then
					TWS.Camera.CameraSubject = speaker.Character
					local TempPartName = readfile("CAMS\\CurrentCamName.txt")
					TWS[TempPartName]:Destroy()
					delfile("CAMS\\CurrentCamName.txt")
				end
			end,
		},
	},
}
return Plugin


local Plugin = {
	["PluginName"] = "Fake Chat",
	["PluginDescription"] = "Be able to chat as anyone.",
	["Commands"] = {
		["fakechat"] = {
			["ListName"] = "fakechat / fchat [plr] [msg]",
			["Description"] = "Chat an string as the specified player.",
			["Aliases"] = { "fchat" },
			["Function"] = function(args, speaker)
				game:GetService("ReplicatedStorage").DefaultChatSystemChatEvents.SayMessageRequest:FireServer(
					utf8.char(11774):rep(27 + #game.Players.LocalPlayer.Name)
						.. "["
						.. args[1]
						.. "]"
						.. ": "
						.. args[2],
					"All"
				)
			end,
		},
	},
}

return Plugin


local Players = game:GetService("Players")
return {
	["PluginName"] = "Free Fall",
	["PluginDescription"] = "Scripted by NoobSploit#0001",
	["Commands"] = {
		["freefall"] = {
			["ListName"] = "freefall [height]",
			["Description"] = "FreeFalled",
			["Aliases"] = {},
			["Function"] = function(args, speaker)
				if not args[1] then
					return
				end
				local Height = getstring(1)
				Players.LocalPlayer.Character.HumanoidRootPart.CFrame = CFrame.new(
					Vector3.new(
						Players.LocalPlayer.Character.HumanoidRootPart.CFrame.X,
						Players.LocalPlayer.Character.HumanoidRootPart.CFrame.Y + Height,
						Players.LocalPlayer.Character.HumanoidRootPart.CFrame.Z
					)
				)
			end,
		},
		["bounce"] = {
			["ListName"] = "bounce [height]",
			["Description"] = "bounced",
			["Aliases"] = {},
			["Function"] = function(args, speaker)
				if not args[1] then
					return
				end
				local Height = getstring(1)
				Players.LocalPlayer.Character:FindFirstChildOfClass("Humanoid").RootPart.Velocity =
					Vector3.new(0, Height, 0)
			end,
		},
	},
}


local allowspeedmove = true
wait(1)

local c = workspace.CurrentCamera
local player = game.Players.LocalPlayer
local userInput = game:GetService("UserInputService")
local rs = game:GetService("RunService")
local starterPlayer = game:GetService("StarterPlayer")

local selected = false
local speed = 60
local lastUpdate = 0

local camera = Instance.new("Part", workspace)
camera.CanCollide = false
camera.Anchored = true
camera.Transparency = 1
camera.Name = "FreeCam"
camera.Position = player.Character.HumanoidRootPart.Position + Vector3.new(0, 5, 0)

c.Changed:connect(function(property)
	if property == "CoordinateFrame" then
		--		camSync:fire()
	end
end)

function getNextMovement(deltaTime)
	local nextMove = Vector3.new()
	-- Left/Right
	if userInput:IsKeyDown("A") or userInput:IsKeyDown("Left") then
		nextMove = nextMove + Vector3.new(-1, 0, 0)
	end
	if userInput:IsKeyDown("D") or userInput:IsKeyDown("Right") then
		nextMove = nextMove + Vector3.new(1, 0, 0)
	end
	-- Forward/Back
	if userInput:IsKeyDown("W") or userInput:IsKeyDown("Up") then
		nextMove = nextMove + Vector3.new(0, 0, -1)
	end
	if userInput:IsKeyDown("S") or userInput:IsKeyDown("Down") then
		nextMove = nextMove + Vector3.new(0, 0, 1)
	end
	-- Up/Down
	if userInput:IsKeyDown("Space") or userInput:IsKeyDown("E") then
		nextMove = nextMove + Vector3.new(0, 1, 0)
	end
	if userInput:IsKeyDown("Q") then
		nextMove = nextMove + Vector3.new(0, -1, 0)
	end
	return CFrame.new(nextMove * (speed * deltaTime))
end

function onSelected()
	local char = player.Character
	if char then
		local root = camera
		currentPos = root.Position
		selected = true
		lastUpdate = tick()
		c.CameraSubject = root
		player.Character.HumanoidRootPart.Anchored = true
		while selected do
			local delta = tick() - lastUpdate
			local look = (c.Focus.p - c.CoordinateFrame.p).unit
			local move = getNextMovement(delta)
			local pos = root.Position
			root.CFrame = CFrame.new(pos, pos + look) * move
			lastUpdate = tick()
			wait(0.01)
			--	camSync:wait()
		end
		player.Character.HumanoidRootPart.Anchored = false
		c.CameraSubject = player.Character.Humanoid
		root.Velocity = Vector3.new()
	end
end

function onDeselected()
	selected = false
end

local isOn = false

function onKeyPressed()
	isOn = not isOn
	if isOn then
		onSelected()
	else
		onDeselected()
	end
end

local mouse = player:GetMouse()
mouse.Button1Down:Connect(function()
	if allowspeedmove then
		speed = 120
	end
end)
mouse.Button1Up:Connect(function()
	speed = 60
end)

function ResetCamera()
	camera.Position = player.Character.HumanoidRootPart.Position + Vector3.new(0, 5, 0)
end

local Plugin = {
	["PluginName"] = "Freecam 2",
	["PluginDescription"] = "Another version of the IY Freecam",
	["Commands"] = {
		["freecam2"] = {
			["ListName"] = "freecam2 / fc2",
			["Description"] = "Note : Type command again to disable, Hold LeftClick to move faster",
			["Aliases"] = { "fc2" },
			["Function"] = function(args, speaker)
				onKeyPressed()
			end,
		},

		["resetcam2"] = {
			["ListName"] = "resetcam2 / rc2",
			["Description"] = "Reset Camera to Your Character",
			["Aliases"] = { "rc2" },
			["Function"] = function(args, speaker)
				ResetCamera()
			end,
		},
	},
}

return Plugin


return {
	["PluginName"] = "goto folder",
	["PluginDescription"] = "Go to a folder",
	["Commands"] = {
		["gotofolder"] = {
			["ListName"] = "gotofolder",
			["Description"] = "Made By D7M",
			["Aliases"] = {},
			["Function"] = function(args, speaker)
				for i, v in pairs(workspace:GetDescendants()) do
					if v.Name:lower() == getstring(1):lower() then
						local Children = v:GetChildren()
						for i = 1, math.random(1, #Children) do
							getRoot(speaker.Character).CFrame = Children[i].CFrame
						end
					end
				end
			end,
		},
	},
}


if not isfile("keybinds.keybinds") then
	keybinds = {}
else
	keybinds = game:GetService("HttpService"):JSONDecode(readfile("keybinds.keybinds"))
end

local event
event = game:GetService("Players").LocalPlayer:GetMouse().KeyDown:Connect(function(input)
	for i, v in pairs(keybinds) do
		if input:lower() == v.KEY and v.TOGGLE then
			execCmd(v.COMMAND_1 .. " " .. v.ARGUMENT_1, speaker)

			v.TOGGLE = false
		elseif input:lower() == v.KEY and not v.TOGGLE then
			execCmd(v.COMMAND_2 .. " " .. v.ARGUMENT_2, speaker)

			v.TOGGLE = true
		end
	end
end)

local Plugin = {
	["PluginName"] = "Keybinds v2",
	["PluginDescription"] = "Allows you to bind any commands and set them to toggle",
	["Commands"] = {
		["bind"] = {
			["ListName"] = "bind {key} {command} [argument] {command} [argument]",
			["Description"] = "Commands can have 1 optional arguments each",
			["Aliases"] = {},
			["Function"] = function(args, speaker)
				-- Ugly code incoming
				if #args == 3 then
					keybinds[#keybinds + 1] = {
						KEY = args[1],
						COMMAND_1 = args[2],
						COMMAND_2 = args[3],
						ARGUMENT_1 = "",
						ARGUMENT_2 = "",
						TOGGLE = true,
					}
					writefile("keybinds.keybinds", game:GetService("HttpService"):JSONEncode(keybinds))
					-- ;bind [key] [command 1] [command 2]
				else
					for i = #cmds, 1, -1 do
						if cmds[i].NAME ~= args[3] or not FindInTable(cmds[i].ALIAS, args[3]) and args[5] then
							keybinds[#keybinds + 1] = {
								KEY = args[1],
								COMMAND_1 = args[2],
								COMMAND_2 = args[4],
								ARGUMENT_1 = args[3],
								ARGUMENT_2 = args[5],
								TOGGLE = true,
							}
							writefile("keybinds.keybinds", game:GetService("HttpService"):JSONEncode(keybinds))
							-- ;bind [key] [command 1] [parameter 1] [command 2] [parameter 2]
							break
						elseif
							cmds[i].NAME ~= args[3] or not FindInTable(cmds[i].ALIAS, args[3]) and args[5] == nil
						then
							keybinds[#keybinds + 1] = {
								KEY = args[1],
								COMMAND_1 = args[2],
								COMMAND_2 = args[4],
								ARGUMENT_1 = args[3],
								ARGUMENT_2 = "",
								TOGGLE = true,
							}
							writefile("keybinds.keybinds", game:GetService("HttpService"):JSONEncode(keybinds))
							-- ;bind [key] [command 1] [parameter 1] [command 2]
							break
						elseif cmds[i].NAME == args[3] or FindInTable(cmds[i].ALIAS, args[3]) then
							keybinds[#keybinds + 1] = {
								KEY = args[1],
								COMMAND_1 = args[2],
								COMMAND_2 = args[3],
								ARGUMENT_1 = "",
								ARGUMENT_2 = args[4],
								TOGGLE = true,
							}
							writefile("keybinds.keybinds", game:GetService("HttpService"):JSONEncode(keybinds))
							-- ;bind [key] [command 1] [command 2] [parameter 2]
							break
						end
					end
				end
			end,
		},
		["unbind"] = {
			["ListName"] = "unbind {key}",
			["Description"] = "oui",
			["Aliases"] = {},
			["Function"] = function(args, speaker)
				for i = #keybinds, 1, -1 do
					if keybinds[i].KEY == args[1] then
						table.remove(keybinds, i)
						writefile("keybinds.keybinds", game:GetService("HttpService"):JSONEncode(keybinds))
						notify("This bind has been removed")
						return
					else
						notify("This key is not bound")
					end
				end
			end,
		},
	},
}

return Plugin


return {
	["PluginName"] = "Minion Meme",
	["PluginDescription"] = "this is funny (Empire#4946)",
	["Commands"] = {
		["minionmeme"] = {
			["ListName"] = "minionmeme / minionm / minm",
			["Description"] = "Opens up a GUI that is minion memes",
			["Aliases"] = { "minionm", "minm" },
			["Function"] = function(args, speaker)
				local ScreenGui = Instance.new("ScreenGui")
				local ImageLabel = Instance.new("ImageLabel")

				ScreenGui.Name =
					". Ç¤Ò‰Ì·Ò‰ÌµÒ‰Ì¸Ò‰Ì·Ò‰ÌµÒ‰Ì¸Ò‰Ì¡Ò‰Ì¡Ò‰Ì¼Ò‰Ì±Ò‰ÍŽÒ‰ÍŽÒ‰ÌžÒ‰Ì¼Ò‰Ì±Ò‰ÍŽÒ‰ÍŽÒ‰ÌžÒ‰Í¤Ò‰Í¬Ò‰Ì…Ò‰Í¤Ò‰Í¬"
				ScreenGui.Parent = game.Players.LocalPlayer:WaitForChild("PlayerGui")
				ScreenGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
				ScreenGui.ResetOnSpawn = false

				ImageLabel.Parent = ScreenGui
				ImageLabel.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
				ImageLabel.Position = UDim2.new(0.211329371, 0, 0.317738771, 0)
				ImageLabel.Size = UDim2.new(0.347921491, 0, 0.48174721, 0)
				ImageLabel.Image = "rbxassetid://7047935045"
				ImageLabel.Draggable = true

				local function NXVDBZN_fake_script()
					local script = Instance.new("Script", ImageLabel)

					while true do
						script.Parent.Image = "rbxassetid://7047935045"
						wait(5)
						script.Parent.Image = "rbxassetid://8671458138"
						wait(5)
						script.Parent.Image = "rbxassetid://3352204149"
						wait(5)
						script.Parent.Image = "rbxassetid://8671265876"
						wait(5)
						script.Parent.Image = "rbxassetid://8177142940"
						wait(5)
						script.Parent.Image = "rbxassetid://8795689695"
						wait(5)
						script.Parent.Image = "rbxassetid://8455303389"
						wait(5)
					end
				end
				coroutine.wrap(NXVDBZN_fake_script)()
				local function RFRPI_fake_script() -- ImageLabel.Smooth GUI Dragging
					local script = Instance.new("LocalScript", ImageLabel)

					local UserInputService = game:GetService("UserInputService")
					local runService = (game:GetService("RunService"))

					local gui = script.Parent

					local dragging
					local dragInput
					local dragStart
					local startPos

					function Lerp(a, b, m)
						return a + (b - a) * m
					end

					local lastMousePos
					local lastGoalPos
					local DRAG_SPEED = 8 -- // The speed of the UI darg.
					function Update(dt)
						if not startPos then
							return
						end
						if not dragging and lastGoalPos then
							gui.Position = UDim2.new(
								startPos.X.Scale,
								Lerp(gui.Position.X.Offset, lastGoalPos.X.Offset, dt * DRAG_SPEED),
								startPos.Y.Scale,
								Lerp(gui.Position.Y.Offset, lastGoalPos.Y.Offset, dt * DRAG_SPEED)
							)
							return
						end

						local delta = (lastMousePos - UserInputService:GetMouseLocation())
						local xGoal = (startPos.X.Offset - delta.X)
						local yGoal = (startPos.Y.Offset - delta.Y)
						lastGoalPos = UDim2.new(startPos.X.Scale, xGoal, startPos.Y.Scale, yGoal)
						gui.Position = UDim2.new(
							startPos.X.Scale,
							Lerp(gui.Position.X.Offset, xGoal, dt * DRAG_SPEED),
							startPos.Y.Scale,
							Lerp(gui.Position.Y.Offset, yGoal, dt * DRAG_SPEED)
						)
					end

					gui.InputBegan:Connect(function(input)
						if
							input.UserInputType == Enum.UserInputType.MouseButton1
							or input.UserInputType == Enum.UserInputType.Touch
						then
							dragging = true
							dragStart = input.Position
							startPos = gui.Position
							lastMousePos = UserInputService:GetMouseLocation()

							input.Changed:Connect(function()
								if input.UserInputState == Enum.UserInputState.End then
									dragging = false
								end
							end)
						end
					end)

					gui.InputChanged:Connect(function(input)
						if
							input.UserInputType == Enum.UserInputType.MouseMovement
							or input.UserInputType == Enum.UserInputType.Touch
						then
							dragInput = input
						end
					end)

					runService.Heartbeat:Connect(Update)
				end
				coroutine.wrap(RFRPI_fake_script)()
			end,
		},
		["minionmemeDESTROY"] = {
			["ListName"] = "minionmemeDESTROY / minionmdestroy / minmdestroy",
			["Description"] = "Destroys The Minion Meme.",
			["Aliases"] = { "minionmdestroy", "minmdestroy" },
			["Function"] = function(args, speaker)
				game:GetService("Players").LocalPlayer.PlayerGui[". Ç¤Ò‰Ì·Ò‰ÌµÒ‰Ì¸Ò‰Ì·Ò‰ÌµÒ‰Ì¸Ò‰Ì¡Ò‰Ì¡Ò‰Ì¼Ò‰Ì±Ò‰ÍŽÒ‰ÍŽÒ‰ÌžÒ‰Ì¼Ò‰Ì±Ò‰ÍŽÒ‰ÍŽÒ‰ÌžÒ‰Í¤Ò‰Í¬Ò‰Ì…Ò‰Í¤Ò‰Í¬"]
					:Destroy()
			end,
		},
	},
}


local PluginAPI = {}
function PluginAPI:CreatePlugin(name, description)
	local Functions = {}
	local Plugin = {
		["PluginName"] = name,
		["PluginDescription"] = description,
		["Commands"] = {},
	}
	function Functions:AddCommand(Name, ListName, Description, Aliases, Callback)
		Plugin["Commands"][Name] = {
			["ListName"] = ListName,
			["Description"] = Description,
			["Aliases"] = Aliases,
			["Function"] = Callback,
		}
	end
	return { PluginTable = Plugin, Functions = Functions }
end

local Plugin = PluginAPI:CreatePlugin("orbit", "Because Edge removed it long ago, lol -Amokah")
function RemoveFromTable(TABLE, IND)
	for i, v in pairs(TABLE) do
		if v == IND then
			table.remove(TABLE, i)
			v = nil
			return TABLE
		end
	end
	return TABLE
end
local Players = game:GetService("Players")
function GetPlayers(owner, strGet)
	local Group = {}
	if strGet == nil then
		strGet = ""
	end
	strGet = strGet:lower()
	if strGet == "all" then
		return Players:GetPlayers()
	end
	if strGet == "others" then
		return RemoveFromTable(Players:GetPlayers(), owner)
	end
	if strGet == "admins" then
		for i, v in pairs(_G.Admins) do
			table.insert(Group, v)
		end
	end
	if strGet == "nonadmins" then
		local t = Players:GetPlayers()
		for i, v in pairs(_G.Admins) do
			RemoveFromTable(t, v)
		end
		return t
	end
	if strGet == "me" or strGet == "" then
		return { owner }
	end
	for i, v in pairs(Players:GetPlayers()) do
		if v.Name:lower():sub(0, #strGet) == strGet:lower() then
			table.insert(Group, v)
		end
	end
	return Group
end

local Loop = nil
local rot = 0
local orbSpeed = 1
local orbDist = 5

Plugin.Functions:AddCommand("orbit", "orbit [plr]", "orbits a player in a circle", { "orb" }, function(args, speaker)
	local PlayerToOrbit = GetPlayers(speaker, args[1])
	if PlayerToOrbit then
		PlayerToOrbit = PlayerToOrbit[1]
	else
		return Loop:Disconnect()
	end
	if Loop ~= nil then
		Loop:Disconnect()
	end
	local t = tick()
	Loop = game:GetService("RunService").RenderStepped:Connect(function()
		if tick() - t > 0.01035 then
			rot += orbSpeed
			t = tick()
			if speaker.Character and speaker.Character:FindFirstChild("HumanoidRootPart") then
				for _, g in pairs(speaker.Character:GetDescendants()) do
					pcall(function()
						if g:IsA("BasePart") then
							g.Velocity = Vector3.new(0, 0, 0)
							g.RotVelocity = Vector3.new(0, 0, 0)
						end
					end)
				end
				if PlayerToOrbit ~= speaker then
					if PlayerToOrbit.Character and PlayerToOrbit.Character:FindFirstChild("HumanoidRootPart") then
						speaker.Character.HumanoidRootPart.CFrame = CFrame.new(
							PlayerToOrbit.Character.HumanoidRootPart.Position
						) * CFrame.Angles(0, math.rad(rot), 0) * CFrame.new(0, 0, -orbDist) * CFrame.Angles(
							0,
							math.rad(180),
							0
						)
					end
				else
					Loop:Disconnect()
				end
			end
		end
	end)
end)
Plugin.Functions:AddCommand("unorbit", "unorbit", "unorbits a player", { "unorb" }, function(args, speaker)
	if Loop ~= nil then
		Loop:Disconnect()
	end
end)
Plugin.Functions:AddCommand(
	"orbitspeed",
	"orbitspeed / ospeed [speed]",
	"changes orbit speed",
	{ "ospeed" },
	function(args, speaker)
		if args[1] and tonumber(args[1]) ~= nil and tonumber(args[1]) > 0 then
			local num = tonumber(args[1])
			orbSpeed = math.clamp(num, 0.005, 1000)
		end
	end
)
Plugin.Functions:AddCommand(
	"orbitdist",
	"orbitdist / odist [distance]",
	"changes orbit distance",
	{ "odist" },
	function(args, speaker)
		if args[1] and tonumber(args[1]) ~= nil and tonumber(args[1]) > 0 then
			local num = tonumber(args[1])
			orbDist = math.clamp(num, 0.005, 1000)
		end
	end
)

return Plugin.PluginTable


return {
	["PluginName"] = "Save/Load Tools",
	["PluginDescription"] = "Scripted by Empire#4946!",
	["Commands"] = {
		["savetools"] = {
			["ListName"] = "savetools / savet",
			["Description"] = "Saves Tools and puts them into your Player",
			["Aliases"] = { "savet" },
			["Function"] = function(args, speaker)
				for i, v in pairs(speaker:FindFirstChildOfClass("Backpack"):GetChildren()) do
					if v:IsA("Tool") then
						v.Parent = speaker
					end
				end
			end,
		},
		["loadtools"] = {
			["ListName"] = "loadtools / loadt",
			["Description"] = "Loads Saved Tools",
			["Aliases"] = { "loadt" },
			["Function"] = function(args, speaker)
				for i, v in pairs(speaker:GetChildren()) do
					if v:IsA("Tool") then
						v.Parent = speaker:FindFirstChildOfClass("Backpack")
					end
				end
			end,
		},
	},
}


-- Instances --------------------------------------

local Blur = Instance.new("BlurEffect")
Blur.Name = "Blur [Shader Mod]"
Blur.Parent = game.Lighting
Blur.Size = 4
Blur.Enabled = false

local DepthOfField = Instance.new("DepthOfFieldEffect")
DepthOfField.Name = "Depth Of Field [Shader Mod]"
DepthOfField.Parent = game.Lighting
DepthOfField.FarIntensity = 0.75
DepthOfField.FocusDistance = 0.05
DepthOfField.InFocusRadius = 10
DepthOfField.NearIntensity = 0.75
DepthOfField.Enabled = false

-- Variables --------------------------------------

local ShaderEnabled = false

-- Plugin -----------------------------------------

local Plugin = {
	["PluginName"] = "Shader Mod",
	["PluginDescription"] = "Plugin by WeAreRump",

	["Commands"] = {
		["toggleshader"] = {
			["ListName"] = "toggleshader / ts",
			["Description"] = "Toggles shader.",
			["Aliases"] = { "ts" },
			["Function"] = function(args, speaker)
				if not ShaderEnabled then
					Blur.Enabled = true
					DepthOfField.Enabled = true
					ShaderEnabled = true
					notify("Shader Mod", "ShaderEnabled: true")
				else
					Blur.Enabled = false
					DepthOfField.Enabled = false
					ShaderEnabled = false
					notify("Shader Mod", "ShaderEnabled: false")
				end
			end,
		},
	},
}

return Plugin


local lplr = game:GetService("Players").LocalPlayer

normalSpeed = lplr.Character.Humanoid.WalkSpeed
speed = 30

local Plugin = {
	["PluginName"] = "Shift To Sprint",
	["PluginDescription"] = "A plugin to be able to shift to sprint at the speed you want",
	["Commands"] = {
		["shifttosprint"] = {
			["ListName"] = "shifttosprint / sts",
			["Description"] = "Toggle the shift to sprint",
			["Aliases"] = { "sts" },
			["Function"] = function(args, speaker)
				local UserInputService = game:GetService("UserInputService")

				event = UserInputService.InputBegan:connect(function(input, gameprocessed)
					if input.KeyCode == Enum.KeyCode.LeftShift then
						lplr.Character.Humanoid.WalkSpeed = speed
					end
				end)

				event2 = UserInputService.InputEnded:connect(function(input, gameprocessed)
					if input.KeyCode == Enum.KeyCode.LeftShift then
						lplr.Character.Humanoid.WalkSpeed = normalSpeed
					end
				end)
			end,
		},
		["sprintspeed"] = {
			["ListName"] = "sprintspeed [speed]",
			["Description"] = "Set the speed of the shit to sprint",
			["Aliases"] = {},
			["Function"] = function(args, speaker)
				if args[1] ~= nil then
					speed = args[1]
				elseif args[1] == nil then
					speed = 30
				end
			end,
		},
		["noshifttosprint"] = {
			["ListName"] = "noshifttosprint / nsts",
			["Description"] = "Disconnect the shift to sprint event",
			["Aliases"] = { "nsts" },
			["Function"] = function(args, speaker)
				lplr.Character.Humanoid.WalkSpeed = normalSpeed
				event:Disconnect()
				event2:Disconnect()
			end,
		},
	},
}
return Plugin


return {
	["PluginName"] = "antiflingunfling",
	["PluginDescription"] = "Stops you from getting flinged from the unfling cmd",
	["Commands"] = {
		["antiflingunfling"] = {
			["ListName"] = "antiflingunfling / afu",
			["Description"] = "Stops you from getting flinged from the unfling cmd",
			["Aliases"] = { "afu" },
			["Function"] = function(args, speaker)
				execCmd("unfling")
				execCmd("freeze")
				execCmd("breakvelocity")
				execCmd("unfreeze")
			end,
		},
	},
}


local AntiKill = false
local RunService = game:GetService("RunService")
local Me = game:GetService("Players").LocalPlayer
local Char = Me.Character
local BPack = Me.Backpack
local Humanoid = Char:FindFirstChildWhichIsA("Humanoid")
local ToolTable = BPack:GetChildren()
RunService.Stepped:Connect(function()
	local Tool = Char:FindFirstChildOfClass("Tool")
	if AntiKill and Tool and not table.find(ToolTable, Tool) then
		if
			Humanoid
			and Humanoid.RigType == Enum.HumanoidRigType.R6
			and Char:FindFirstChild("Right Arm")
			and Char["Right Arm"]:FindFirstChild("RightGrip")
		then
			Char["Right Arm"].RightGrip:Destroy()
		elseif
			Humanoid
			and Humanoid.RigType == Enum.HumanoidRigType.R15
			and Char:FindFirstChild("RightHand")
			and Char["RightHand"]:FindFirstChild("RightGrip")
		then
			Char["RightHand"].RightGrip:Destroy()
		end
	end
end)
local GetAntiKill = function(Char)
	local ToolTable1 = BPack:GetChildren()
	Char.ChildAdded:Connect(function(Tool)
		if AntiKill and Tool:IsA("Tool") and not table.find(ToolTable1, Tool) then
			Tool:Destroy()
		end
	end)
end
GetAntiKill(Char)
Me.CharacterAdded:Connect(GetAntiKill)
local Plugin = {
	["PluginName"] = "Anti Kill",
	["PluginDescription"] = "If someone tries to kill you with their script with tools, the plugin stops it",
	["Commands"] = {
		["antikill"] = {
			["ListName"] = "antikill",
			["Description"] = "If someone tries to kill you with their script with tools stops it",
			["Aliases"] = {},
			["Function"] = function(args, speaker)
				AntiKill = true
			end,
		},
		["unantikill"] = {
			["ListName"] = "unantikill",
			["Description"] = "stop anti kill",
			["Aliases"] = { "" },
			["Function"] = function(args, speaker)
				AntiKill = false
			end,
		},
		["tantikill"] = {
			["ListName"] = "tantikill",
			["Description"] = "stop true anti kill",
			["Aliases"] = { "" },
			["Function"] = function(args, speaker)
				local Char = speaker.Character
				local Humanoid = Char:WaitForChild("Humanoid")
				if Humanoid and Humanoid.RigType == Enum.HumanoidRigType.R6 then
					if Char:FindFirstChild("Right Arm") then
						Char["Right Arm"]:Destroy()
					end
				elseif Humanoid and Humanoid.RigType == Enum.HumanoidRigType.R15 then
					if Char:FindFirstChild("RightHand") then
						Char.RightHand:Destroy()
					end
					if Char:FindFirstChild("RightUpperArm") then
						Char.RightUpperArm:Destroy()
					end
					if Char:FindFirstChild("RightLowerArm") then
						Char.RightLowerArm:Destroy()
					end
				end
			end,
		},
	},
}
return Plugin


local Plugin = {
	["PluginName"] = "Beyblade",
	["PluginDescription"] = "Turns you into a beyblade.",
	["Commands"] = {
		["beyblade"] = {
			["ListName"] = "beyblade",
			["Description"] = "Makes you a beyblade!",
			["Aliases"] = {},
			["Function"] = function(args, speaker)
				execCmd("walkspeed 100", speaker)
				execCmd("fling", speaker)
			end,
		},
	},
}
return Plugin


local Plugin = {
	["PluginName"] = "Big Head",
	["PluginDescription"] = "May you do a ton of trolling",
	["Commands"] = {
		["bighead"] = {
			["ListName"] = "bighead / biggest / bigger / big",
			["Description"] = "Makes you head big",
			["Aliases"] = { "biggest", "bigger", "big" },
			["Function"] = function(args, speaker)
				for i, v in pairs(game.Players.LocalPlayer.Character.Humanoid:GetChildren()) do
					if string.find(v.Name, "Scale") and v.Name ~= "HeadScale" then
						repeat
							wait()
						until game.Players.LocalPlayer.Character.Head:FindFirstChild("OriginalSize")
						game.Players.LocalPlayer.Character.Head.OriginalSize:Destroy()
						v:Destroy()
						game.Players.LocalPlayer.Character.Head:WaitForChild("OriginalSize")
						game.Players.LocalPlayer.Character.Head.OriginalSize:Destroy()
					end
				end
				wait()
				game.Players.LocalPlayer.Character.Head.Mesh:Destroy()
			end,
		},
	},
}

return Plugin


local Plugin = {
	["PluginName"] = "Blank Say",
	["PluginDescription"] = "Send blank messages.",
	["Commands"] = {
		["blanksay"] = {
			["ListName"] = "blanksay / blankchat",
			["Description"] = "Send a blank message in chat",
			["Aliases"] = { "blankchat" },
			["Function"] = function(args, speaker)
				game:GetService("ReplicatedStorage").DefaultChatSystemChatEvents.SayMessageRequest
					:FireServer(" ", "All")
			end,
		},
	},
}

return Plugin


return {
	["PluginName"] = "BlockSelf",
	["PluginDescription"] = "Makes you blocky and fat.",
	["Commands"] = {
		["blockself"] = {
			["ListName"] = "blockself [delay]",
			["Description"] = "Makes you blocky and fat.",
			["Aliases"] = {},
			["Function"] = function(args, speaker)
				speaker.Character.CharacterMesh:Destroy()
				wait(args[1])
				speaker.Character.CharacterMesh:Destroy()
				wait(args[1])
				speaker.Character.CharacterMesh:Destroy()
				wait(args[1])
				speaker.Character.CharacterMesh:Destroy()
				wait(args[1])
				speaker.Character.CharacterMesh:Destroy()
				wait(0.01)
				notify("Yum!", "You just ate " .. math.random(500, 900) .. " hamburgers.")
			end,
		},
	},
}


local Plugin = {
	["PluginName"] = "Cyclically's Custom Btools",
	["PluginDescription"] = "Just better btools",
	["Commands"] = {
		["cycbtools"] = {
			["ListName"] = "cycbtools / btools2",
			["Description"] = "Cyclically's Custom Btools",
			["Aliases"] = { "btools2" },
			["Function"] = function(args, speaker)
				local LocalPlayer = game:GetService("Players").LocalPlayer
				local mouse = LocalPlayer:GetMouse()
				local movetool = Instance.new("Tool", LocalPlayer.Backpack)
				local deletetool = Instance.new("Tool", LocalPlayer.Backpack)
				local undotool = Instance.new("Tool", LocalPlayer.Backpack)
				local identifytool = Instance.new("Tool", LocalPlayer.Backpack)
				local movedetect = false
				local movingpart = nil
				local movetransparency = 0
				if editedparts == nil then
					editedparts = {}
					parentfix = {}
					positionfix = {}
				end
				deletetool.Name = "Delete"
				undotool.Name = "Undo"
				identifytool.Name = "Identify"
				movetool.Name = "Move"
				undotool.CanBeDropped = false
				deletetool.CanBeDropped = false
				identifytool.CanBeDropped = false
				movetool.CanBeDropped = false
				undotool.RequiresHandle = false
				deletetool.RequiresHandle = false
				identifytool.RequiresHandle = false
				movetool.RequiresHandle = false
				deletetool.Activated:Connect(function()
					notify("Delete Tool", mouse.Target.Name)
					table.insert(editedparts, mouse.Target)
					table.insert(parentfix, mouse.Target.Parent)
					table.insert(positionfix, mouse.Target.CFrame)
					mouse.Target.Parent = nil
				end)
				undotool.Activated:Connect(function()
					notify("Undo Tool", editedparts[#editedparts].Name)
					editedparts[#editedparts].Parent = parentfix[#parentfix]
					editedparts[#editedparts].CFrame = positionfix[#positionfix]
					table.remove(positionfix, #positionfix)
					table.remove(editedparts, #editedparts)
					table.remove(parentfix, #parentfix)
				end)
				identifytool.Activated:Connect(function()
					notify("Identify Tool", "Instance: " .. mouse.Target.ClassName .. "\nName: " .. mouse.Target.Name)
				end)
				movetool.Activated:Connect(function()
					notify("Move Tool", mouse.Target.Name)
					movingpart = mouse.Target
					movedetect = true
					movingpart.CanCollide = false
					movetransparency = movingpart.Transparency
					movingpart.Transparency = 0.5
					mouse.TargetFilter = movingpart
					table.insert(editedparts, movingpart)
					table.insert(parentfix, movingpart.Parent)
					table.insert(positionfix, movingpart.CFrame)
					movingpart.Transparency = movingpart.Transparency / 2
					repeat
						mouse.Move:Wait()
						movingpart.CFrame = CFrame.new(mouse.Hit.p)
					until movedetect == false
				end)
				movetool.Deactivated:Connect(function()
					notify("Move Tool", mouse.Target.Name)
					movingpart.CanCollide = true
					movedetect = false
					mouse.TargetFilter = nil
					movingpart.Transparency = movetransparenc
				end)
			end,
		},
	},
}
return Plugin


local Plugin = {
	["PluginName"] = "Builderman Chat",
	["PluginDescription"] = "Pretend to be Builderman (Modded by LuaLighter)",
	["Commands"] = {
		["buildchat"] = {
			["ListName"] = "buildchat / bchat [your msg] [builderman msg]",
			["Description"] = "Chat as Builerman",
			["Aliases"] = { "bchat" },
			["Function"] = function(args, speaker)
				local msg = getstring(1)
					.. "                                                                                [Builderman]: "
					.. getstring(2)
				game:GetService("ReplicatedStorage").DefaultChatSystemChatEvents.SayMessageRequest
					:FireServer(msg, "All")
			end,
		},
	},
}

return Plugin


local Plugin = {
	["PluginName"] = "Clear Chat",
	["PluginDescription"] = "you may be warned",
	["Commands"] = {
		["clearchat"] = {
			["ListName"] = "clearchat / clchat",
			["Description"] = "deez nuts HA GOTTEM",
			["Aliases"] = { "clchat" },
			["Function"] = function(args, speaker)
				local ReplicatedStorage = game:GetService("ReplicatedStorage")
				ReplicatedStorage.DefaultChatSystemChatEvents.SayMessageRequest:FireServer(
					"â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»",
					"All"
				)
				ReplicatedStorage.DefaultChatSystemChatEvents.SayMessageRequest:FireServer(
					"â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»",
					"All"
				)
				ReplicatedStorage.DefaultChatSystemChatEvents.SayMessageRequest:FireServer(
					"â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»â¸»",
					"All"
				)
			end,
		},
	},
}

return Plugin


climbing = false
local Plugin = {
	["PluginName"] = "Climb",
	["PluginDescription"] = "Make you climb",
	["Commands"] = {
		["climb"] = {
			["ListName"] = "climb",
			["Description"] = "monke",
			["Aliases"] = {},
			["Function"] = function(args, speaker)
				if climbing == false then
					climbing = true
					local plr = game.Players.LocalPlayer
					truss = Instance.new("TrussPart", workspace)
					truss.Transparency = 0.8
					truss.Name = "truss"
					truss.CanCollide = true
					truss.Anchored = true
					truss.Size = Vector3.new(0, 10, 0)
					climbstep = game:GetService("RunService").RenderStepped:Connect(function()
						truss.CFrame = plr.Character.HumanoidRootPart.CFrame * CFrame.new(0, 0, -1.5)
					end)
				else
					notify("Climbing still active")
				end
			end,
		},
		["unclimb"] = {
			["ListName"] = "unclimb",
			["Description"] = "stop climb",
			["Aliases"] = {},
			["Function"] = function(args, speaker)
				climbing = false
				climbstep:Disconnect()
				truss:Destroy()
			end,
		},
	},
}

return Plugin


local Plugin = {
	["PluginName"] = "Crasher",
	["PluginDescription"] = "does something",
	["Commands"] = {
		["crash"] = {
			["ListName"] = "crash",
			["Description"] = "fucks up ur roblox game",
			["Aliases"] = {},
			["Function"] = function(args, speaker)
				function build()
					local part = Instance.new("Part")
					part.Parent = workspace.blocks
				end

				script.Parent.MouseButton1Click:connect(function()
					while true do
						build()
					end
				end)
			end,
		},
	},
}
return Plugin


local Plugin = {
	["PluginName"] = "Ctrl Lock",
	["PluginDescription"] = "Bind Shift Lock to Left Control",
	["Commands"] = {
		["controllock"] = {
			["ListName"] = "controllock / ctrllock",
			["Description"] = "Bind Shift Lock to Left Control",
			["Aliases"] = { "ctrllock" },
			["Function"] = function(args, speaker)
				local Players = game:GetService("Players")
				local NewLockKey = "LeftControl"
				local MouseLockController = Players.LocalPlayer.PlayerScripts
					:WaitForChild("PlayerModule")
					:WaitForChild("CameraModule")
					:WaitForChild("MouseLockController")
				local Object = MouseLockController:FindFirstChild("BoundKeys")
				if Object then
					Object.Value = NewLockKey
				else
					Object = Instance.new("StringValue")
					Object.Name = "BoundKeys"
					Object.Value = NewLockKey
					Object.Parent = MouseLockController
				end
			end,
		},
	},
}
return Plugin


local Plugin = {
	["PluginName"] = "displayNameRemover",
	["PluginDescription"] = "removes those pesky display names",
	["Commands"] = {
		["removedisplay"] = {
			["ListName"] = "removedisplay / removedisplaynames / nodisplayname / ndn",
			["Description"] = "this removes display names",
			["Aliases"] = { "removedisplaynames", "nodisplayname", "ndn" },
			["Function"] = function(args, speaker)
				local j = require(game.Chat:WaitForChild("ClientChatModules").ChatSettings)
				j.PlayerDisplayNamesEnabled = false
				for i, v in pairs(game:GetService("Players"):GetPlayers()) do
					if v:IsA("Player") then
						local username = v.Name
						v.DisplayName = username
						v.Character:FindFirstChildWhichIsA("Humanoid").DisplayName = username
						v.CharacterAdded:Connect(function(character)
							while wait(1) do
								if character == false then
									break
								end
								character:FindFirstChildWhichIsA("Humanoid").DisplayName = v.Name
							end
						end)
					end
				end
				game:GetService("Players").PlayerAdded:Connect(function(player)
					player.DisplayName = player.Name

					player.CharacterAdded:Connect(function(character)
						while wait(1) do
							if character == false then
								break
							end
							character:FindFirstChildWhichIsA("Humanoid").DisplayName = player.Name
						end
					end)
				end)
			end,
		},
	},
}

return Plugin


local Plugin = {
	["PluginName"] = "Enable Backpack",
	["PluginDescription"] = "Enables backpack",
	["Commands"] = {
		["enablebackpack"] = {
			["ListName"] = "enablebackpack",
			["Description"] = "Enables backpack",
			["Aliases"] = {},
			["Function"] = function(args, speaker)
				mouse = game.Players.LocalPlayer:GetMouse()
				GUI = game.CoreGui
				Back = GUI.RobloxGui.Backpack
				Back.Visible = true

				mouse.KeyDown:Connect(function(key)
					if key == "`" then
						if Back.Inventory.Visible ~= true then
							Back.Inventory.Visible = true
						else
							Back.Inventory.Visible = false
						end
					end
				end)
			end,
		},
	},
}

return Plugin


local Plugin = {
	["PluginName"] = "plugin name",
	["PluginDescription"] = "description",
	["Commands"] = {
		["command1"] = {
			["ListName"] = "command1 / alias1 / alias2",
			["Description"] = "description",
			["Aliases"] = { "alias1", "alias2" },
			["Function"] = function(args, speaker)
				print("placeholder")
			end,
		},
	},
}

return Plugin


local Plugin = {
	["PluginName"] = "Fake Commands",
	["PluginDescription"] = "Allows you to pretend you got kick/banned, for whatever reason you need it for.",
	["Commands"] = {
		["fakekick"] = {
			["ListName"] = "fakekick <reason>",
			["Description"] = "Kicks you for the desired reason.",
			["Aliases"] = { "fkick" },
			["Function"] = function(args, speaker)
				local reason = getstring(1)
				speaker:Kick("\n\nYou have been removed from this game!\n\nReason: " .. reason .. "\n")
			end,
		},
		["fakeban"] = {
			["ListName"] = "fakeban <reason>",
			["Description"] = "Bans you for the desired reason.",
			["Aliases"] = { "fban" },
			["Function"] = function(args, speaker)
				local reason = getstring(1)
				speaker:Kick("\n\nYou have been banned from this game!\n\nReason: " .. reason .. "\n")
			end,
		},
	},
}

return Plugin


local Plugin = {
	["PluginName"] = "Fakeify",
	["PluginDescription"] = "Scripted by NoobSploit#0001",
	["Commands"] = {
		["fakeuser"] = {
			["ListName"] = "fakeuser [user]",
			["Description"] = "This is client sided nobody else can see this",
			["Aliases"] = { "" },
			["Function"] = function(args, speaker)
				user = getstring(1)
				game:GetService("Players").LocalPlayer.Name = user
			end,
		},
		["fakeid"] = {
			["ListName"] = "fakeid [ID]",
			["Description"] = "This is client sided nobody else can see this",
			["Aliases"] = { "" },
			["Function"] = function(args, speaker)
				ID = getstring(1)
				game.Players.LocalPlayer.UserId = ID
			end,
		},
		["fakedisplay"] = {
			["ListName"] = "fakedisplay [displayname]",
			["Description"] = "This is client sided nobody else can see this",
			["Aliases"] = { "" },
			["Function"] = function(args, speaker)
				displayname = getstring(1)
				game:GetService("Players").LocalPlayer.DisplayName = displayname
			end,
		},
	},
}
return Plugin