local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local Assets = require(Rorooms.SourceCode.Shared.Assets)
local Profiles = require(Rorooms.SourceCode.Client.UI.States.Profiles)

export type Props = {
	UserId: Fusion.UsedAs<number>?,
}

return function(Scope: Fusion.Scope<any>, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, OnyxUI.Components, OnyxUI.Util)
	local Theme = OnyxUI.Themer.Theme:now()

	local UserId = OnyxUI.Util.Fallback(Props.UserId, nil)

	local Profile = Profiles.ProfileValue(Scope, UserId)
	local SafeProfile = Profiles.SafeProfileValue(Scope, Profile)
	local Badges = Scope:Computed(function(Use)
		local ReturnBadges = {}
		local SafeProfileValue = Use(SafeProfile)

		if SafeProfileValue.Membership == "RoroomsPlus" then
			table.insert(ReturnBadges, "RoroomsPlus")
		end
		if SafeProfileValue.ServerOwner then
			table.insert(ReturnBadges, "ServerOwner")
		end

		return ReturnBadges
	end)

	return Scope:IconText(OnyxUI.Util.CombineProps(Props, {
		Content = Scope:Computed(function(Use)
			local BadgesValue = Use(Badges)
			local Content = {}

			for _, Badge in ipairs(BadgesValue) do
				if Assets.Icons.UserBadges[Badge] then
					table.insert(Content, Assets.Icons.UserBadges[Badge])
				end
			end

			return Content
		end),

		ContentSize = Theme.TextSize["1.5"],
		ListVerticalAlignment = Enum.VerticalAlignment.Center,
	}))
end


local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local Assets = require(Rorooms.SourceCode.Shared.Assets)

local Util = OnyxUI.Util
local Themer = OnyxUI.Themer

export type Props = {}

return function(Scope, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, OnyxUI.Components, Util)
	local Theme = Themer.Theme:now()

	return Scope:Image(Util.CombineProps(Props, {
		Name = "RoroomsLogo",
		BackgroundTransparency = 1,
		Image = Assets.Images.RoroomsLogo,
		Size = Scope:Computed(function(Use)
			return UDim2.fromOffset(0, Use(Theme.Spacing["1"]))
		end),
		AspectRatio = 1024 / 221,
		AspectType = Enum.AspectType.ScaleWithParentSize,
		DominantAxis = Enum.DominantAxis.Height,
	}))
end


local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)

local Themer = OnyxUI.Themer
local Children = Fusion.Children
local Util = OnyxUI.Util

local DISABLED_TRANSPARENCY = 0.5

export type Props = {
	Label: Fusion.UsedAs<string>,
}

local function SettingToggle(Scope: Fusion.Scope<any>, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, Util, OnyxUI.Components)
	local Theme = Themer.Theme:now()

	local Switched = Scope:EnsureValue(Util.Fallback(Props.Switched, false))
	local Disabled = Util.Fallback(Props.Disabled, false)

	Props.Switched = Switched

	return Scope:SwitchGroup(Util.CombineProps(Props, {
		AutomaticSize = Enum.AutomaticSize.Y,
		Switched = Switched,
		Disabled = Disabled,

		[Children] = {
			Scope:Text {
				AnchorPoint = Vector2.new(0, 0.5),
				Position = UDim2.fromScale(0, 0.5),
				Text = Props.Label,
				TextColor3 = Theme.Colors.BaseContent.Main,
				TextTransparency = Scope:Computed(function(use)
					if use(Disabled) then
						return DISABLED_TRANSPARENCY
					else
						return 0
					end
				end),
				TextWrapped = false,
			},
			Scope:SwitchInput {
				AnchorPoint = Vector2.new(1, 0),
				Position = UDim2.fromScale(1, 0),
				Switched = Switched,
				Disabled = Props.Disabled,
				Selectable = false,
			},
		},
	}))
end

return SettingToggle


local Rorooms = script.Parent.Parent.Parent.Parent.Parent

local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local States = require(Rorooms.SourceCode.Client.UI.States)

local Children = Fusion.Children
local Util = OnyxUI.Util
local Themer = OnyxUI.Themer
local Peek = Fusion.peek

return function(Scope: Fusion.Scope<any>, Props)
	local Scope = Fusion.innerScope(Scope, Fusion, OnyxUI.Util, OnyxUI.Components)
	local Theme = Themer.Theme:now()

	local SizeMultiplier = Util.Fallback(Props.SizeMultiplier, 1)
	local MenuName = Util.Fallback(Props.MenuName, "")
	local Icon = Util.Fallback(Props.Icon, "")
	local IconFilled = Util.Fallback(Props.IconFilled, "")
	local IndicatorEnabled = Util.Fallback(Props.IndicatorEnabled, false)
	local IndicatorColor = Util.Fallback(Props.IndicatorColor, Color3.fromRGB(255, 255, 255))
	local Callback = Util.Fallback(Props.Callback, function() end)

	local IsHovering = Scope:Value(false)
	local MenuOpen = Scope:Computed(function(Use)
		return Use(States.Menus.CurrentMenu) == Use(MenuName)
	end)

	return Scope:BaseButton {
		Name = "TopbarButton",
		BackgroundColor3 = Theme.Colors.BaseContent.Main,
		BackgroundTransparency = Scope:Computed(function(Use)
			if Use(IsHovering) or Use(MenuOpen) then
				return 0.9
			else
				return 1
			end
		end),
		Size = Scope:Computed(function(Use)
			local BaseSize = UDim2.fromOffset(45, 45)
			local SizeMultiplierValue = Use(SizeMultiplier)
			return UDim2.fromOffset(BaseSize.X.Offset * SizeMultiplierValue, BaseSize.Y.Offset * SizeMultiplierValue)
		end),
		AutomaticSize = Enum.AutomaticSize.None,
		LayoutOrder = Props.LayoutOrder,
		CornerRadius = Scope:Computed(function(Use)
			return UDim.new(0, Use(Theme.CornerRadius["Full"]))
		end),

		IsHovering = IsHovering,
		OnActivated = function()
			if Peek(States.Menus.CurrentMenu) == Peek(MenuName) then
				States.Menus.CurrentMenu:set()
			else
				States.Menus.CurrentMenu:set(Peek(MenuName))
				Callback()

				if Peek(States.CoreGui.ScreenSize).Y < 900 then
					States.Menus.ItemsMenu.Open:set()
				end
			end
		end,

		[Children] = {
			Scope:Icon {
				Name = "Icon",
				Image = Scope:Computed(function(Use)
					if Use(MenuOpen) then
						return Use(IconFilled)
					else
						return Use(Icon)
					end
				end),
				ImageColor3 = Theme.Colors.BaseContent.Main,
				Size = UDim2.fromOffset(30, 30),
				AnchorPoint = Vector2.new(0.5, 0.5),
				Position = UDim2.fromScale(0.5, 0.5),
			},
			Scope:Base {
				Name = "Indicator",
				BackgroundTransparency = 0,
				BackgroundColor3 = IndicatorColor,
				Size = UDim2.fromOffset(12, 3),
				AnchorPoint = Vector2.new(0.5, 1),
				Position = UDim2.fromScale(0.5, 1),
				CornerRadius = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.CornerRadius.Full))
				end),
				Visible = IndicatorEnabled,
			},
		},
	}
end


local MarketplaceService = game:GetService("MarketplaceService")

local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local Future = require(script.Parent.Parent.Parent.Parent.Parent.Parent.Future)
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local States = require(Rorooms.SourceCode.Client.UI.States)

local Children = Fusion.Children
local Util = OnyxUI.Util
local Themer = OnyxUI.Themer
local Peek = Fusion.peek

local CustomButton = require(script.Parent.CustomButton)

return function(Scope: Fusion.Scope<any>, Props)
	local Scope = Fusion.innerScope(Scope, Fusion, OnyxUI.Util, OnyxUI.Components, {
		CustomButton = CustomButton,
	})
	local Theme = Themer.Theme:now()

	local PlaceId = Util.Fallback(Props.PlaceId, nil)

	local PlaceInfo = Scope:Value({})

	local function UpdatePlaceInfo()
		Future.Try(function()
			return MarketplaceService:GetProductInfo(Peek(PlaceId))
		end):After(function(Success, Result)
			if Success then
				PlaceInfo:set(Result)
			else
				warn(Result)
			end
		end)
	end

	Scope:Observer(PlaceId):onChange(UpdatePlaceInfo)
	UpdatePlaceInfo()

	return Scope:CustomButton {
		Name = "WorldButton",
		ListEnabled = true,
		ListFillDirection = Enum.FillDirection.Vertical,
		ListHorizontalAlignment = Enum.HorizontalAlignment.Center,
		ListPadding = Scope:Computed(function(Use)
			return UDim.new(0, Use(Theme.Spacing["0.5"]))
		end),
		PaddingLeft = Scope:Computed(function(Use)
			return UDim.new(0, Use(Theme.Spacing["0"]))
		end),
		PaddingTop = Scope:Computed(function(Use)
			return UDim.new(0, Use(Theme.Spacing["0"]))
		end),
		PaddingRight = Scope:Computed(function(Use)
			return UDim.new(0, Use(Theme.Spacing["0"]))
		end),

		OnActivated = function()
			States.WorldPageMenu.PlaceId:set(Peek(PlaceId))
			States.Menus.CurrentMenu:set("WorldPageMenu")
		end,

		[Children] = {
			Scope:Image {
				Name = "Icon",
				Size = UDim2.fromOffset(105, 105),
				Image = Scope:Computed(function(Use)
					if Use(PlaceInfo) and Use(PlaceInfo).IconImageAssetId then
						return `rbxassetid://{Use(PlaceInfo).IconImageAssetId}`
					else
						return "rbxasset://textures/ui/GuiImagePlaceholder.png"
					end
				end),
				BackgroundTransparency = 1,
				CornerRadius = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.CornerRadius["1.5"]))
				end),
				AspectRatio = 1,
				AspectType = Enum.AspectType.FitWithinMaxSize,
				DominantAxis = Enum.DominantAxis.Height,
			},
			Scope:Text {
				Name = "Title",
				Text = Scope:Computed(function(Use)
					if Use(PlaceInfo) and Use(PlaceInfo).Name then
						return Use(PlaceInfo).Name
					else
						return "Title"
					end
				end),
				Size = Scope:Computed(function(Use)
					return UDim2.fromOffset(90, Use(Theme.TextSize["1"]) * 2)
				end),
				AutomaticSize = Enum.AutomaticSize.None,
				TextTruncate = Enum.TextTruncate.AtEnd,
				TextXAlignment = Enum.TextXAlignment.Center,
				TextYAlignment = Enum.TextYAlignment.Top,
				AutoLocalize = false,
				TextWrapped = true,
				RichText = false,
			},
		},
	}
end


local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local Assets = require(Rorooms.SourceCode.Shared.Assets)

local Children = Fusion.Children
local Util = OnyxUI.Util
local Themer = OnyxUI.Themer

return function(Scope: Fusion.Scope<any>, Props)
	local Scope = Fusion.innerScope(Scope, Fusion, OnyxUI.Util, OnyxUI.Components)
	local Theme = Themer.Theme:now()

	local Title = Util.Fallback(Props.Title, "General")
	local Icon = Util.Fallback(Props.Icon, Assets.Icons.Categories.General)
	local Name = Util.Fallback(Props.Name, script.Name)
	local Size = Util.Fallback(Props.Size, UDim2.fromScale(1, 0))
	local LayoutOrder = Util.Fallback(Props.LayoutOrder, 0)
	local Visible = Util.Fallback(Props.Visible, true)

	return Scope:Frame(Util.CombineProps(Props, {
		Name = Name,
		Size = Size,
		LayoutOrder = LayoutOrder,
		Visible = Visible,
		ListEnabled = true,
		ListHorizontalFlex = Enum.UIFlexAlignment.Fill,

		[Children] = {
			Scope:Frame {
				Name = "Title",
				ListEnabled = true,
				ListFillDirection = Enum.FillDirection.Horizontal,
				ListPadding = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.Spacing["0.25"]))
				end),

				[Children] = {
					Scope:Icon {
						Image = Icon,
						ImageColor3 = Theme.Colors.BaseContent.Main,
						Size = Scope:Computed(function(Use)
							return UDim2.fromOffset(Use(Theme.TextSize["1"]), Use(Theme.TextSize["1"]))
						end),
					},
					Scope:Text {
						Text = Title,
						TextWrapped = false,
					},
				},
			},
			Scope:Frame {
				Name = "Contents",
				AutomaticSize = Enum.AutomaticSize.Y,
				ListEnabled = true,
				ListHorizontalFlex = Enum.UIFlexAlignment.Fill,

				[Children] = Props[Children],
			},
		},
	}, { Children }))
end


local STORY_EXTENSION = ".story"

local Components = {
	CategoriesSidebar = require(script.CategoriesSidebar),
	CategoryButton = require(script.CategoryButton),
	CustomButton = require(script.CustomButton),
	EmoteButton = require(script.EmoteButton),
	EmoteCategoriesSidebar = require(script.EmoteCategoriesSidebar),
	EmotesCategory = require(script.EmotesCategory),
	FriendButton = require(script.FriendButton),
	ItemButton = require(script.ItemButton),
	ItemCategoriesSidebar = require(script.ItemCategoriesSidebar),
	ItemsCategory = require(script.ItemsCategory),
	SettingToggle = require(script.SettingToggle),
	TopbarButton = require(script.TopbarButton),
	WorldButton = require(script.WorldButton),
	WorldsCategory = require(script.WorldsCategory),
	Menu = require(script.Menu),
	EditableText = require(script.EditableText),
	PlayerAvatar = require(script.PlayerAvatar),
	ProfileBadges = require(script.ProfileBadges),
	LevelBadge = require(script.LevelBadge),
	RoroomsLogo = require(script.RoroomsLogo),
}

for _, Child in ipairs(script:GetChildren()) do
	local LastCharacters = string.sub(Child.Name, -string.len(STORY_EXTENSION))
	if LastCharacters ~= STORY_EXTENSION then
		local Success, Result = pcall(function()
			return require(Child)
		end)
		if Success then
			if Components[Child.Name] ~= Result then
				warn(`Component`, Child, `is not listed.`)
			end
		else
			warn(Child, "errored during require.")
		end
	end
end

return Components


local Rorooms = script.Parent.Parent.Parent.Parent
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local ColorUtils = require(Rorooms.Parent.ColorUtils)

local Util = OnyxUI.Util

local Scope = Fusion.scoped(Fusion)

return {
	Colors = {
		Primary = {
			Main = Util.Colors.White,
		},
		Secondary = {
			Main = Util.Colors.White,
		},
		Accent = {
			Main = Util.Colors.White,
		},

		Neutral = {
			Main = ColorUtils.Lighten(Util.Colors.Stone["800"], 0.05),
		},
		NeutralContent = {
			Main = Util.Colors.Stone["100"],
			Dark = ColorUtils.Darken(Util.Colors.Stone["100"], 0.2),
		},

		Base = {
			Main = Util.Colors.Black,
		},
		BaseContent = {
			Main = Util.Colors.White,
		},

		Success = {
			Main = Util.Colors.Green["500"],
		},
		Error = {
			Main = Util.Colors.Red["500"],
		},
		Warning = {
			Main = Util.Colors.Amber["500"],
		},
		Info = {
			Main = Util.Colors.Cyan["400"],
		},
	},
	Font = {
		Body = "rbxasset://fonts/families/Montserrat.json",
		Heading = "rbxasset://fonts/families/Montserrat.json",
		Monospace = "rbxasset://fonts/families/Montserrat.json",
	},
	FontWeight = {
		Body = Enum.FontWeight.SemiBold,
		Bold = Enum.FontWeight.Bold,
		Heading = Enum.FontWeight.Bold,
	},
	TextSize = {
		Base = 17,
	},
	CornerRadius = {
		Base = 6,
	},
	StrokeThickness = {
		Base = 1,
	},
	Spacing = {
		Base = 14,
	},
	SpringSpeed = {
		Base = 60,
	},
	SpringDampening = {
		Base = 1.25,
	},
	Sound = {
		Hover = Scope:New "Sound" {
			SoundId = "rbxassetid://10066936758",
			Volume = 0,
		},
		Click = Scope:New "Sound" {
			SoundId = "rbxassetid://16480549841",
			Volume = 0,
		},
		Focus = Scope:New "Sound" {
			SoundId = "rbxassetid://16480549841",
			Volume = 0,
		},
		Switch = Scope:New "Sound" {
			SoundId = "rbxassetid://9119713951",
			Volume = 0,
		},
	},
	Emphasis = {
		Light = 0.1,
		Regular = 0.15,
		Strong = 0.5,
		Contrast = 1,
	},
}


local Rorooms = script.Parent.Parent.Parent.Parent
local OnyxUI = require(Rorooms.Parent.OnyxUI)

local Util = OnyxUI.Util

return {
	Colors = {
		Primary = {
			Main = Util.Colors.Violet["400"],
		},
		Secondary = {
			Main = Util.Colors.White,
		},
		Accent = {
			Main = Util.Colors.White,
		},

		Neutral = {
			Main = Util.Colors.Slate["700"],
		},
		NeutralContent = {
			Main = Util.Colors.Slate["300"],
		},

		Base = {
			Main = Util.Colors.Slate["950"],
		},
		BaseContent = {
			Main = Util.Colors.White,
		},

		Success = {
			Main = Util.Colors.Green["500"],
		},
		Error = {
			Main = Util.Colors.Red["500"],
		},
		Warning = {
			Main = Util.Colors.Amber["500"],
		},
		Info = {
			Main = Util.Colors.Cyan["400"],
		},
	},
	Font = {
		Body = "rbxasset://fonts/families/FredokaOne.json",
		Heading = "rbxasset://fonts/families/FredokaOne.json",
		Monospace = "rbxasset://fonts/families/FredokaOne.json",
	},
	FontWeight = {
		Body = Enum.FontWeight.Regular,
		Bold = Enum.FontWeight.Regular,
		Heading = Enum.FontWeight.Regular,
	},
	TextSize = {
		Base = 16,
	},
	CornerRadius = {
		Base = 10,
	},
	StrokeThickness = {
		Base = 2,
	},
	Spacing = {
		Base = 18,
	},
	SpringSpeed = {
		Base = 25,
	},
	SpringDampening = {
		Base = 1,
	},
	Sound = {},
}


local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local States = require(Rorooms.SourceCode.Client.UI.States)
local Config = require(Rorooms.Config).Config
local Components = require(Rorooms.SourceCode.Client.UI.Components)

local Children = Fusion.Children
local Themer = OnyxUI.Themer
local Peek = Fusion.peek

return function(Scope: Fusion.Scope<any>, Props)
	local Scope = Fusion.innerScope(Scope, Fusion, OnyxUI.Util, OnyxUI.Components, Components)
	local Theme = Themer.Theme:now()

	local MenuOpen = Scope:Computed(function(Use)
		return Use(States.Menus.CurrentMenu) == script.Name
	end)

	local EmotesMenu = Scope:Menu {
		Name = script.Name,
		Open = MenuOpen,
		Parent = Props.Parent,
		AutomaticSize = Enum.AutomaticSize.XY,

		[Children] = {
			Scope:Frame {
				Size = UDim2.new(UDim.new(0, 0), UDim.new(0, 185)),
				AutomaticSize = Enum.AutomaticSize.X,
				ListEnabled = true,
				ListFillDirection = Enum.FillDirection.Horizontal,
				ListHorizontalFlex = Enum.UIFlexAlignment.Fill,
				ListPadding = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.Spacing["0.75"]))
				end),

				[Children] = {
					Scope:EmoteCategoriesSidebar {
						Size = UDim2.fromScale(0, 1),
					},
					Scope:Scroller {
						Name = "EmotesList",
						Size = Scope:Computed(function(Use)
							return UDim2.new(UDim.new(0, 260), UDim.new(1, 0))
						end),
						ScrollBarThickness = Theme.StrokeThickness["1"],
						Padding = Scope:Computed(function(Use)
							return UDim.new(0, Use(Theme.StrokeThickness["1"]))
						end),
						PaddingRight = Scope:Computed(function(Use)
							return UDim.new(0, Use(Theme.Spacing["1"]))
						end),
						ListEnabled = true,
						ListPadding = Scope:Computed(function(Use)
							return UDim.new(0, Use(Theme.Spacing["1"]))
						end),
						ListHorizontalFlex = Enum.UIFlexAlignment.Fill,

						[Children] = {
							Scope:ForPairs(
								Config.Systems.Emotes.Categories,
								function(Use, Scope, Name: string, Category)
									return Name,
										Scope:EmotesCategory {
											Name = Name,
											CategoryName = Name,
											LayoutOrder = Category.LayoutOrder,
										}
								end
							),
						},
					},
				},
			},
		},
	}

	local EmotesList = EmotesMenu.MenuFrame.Frame.EmotesList
	Scope:Observer(States.Menus.EmotesMenu.FocusedCategory):onChange(function()
		local Category = EmotesList:FindFirstChild(`{Peek(States.Menus.EmotesMenu.FocusedCategory)}`)
		if Category then
			EmotesList.CanvasPosition = Vector2.new(0, 0)
			EmotesList.CanvasPosition = Vector2.new(0, Category.AbsolutePosition.Y - EmotesList.AbsolutePosition.Y)
		end
	end)

	return EmotesMenu
end


local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local SocialService = game:GetService("SocialService")

local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local States = require(Rorooms.SourceCode.Client.UI.States)
local Components = require(Rorooms.SourceCode.Client.UI.Components)
local FriendsController = RunService:IsRunning() and require(Rorooms.SourceCode.Client.Friends.FriendsController)
local Assets = require(Rorooms.SourceCode.Shared.Assets)

local Children = Fusion.Children
local Themer = OnyxUI.Themer
local Peek = Fusion.peek

return function(Scope: Fusion.Scope<any>, Props)
	local Scope = Fusion.innerScope(Scope, Fusion, OnyxUI.Util, OnyxUI.Components, Components)
	local Theme = Themer.Theme:now()

	local MenuOpen = Scope:Computed(function(Use)
		return Use(States.Menus.CurrentMenu) == script.Name
	end)

	local FriendsMenu = Scope:Menu({
		Name = script.Name,
		Open = MenuOpen,
		Parent = Props.Parent,
		AutomaticSize = Enum.AutomaticSize.Y,
		Size = UDim2.fromOffset(361, 0),

		[Children] = {
			Scope:Scroller({
				Name = "Friends",
				Size = UDim2.new(UDim.new(1, 0), UDim.new(0, 180)),
				ScrollBarThickness = Theme.StrokeThickness["1"],
				Padding = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.StrokeThickness["1"]))
				end),
				PaddingRight = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.Spacing["1"]))
				end),
				ListEnabled = true,
				ListHorizontalFlex = Enum.UIFlexAlignment.Fill,

				[Children] = {
					Scope:Frame {
						ListPadding = Scope:Computed(function(Use)
							return UDim.new(0, Use(Theme.Spacing["0.75"]))
						end),
						ListFillDirection = Enum.FillDirection.Horizontal,
						ListWraps = true,

						[Children] = {
							Scope:ForValues(States.Friends.InRorooms, function(Use, Scope, Friend)
								return Themer.Theme:is(Theme):during(function()
									return Scope:FriendButton({
										UserId = Friend.VisitorId,
										DisplayName = Friend.DisplayName,
										PlaceId = Friend.PlaceId,
										JobId = Friend.GameId,
										InRorooms = true,
									})
								end)
							end),
							Scope:ForValues(States.Friends.NotInRorooms, function(Use, Scope, Friend)
								return Themer.Theme:is(Theme):during(function()
									return Scope:FriendButton({
										UserId = Friend.VisitorId,
										DisplayName = Friend.DisplayName,
										Online = Friend.IsOnline,
										PlaceId = Friend.PlaceId,
										JobId = Friend.GameId,
										InRorooms = false,
									})
								end)
							end),
						},
					},
					Scope:Button({
						Name = "InviteButton",
						Content = { Assets.Icons.General.People, "Invite Others" },
						AutomaticSize = Enum.AutomaticSize.Y,

						OnActivated = function()
							SocialService:PromptGameInvite(Players.LocalPlayer)
						end,
					}),
				},
			}),
		},
	})

	Scope:Observer(MenuOpen):onChange(function()
		if Peek(MenuOpen) and FriendsController then
			FriendsController:UpdateFriends()
		end
	end)

	return FriendsMenu
end


local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local States = require(Rorooms.SourceCode.Client.UI.States)
local Config = require(Rorooms.Config).Config
local Components = require(Rorooms.SourceCode.Client.UI.Components)

local Children = Fusion.Children
local Themer = OnyxUI.Themer
local Peek = Fusion.peek

return function(Scope: Fusion.Scope<any>, Props)
	local Scope = Fusion.innerScope(Scope, Fusion, OnyxUI.Util, OnyxUI.Components, Components)
	local Theme = Themer.Theme:now()

	local ItemsMenu = Scope:Menu {
		Name = script.Name,
		Open = States.Menus.ItemsMenu.Open,
		Parent = Props.Parent,
		AutomaticSize = Enum.AutomaticSize.X,
		Size = UDim2.fromOffset(0, 220),
		AnchorPoint = Vector2.new(0.5, 1),
		Position = Scope:Computed(function(Use)
			local YPos = 68 + 15
			if not Use(States.Menus.ItemsMenu.Open) then
				YPos -= 15
			end
			return UDim2.new(UDim.new(0.5, 0), UDim.new(1, -YPos))
		end),
		ListFillDirection = Enum.FillDirection.Horizontal,
		ListVerticalFlex = Enum.UIFlexAlignment.Fill,

		[Children] = {
			Scope:ItemCategoriesSidebar {},
			Scope:Scroller {
				Name = "Items",
				Size = Scope:Computed(function(Use)
					return UDim2.fromOffset(252, 0)
				end),
				Padding = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.StrokeThickness["1"]))
				end),
				PaddingRight = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.Spacing["1"]))
				end),
				ListEnabled = true,
				ListPadding = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.Spacing["0.75"]))
				end),
				ScrollBarThickness = Theme.StrokeThickness["1"],

				[Children] = {
					Scope:ForPairs(Config.Systems.Items.Categories, function(Use, Scope, Name: string, Category)
						return Name,
							Scope:ItemsCategory {
								Name = Name,
								CategoryName = Name,
								LayoutOrder = Category.LayoutOrder,
							}
					end),
				},
			},
		},
	}

	Scope:Observer(States.Menus.ItemsMenu.Open):onChange(function()
		local TextClasses = { "TextLabel", "TextButton", "TextBox" }
		if Peek(States.Menus.ItemsMenu.Open) then
			if Peek(States.CoreGui.ScreenSize).Y < 1000 then
				States.Menus.CurrentMenu:set()
			end
		end
		for _, Descendant in ipairs(ItemsMenu:GetDescendants()) do
			if table.find(TextClasses, Descendant.ClassName) then
				task.wait()
			end
		end
	end)

	local ItemsList = ItemsMenu.MenuFrame.Items
	Scope:Observer(States.Menus.ItemsMenu.FocusedCategory):onChange(function()
		local Category = ItemsList:FindFirstChild(`{Peek(States.Menus.ItemsMenu.FocusedCategory)}`)
		if Category then
			ItemsList.CanvasPosition = Vector2.new(0, 0)
			ItemsList.CanvasPosition = Vector2.new(0, Category.AbsolutePosition.Y - ItemsList.AbsolutePosition.Y)
		end
	end)

	return ItemsMenu
end


local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local Components = require(Rorooms.SourceCode.Client.UI.Components)
local States = require(Rorooms.SourceCode.Client.UI.States)

local Children = Fusion.Children

export type Props = {
	Parent: Fusion.UsedAs<Instance>?,
}

return function(Scope: Fusion.Scope<typeof(Fusion)>, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, OnyxUI.Util, OnyxUI.Components, Components)
	local Theme = OnyxUI.Themer.Theme:now()

	local GlowIntensity = Scope:Value(0)

	local Thread = task.spawn(function()
		while true do
			GlowIntensity:set(1)
			task.wait(1)
			GlowIntensity:set(0)
			task.wait(1)
		end
	end)

	table.insert(Scope, function()
		task.cancel(Thread)
	end)

	return Scope:New "ScreenGui" {
		Name = script.Name,
		Parent = Props.Parent,
		ScreenInsets = Enum.ScreenInsets.None,
		DisplayOrder = 10000,

		[Children] = {
			Scope:Group {
				BackgroundTransparency = 0,
				BackgroundColor3 = OnyxUI.Util.Colors.Black,
				Size = UDim2.fromScale(1, 1),
				Active = States.Loading,
				GroupTransparency = Scope:Spring(
					Scope:Computed(function(Use)
						return (Use(States.Loading) and 0) or 1
					end),
					Theme.SpringSpeed["0.5"],
					Theme.SpringDampening["1.5"]
				),

				[Children] = {
					Scope:Frame {
						BackgroundTransparency = 0,
						BackgroundColor3 = OnyxUI.Util.Colors.Black,
						Size = UDim2.fromScale(1, 1),

						[Children] = {
							Scope:Frame {
								AnchorPoint = Vector2.new(0.5, 0.5),
								Position = UDim2.fromScale(0.5, 0.5),
								ListEnabled = true,
								ListHorizontalAlignment = Enum.HorizontalAlignment.Center,

								[Children] = {
									Scope:Icon {
										Image = "rbxassetid://97237065883195",
										Size = Scope:Computed(function(Use)
											local Offset = Use(Theme.Spacing["8"])
											return UDim2.fromOffset(Offset, Offset)
										end),
										ImageColor3 = Color3.fromHex("8566FF"),
										GradientEnabled = true,
										GradientTransparency = NumberSequence.new({
											NumberSequenceKeypoint.new(0, 0),
											NumberSequenceKeypoint.new(1, 0.5),
										}),
										GradientRotation = Scope:Spring(
											Scope:Computed(function(Use)
												local GlowIntensityValue = Use(GlowIntensity)
												return GlowIntensityValue * 360
											end),
											6,
											Theme.SpringDampening["1.5"]
										),
									},
								},
							},
						},
					},
				},
			},
		},
	}
end


local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local SocialService = game:GetService("SocialService")
local StarterGui = game:GetService("StarterGui")

local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local States = require(Rorooms.SourceCode.Client.UI.States)
local Config = require(Rorooms.Config)
local Assets = require(Rorooms.SourceCode.Shared.Assets)
local Components = require(Rorooms.SourceCode.Client.UI.Components)
local WorldsController = RunService:IsRunning() and require(Rorooms.SourceCode.Client.Worlds.WorldsController)
local Profiles = require(Rorooms.SourceCode.Client.UI.States.Profiles)
local Types = require(Rorooms.SourceCode.Shared.Types)
local DeepCopy = require(Rorooms.SourceCode.Shared.ExtPackages.DeepCopy)
local Prompts = require(Rorooms.SourceCode.Client.UI.States.Prompts)

local Children = Fusion.Children
local Themer = OnyxUI.Themer
local Peek = Fusion.peek

local LOCAL_USER_ID = ((Players.LocalPlayer ~= nil) and Players.LocalPlayer.UserId) or 1

return function(Scope: Fusion.Scope<any>, Props)
	local Scope = Fusion.innerScope(Scope, Fusion, OnyxUI.Util, OnyxUI.Components, Components, {
		Profile = Profiles.ProfileValue,
		SafeProfile = Profiles.SafeProfileValue,
	})
	local Theme = Themer.Theme:now()

	local MenuOpen = Scope:Computed(function(Use)
		return Use(States.Menus.CurrentMenu) == script.Name
	end)

	local Profile = Scope:Profile(States.Menus.ProfileMenu.UserId)
	local SafeProfile = Scope:SafeProfile(Profile)

	local ShownName = Scope:Computed(function(Use)
		local SafeProfileValue: Types.Profile = Use(SafeProfile)

		if string.len(SafeProfileValue.Nickname or "") > 0 then
			return SafeProfileValue.Nickname
		else
			return SafeProfileValue.DisplayName
		end
	end)
	local Role = Scope:Computed(function(Use)
		local ProfileValue = Use(Profile)

		if ProfileValue then
			return Config.Config.Systems.Profiles.Roles[ProfileValue.Role]
		end

		return nil
	end)
	local OrderedRoles = Scope:Computed(function(Use)
		local Roles = {}

		for RoleId, RoleEntry in pairs(Config.Config.Systems.Profiles.Roles) do
			local FullRole = DeepCopy(RoleEntry)

			FullRole.RoleId = RoleId

			table.insert(Roles, FullRole)
		end

		table.sort(Roles, function(RoleA, RoleB)
			return (RoleA.LayoutOrder or string.byte(RoleA.Name)) < (RoleB.LayoutOrder or string.byte(RoleB.Name))
		end)

		return Roles
	end)
	local RoleOptions = Scope:Computed(function(Use)
		local OrderedRolesValue = Use(OrderedRoles)
		local Options = {}

		for _, RoleEntry in ipairs(OrderedRolesValue) do
			table.insert(Options, RoleEntry.RoleId)
		end

		return Options
	end)
	local Player = Scope:Computed(function(Use)
		local UserIdValue = Use(States.Menus.ProfileMenu.UserId)
		if UserIdValue then
			return Players:GetPlayerByUserId(UserIdValue)
		else
			return nil
		end
	end)

	local NicknameInput = Scope:Value("")
	local BioInput = Scope:Value("")
	local RoleInput = Scope:Value(1)
	local SelectedRoleId = Scope:Computed(function(Use)
		local RoleInputValue = Use(RoleInput)
		local OrderedRolesValue = Use(OrderedRoles)

		local RoleEntry = OrderedRolesValue[RoleInputValue]
		if RoleEntry ~= nil then
			return RoleEntry.RoleId
		else
			return nil
		end
	end)

	Scope:Observer(States.Menus.ProfileMenu.UserId):onChange(function()
		States.Menus.ProfileMenu.EditMode:set(false)
	end)
	Scope:Observer(States.Menus.CurrentMenu):onChange(function()
		States.Menus.ProfileMenu.EditMode:set(false)

		if Fusion.peek(States.Menus.CurrentMenu) ~= script.Name then
			States.Menus.ProfileMenu.UserId:set(nil)
			States.Menus.ProfileMenu.IsFriend:set(false)
			States.Menus.ProfileMenu.Location.Online:set(false)
			States.Menus.ProfileMenu.Location.InRorooms:set(false)
			States.Menus.ProfileMenu.Location.PlaceId:set(nil)
			States.Menus.ProfileMenu.Location.JobId:set(nil)
		end
	end)
	Scope:Observer(States.Menus.ProfileMenu.EditMode):onChange(function()
		local ProfileValue = Peek(Profile)
		local OrderedRolesValue = Peek(OrderedRoles)

		local OrderedRoleIndex = 1
		do
			for RoleIndex, RoleEntry in ipairs(OrderedRolesValue) do
				if RoleEntry.RoleId == ProfileValue.Role then
					OrderedRoleIndex = RoleIndex
					break
				end
			end
		end

		if ProfileValue and Peek(States.Menus.ProfileMenu.EditMode) then
			NicknameInput:set(ProfileValue.Nickname or "")
			BioInput:set(ProfileValue.Bio or "")
			RoleInput:set(OrderedRoleIndex)
		end
	end)

	if not RunService:IsRunning() then
		States.Menus.ProfileMenu.UserId:set(1)
	end

	local ProfileMenu = Scope:Menu {
		Name = script.Name,
		Open = MenuOpen,
		Parent = Props.Parent,
		AutomaticSize = Enum.AutomaticSize.Y,
		Size = UDim2.fromOffset(280, 0),
		ListHorizontalFlex = Enum.UIFlexAlignment.Fill,
		Padding = Scope:Computed(function(Use)
			return UDim.new(0, Use(Theme.Spacing["0"]))
		end),

		[Children] = {
			Scope:Frame {
				ListEnabled = true,
				ListPadding = Scope:Computed(function(Use)
					return UDim.new(0, Theme.Spacing["0"])
				end),
				ListHorizontalFlex = Enum.UIFlexAlignment.Fill,

				[Children] = {
					Scope:Image {
						Name = "Banner",
						AutomaticSize = Enum.AutomaticSize.None,
						Size = Scope:Computed(function(Use)
							return UDim2.new(UDim.new(1, 0), UDim.new(0, Use(Theme.Spacing["4"]) * 1.5))
						end),
						BackgroundTransparency = 0,
						BackgroundColor3 = Theme.Colors.Neutral.Main,

						Image = Scope:Computed(function(Use)
							local UserIdValue = Use(States.Menus.ProfileMenu.UserId) or 1
							if UserIdValue <= 0 then
								UserIdValue = 1
							end

							return `rbxthumb://type=Avatar&id={UserIdValue}&w=420&h=420`
						end),
						ScaleType = Enum.ScaleType.Crop,
						ImageRectSize = Vector2.new(420, 200),

						[Children] = {
							Scope:PlayerAvatar {
								Name = "Avatar",
								AnchorPoint = Vector2.new(0, 1),
								Position = Scope:Computed(function(Use)
									return UDim2.new(UDim.new(0, Use(Theme.Spacing["1"])), UDim.new(1.5, 0))
								end),
								Image = Scope:Computed(function(Use)
									local UserIdValue = Use(States.Menus.ProfileMenu.UserId) or 1
									if UserIdValue <= 0 then
										UserIdValue = 1
									end

									return `rbxthumb://type=AvatarHeadShot&id={UserIdValue}&w=100&h=100`
								end),
								Editable = Scope:Computed(function(Use)
									local EditModeValue = Use(States.Menus.ProfileMenu.EditMode)
									return EditModeValue
										and (Config.Config.Systems.Profiles.AvatarEditorCallback ~= nil)
								end),
								RingThickness = Scope:Computed(function(Use)
									return Use(Theme.StrokeThickness["3"])
								end),
								Status = Scope:Computed(function(Use)
									if Use(States.Menus.ProfileMenu.EditMode) then
										return "Offline"
									end
									if Use(States.Menus.ProfileMenu.UserId) == LOCAL_USER_ID then
										return "Rorooms"
									end

									if Use(States.Menus.ProfileMenu.Location.InRorooms) then
										return "Rorooms"
									elseif Use(States.Menus.ProfileMenu.Location.Online) then
										return "Online"
									else
										return "Offline"
									end
								end),

								OnActivated = function()
									if Config.Config.Systems.Profiles.AvatarEditorCallback then
										Config.Config.Systems.Profiles.AvatarEditorCallback()
									end
								end,
							},
						},
					},
					Scope:Frame {
						Name = "Badges",
						Padding = Scope:Computed(function(Use)
							return UDim.new(0, Use(Theme.Spacing["0.5"]))
						end),

						[Children] = {
							Scope:Frame {
								Name = "Container",
								AnchorPoint = Vector2.new(1, 0),
								Position = UDim2.fromScale(1, 0),
								ListEnabled = true,
								ListFillDirection = Enum.FillDirection.Horizontal,
								ListPadding = Scope:Computed(function(Use)
									return UDim.new(0, Use(Theme.Spacing["0.5"]))
								end),

								[Children] = {
									Scope:IconText {
										Content = { " " },
										ContentSize = Theme.TextSize["1.5"],
									},
									Scope:LevelBadge {
										Visible = Scope:Computed(function(Use)
											local ProfileValue = Use(Profile)
											return (ProfileValue ~= nil) and ProfileValue.Level
										end),
										Level = Scope:Computed(function(Use)
											local SafeProfileValue = Use(SafeProfile)
											return SafeProfileValue.Level
										end),
									},
									Scope:ProfileBadges {
										UserId = States.Menus.ProfileMenu.UserId,
									},
								},
							},
						},
					},
					Scope:Frame {
						Name = "Main",
						ListEnabled = true,
						ListHorizontalFlex = Enum.UIFlexAlignment.Fill,
						Padding = Scope:Computed(function(Use)
							return UDim.new(0, Use(Theme.Spacing["1"]))
						end),

						[Children] = {
							Scope:Frame {
								Name = "Details",
								ListEnabled = true,
								ListHorizontalFlex = Enum.UIFlexAlignment.Fill,

								[Children] = {
									Scope:Frame {
										Name = "Display",
										ListEnabled = true,
										ListHorizontalFlex = Enum.UIFlexAlignment.Fill,
										ListPadding = Scope:Computed(function(Use)
											return UDim.new(0, Use(Theme.Spacing["0.75"]))
										end),
										Visible = Scope:Computed(function(Use)
											return not Use(States.Menus.ProfileMenu.EditMode)
										end),

										[Children] = {
											Scope:Frame {
												Name = "Name",
												ListEnabled = true,
												ListHorizontalFlex = Enum.UIFlexAlignment.Fill,
												ListPadding = Scope:Computed(function(Use)
													return UDim.new(0, Use(Theme.Spacing["0"]))
												end),

												[Children] = {
													Scope:Text {
														Name = "Name",
														Text = ShownName,
														TextSize = Theme.TextSize["1.5"],
														FontFace = Scope:Computed(function(Use)
															return Font.new(
																Use(Theme.Font.Heading),
																Use(Theme.FontWeight.Heading)
															)
														end),
													},
													Scope:Text {
														Name = "Username",
														Text = Scope:Computed(function(Use)
															local SafeProfileValue: Types.Profile = Use(SafeProfile)
															return `@{Use(SafeProfileValue.Username)}`
														end),
														TextColor3 = Theme.Colors.NeutralContent.Dark,
													},
												},
											},
											Scope:Text {
												Name = "Bio",
												Text = Scope:Computed(function(Use)
													local SafeProfileValue: Types.Profile = Use(SafeProfile)
													return SafeProfileValue.Bio or ""
												end),
												TextWrapped = true,
												Visible = Scope:Computed(function(Use)
													local SafeProfileValue: Types.Profile = Use(SafeProfile)
													return utf8.len(SafeProfileValue.Bio or "") > 0
												end),
											},
											Scope:Frame {
												Name = "Role",

												[Children] = {
													Scope:Badge {
														Name = "Role",
														Content = Scope:Computed(function(Use)
															local RoleValue: Config.Role = Use(Role)

															if RoleValue then
																return { RoleValue.Name }
															else
																return { "Role" }
															end
														end),
														Color = Scope:Computed(function(Use)
															local RoleValue: Config.Role = Use(Role)

															if RoleValue then
																return RoleValue.Color
															else
																return Use(Theme.Colors.Neutral.Main)
															end
														end),
														Visible = Scope:Computed(function(Use)
															local RoleValue: Config.Role = Use(Role)
															return RoleValue ~= nil
														end),
													},
												},
											},
										},
									},
									Scope:Frame {
										Name = "Editor",
										ListEnabled = true,
										ListHorizontalFlex = Enum.UIFlexAlignment.Fill,
										ListPadding = Scope:Computed(function(Use)
											return UDim.new(0, Use(Theme.Spacing["0.75"]))
										end),
										Visible = States.Menus.ProfileMenu.EditMode,

										[Children] = {
											Scope:TextInput {
												Name = "Nickname",
												Text = NicknameInput,
												CharacterLimit = Config.Config.Systems.Profiles.NicknameCharacterLimit,
												PlaceholderText = "Nickname",
											},
											Scope:TextArea {
												Name = "Bio",
												Text = BioInput,
												CharacterLimit = Config.Config.Systems.Profiles.BioCharacterLimit,
												PlaceholderText = "Bio",
												AutomaticSize = Enum.AutomaticSize.Y,
												Size = Scope:Computed(function(Use)
													return UDim2.fromOffset(0, Use(Theme.TextSize["1"]) * 3)
												end),
											},
											Scope:SwapInput {
												Options = RoleOptions,
												Color = Scope:Computed(function(Use)
													local SelectedRoleIdValue: Config.Role = Use(SelectedRoleId)
													local SelectedRole =
														Config.Config.Systems.Profiles.Roles[SelectedRoleIdValue]

													if SelectedRole then
														return SelectedRole.Color
													else
														return Use(Theme.Colors.BaseContent.Main)
													end
												end),
												Selection = RoleInput,
												StrokeColor = Theme.Colors.BaseContent.Main,
												Visible = Scope:Computed(function(Use)
													return next(Config.Config.Systems.Profiles.Roles) ~= nil
												end),
											},
										},
									},
								},
							},
							Scope:Frame {
								Name = "Buttons",
								ListEnabled = true,
								ListHorizontalFlex = Enum.UIFlexAlignment.Fill,
								ListFillDirection = Enum.FillDirection.Horizontal,
								ListPadding = Scope:Computed(function(Use)
									return UDim.new(0, Use(Theme.Spacing["0.5"]))
								end),
								LayoutOrder = 3,

								[Children] = {
									Scope:Button {
										Name = "EditButton",
										Content = Scope:Computed(function(Use)
											local EditModeValue = Use(States.Menus.ProfileMenu.EditMode)
											if EditModeValue then
												return { Assets.Icons.General.Checkmark, "Save" }
											else
												return { Assets.Icons.General.EditPerson, "Edit" }
											end
										end),
										Color = Theme.Colors.Primary.Main,
										Visible = Scope:Computed(function(Use)
											return Use(States.Menus.ProfileMenu.UserId) == LOCAL_USER_ID
										end),

										OnActivated = function()
											local EditModeValue = Peek(States.Menus.ProfileMenu.EditMode)
											local SelectedRoleIdValue = Peek(SelectedRoleId)
											local NicknameInputValue = Peek(NicknameInput)
											local BioInputValue = Peek(BioInput)

											if EditModeValue == true then
												if next(States.Services.ProfilesService) ~= nil then
													States.Services.ProfilesService:SetNickname(NicknameInputValue)
													States.Services.ProfilesService:SetBio(BioInputValue)

													if SelectedRoleIdValue ~= nil then
														States.Services.ProfilesService
															:SetRole(Peek(SelectedRoleId))
															:andThen(function(Success: boolean, FailureReason: string?)
																if (not Success) and (FailureReason ~= nil) then
																	Prompts:PushPrompt({
																		Title = "Failure",
																		Text = FailureReason,
																		Buttons = {
																			{
																				Content = { "Close" },
																			},
																		},
																	})
																end
															end)
													end
												end
											end

											States.Menus.ProfileMenu.EditMode:set(not EditModeValue)
										end,
									},
									Scope:Button {
										Name = "JoinButton",
										Content = { Assets.Icons.General.Play, "Join" },
										Color = OnyxUI.Util.Colors.Green["500"],
										Visible = Scope:Computed(function(Use)
											local UserIdValue = Use(States.Menus.ProfileMenu.UserId)
											local InRoroomsValue = Use(States.Menus.ProfileMenu.Location.InRorooms)
											local JobIdValue = Use(States.Menus.ProfileMenu.Location.JobId)
											local IsFriendValue = Use(States.Menus.ProfileMenu.IsFriend)

											return InRoroomsValue
												and IsFriendValue
												and (JobIdValue ~= nil)
												and (JobIdValue ~= game.JobId)
												and (UserIdValue ~= LOCAL_USER_ID)
										end),

										OnActivated = function()
											local JobIdValue = Peek(States.Menus.ProfileMenu.Location.JobId)
											local PlaceIdValue = Peek(States.Menus.ProfileMenu.Location.PlaceId)

											if JobIdValue and PlaceIdValue then
												if WorldsController then
													WorldsController:TeleportToWorld(PlaceIdValue, Peek(JobIdValue))
												end
											end
										end,
									},
									Scope:Button {
										Name = "InviteButton",
										Content = { Assets.Icons.General.Mail, "Invite" },
										Color = Scope:Computed(function(Use)
											local InRoroomsValue = Use(States.Menus.ProfileMenu.Location.InRorooms)

											if InRoroomsValue then
												return Use(Theme.Colors.Neutral.Main)
											else
												return Use(Theme.Colors.Primary.Main)
											end
										end),
										Visible = Scope:Computed(function(Use)
											local UserIdValue = Use(States.Menus.ProfileMenu.UserId)
											local IsFriendValue = Use(States.Menus.ProfileMenu.IsFriend)
											local JobIdValue = Use(States.Menus.ProfileMenu.Location.JobId)

											return IsFriendValue
												and (JobIdValue ~= game.JobId)
												and (UserIdValue ~= LOCAL_USER_ID)
										end),

										OnActivated = function()
											SocialService:PromptGameInvite(
												Players.LocalPlayer,
												Scope:New "ExperienceInviteOptions" {
													InviteUser = Peek(States.Menus.ProfileMenu.UserId),
												}
											)
										end,
									},
									Scope:Button {
										Name = "FriendButton",
										Content = Scope:Computed(function(Use)
											local IsFriendValue = Use(States.Menus.ProfileMenu.IsFriend)

											if IsFriendValue then
												return { Assets.Icons.General.PersonDelete, "Unfriend" }
											else
												return { Assets.Icons.General.PersonAdd, "Friend" }
											end
										end),
										Color = Scope:Computed(function(Use)
											local IsFriendValue = Use(States.Menus.ProfileMenu.IsFriend)

											if IsFriendValue then
												return Use(Theme.Colors.Error.Main)
											else
												return Use(Theme.Colors.Primary.Main)
											end
										end),
										Visible = Scope:Computed(function(Use)
											local PlayerValue = Use(Player)
											local UserIdValue = Use(States.Menus.ProfileMenu.UserId)

											return (PlayerValue ~= nil) and (UserIdValue ~= LOCAL_USER_ID)
										end),

										OnActivated = function()
											local PlayerValue = Peek(Player)
											local IsFriendValue = Peek(States.Menus.ProfileMenu.IsFriend)

											if PlayerValue ~= nil then
												if IsFriendValue then
													StarterGui:SetCore("PromptUnfriend", PlayerValue)
												else
													StarterGui:SetCore("PromptSendFriendRequest", PlayerValue)
												end
											end
										end,
									},
									Scope:Button {
										Name = "BlockButton",
										Content = { Assets.Icons.General.Prohibited, "Block" },
										Color = Theme.Colors.Error.Main,
										Style = "Outlined",
										Visible = Scope:Computed(function(Use)
											local PlayerValue = Use(Player)
											local UserIdValue = Use(States.Menus.ProfileMenu.UserId)

											return (PlayerValue ~= nil) and (UserIdValue ~= LOCAL_USER_ID)
										end),

										OnActivated = function()
											local PlayerValue = Peek(Player)

											if PlayerValue ~= nil then
												StarterGui:SetCore("PromptBlockPlayer", PlayerValue)
											end
										end,
									},
								},
							},
						},
					},
				},
			},
		},
	}

	return ProfileMenu
end


local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local States = require(Rorooms.SourceCode.Client.UI.States)
local Prompts = require(Rorooms.SourceCode.Client.UI.States.Prompts)
local Components = require(Rorooms.SourceCode.Client.UI.Components)

local Children = Fusion.Children
local Themer = OnyxUI.Themer
local Peek = Fusion.peek

return function(Scope: Fusion.Scope<any>, Props)
	local Scope = Fusion.innerScope(Scope, Fusion, OnyxUI.Util, OnyxUI.Components, Components)
	local Theme = Themer.Theme:now()

	local CurrentPrompt = Scope:Computed(function(Use)
		return Use(States.Prompts)[#Use(States.Prompts)]
	end)
	local PromptOpen = Scope:Computed(function(Use)
		return Use(CurrentPrompt) ~= nil
	end)
	local Buttons = Scope:Computed(function(Use)
		if Use(CurrentPrompt) and Use(CurrentPrompt).Buttons then
			return Use(CurrentPrompt).Buttons
		else
			return {}
		end
	end)

	return Scope:Menu {
		Name = script.Name,
		Parent = Props.Parent,
		Open = PromptOpen,
		AnchorPoint = Vector2.new(0.5, 0.5),
		Position = Scope:Computed(function(Use)
			local YPos = Use(States.Topbar.YPosition)
			if not Use(PromptOpen) then
				YPos = YPos + 15
			end
			return UDim2.new(UDim.new(0.5, 0), UDim.new(0.5, YPos))
		end),
		Size = Scope:Computed(function(Use)
			return UDim2.fromOffset(Use(Theme.Spacing["16"]) * 1.25, 0)
		end),
		AutomaticSize = Enum.AutomaticSize.Y,
		ListHorizontalFlex = Enum.UIFlexAlignment.Fill,
		DisplayOrder = 10,

		[Children] = {
			Scope:Frame {
				Name = "Details",
				AutomaticSize = Enum.AutomaticSize.Y,
				ListEnabled = true,
				ListHorizontalFlex = Enum.UIFlexAlignment.Fill,
				ListPadding = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.Spacing["0.5"]))
				end),

				[Children] = {
					Scope:Text {
						Name = "Title",
						Text = Scope:Computed(function(Use)
							if Use(CurrentPrompt) and Use(CurrentPrompt).Title then
								return Use(CurrentPrompt).Title
							else
								return "Title"
							end
						end),
						TextSize = Theme.TextSize["1.25"],
						FontFace = Scope:Computed(function(Use)
							return Font.new(Use(Theme.Font.Heading), Use(Theme.FontWeight.Heading))
						end),
						AutomaticSize = Enum.AutomaticSize.Y,
						TextWrapped = false,
					},
					Scope:Text {
						Name = "Body",
						Text = Scope:Computed(function(Use)
							if Use(CurrentPrompt) and Use(CurrentPrompt).Text then
								return Use(CurrentPrompt).Text
							else
								return "Prompt body text"
							end
						end),
						Size = Scope:Computed(function(Use)
							return UDim2.new(UDim.new(1, 0), UDim.new(0, 0))
						end),
						AutomaticSize = Enum.AutomaticSize.Y,
						TextWrapped = true,
					},
				},
			},
			Scope:Frame {
				Name = "Buttons",
				AutomaticSize = Enum.AutomaticSize.Y,
				Visible = Scope:Computed(function(Use)
					return #Use(Buttons) >= 1
				end),
				ListEnabled = true,
				ListFillDirection = Enum.FillDirection.Horizontal,
				ListHorizontalAlignment = Enum.HorizontalAlignment.Right,

				[Children] = {
					Themer.Theme:is(Theme):during(function()
						local Theme = Themer.Theme:now()

						return Scope:ForValues(Buttons, function(Use, Scope, PromptButton)
							return Themer.Theme:is(Theme):during(function()
								return Scope:Button {
									Content = PromptButton.Content,
									Style = PromptButton.Style,
									Color = Scope:Computed(function(Use)
										if PromptButton.Color == nil then
											return Use(Theme.Colors.Primary.Main)
										else
											return PromptButton.Color
										end
									end),
									Disabled = PromptButton.Disabled,

									OnActivated = function()
										Prompts:RemovePrompt(Peek(CurrentPrompt))

										if PromptButton.Callback then
											PromptButton.Callback()
										end
									end,
								}
							end)
						end)
					end),
				},
			},
		},
	}
end


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

local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local States = require(Rorooms.SourceCode.Client.UI.States)
local Version = require(Rorooms.Version)
local Components = require(Rorooms.SourceCode.Client.UI.Components)
local Config = require(Rorooms.Config).Config
local Assets = require(Rorooms.SourceCode.Shared.Assets)

local Children = Fusion.Children
local Themer = OnyxUI.Themer
local Peek = Fusion.peek

local TOGGLEABLE_CORE_GUIS = { Enum.CoreGuiType.Chat, Enum.CoreGuiType.PlayerList }

return function(Scope: Fusion.Scope<any>, Props)
	local Scope = Fusion.innerScope(Scope, Fusion, OnyxUI.Util, OnyxUI.Components, Components)
	local Theme = Themer.Theme:now()

	local MenuOpen = Scope:Computed(function(Use)
		return Use(States.Menus.CurrentMenu) == script.Name
	end)

	Scope:Observer(States.UserSettings.HideUI):onChange(function()
		for _, CoreGuiType in ipairs(TOGGLEABLE_CORE_GUIS) do
			StarterGui:SetCoreGuiEnabled(CoreGuiType, not Peek(States.UserSettings.HideUI))
		end
		States.Topbar.Visible:set(not Peek(States.UserSettings.HideUI))
		if Peek(States.UserSettings.HideUI) then
			States.Menus.CurrentMenu:set(nil)
		end
	end)
	if Players.LocalPlayer then
		Players.LocalPlayer.CharacterAdded:Connect(function()
			States.UserSettings.HideUI:set(false)
		end)
	end

	local SettingsMenu = Scope:Menu {
		Name = script.Name,
		Parent = Props.Parent,
		Size = UDim2.fromOffset(305, 0),
		Open = MenuOpen,
		ListHorizontalFlex = Enum.UIFlexAlignment.Fill,

		[Children] = {
			Scope:Scroller {
				Size = UDim2.new(UDim.new(1, 0), UDim.new(0, 135)),
				AutomaticSize = Enum.AutomaticSize.None,
				ScrollBarThickness = Theme.StrokeThickness["1"],
				ListEnabled = true,
				Padding = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.StrokeThickness["1"]))
				end),
				PaddingRight = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.Spacing["1"]))
				end),
				ListHorizontalFlex = Enum.UIFlexAlignment.Fill,

				[Children] = {
					Scope:Frame {
						ListEnabled = true,
						ListHorizontalFlex = Enum.UIFlexAlignment.Fill,

						[Children] = {
							Scope:SettingToggle {
								Label = "Mute music",
								Switched = States.UserSettings.MuteMusic,
							},
							Scope:SettingToggle {
								Label = "Hide UI",
								Switched = States.UserSettings.HideUI,
							},
						},
					},
					Scope:Divider {},
					Scope:Button {
						Name = "VersionButton",
						Content = Scope:Computed(function(Use)
							local UpToDateValue = Use(States.Rorooms.UpToDate)
							local VersionStamp = { Assets.Icons.Rorooms.LogoGlyph, `Rorooms {Version}` }

							if UpToDateValue == false then
								table.insert(VersionStamp, `- Outdated!`)

								return VersionStamp
							else
								return VersionStamp
							end
						end),
						ContentColor = OnyxUI.Util.Colors.Black,
						Color = Scope:Computed(function(Use)
							local UpToDateValue = Use(States.Rorooms.UpToDate)

							if UpToDateValue == false then
								return Use(Theme.Colors.Warning.Main)
							else
								return Use(Theme.Colors.Primary.Main)
							end
						end),

						OnActivated = function()
							if Players.LocalPlayer ~= nil then
								pcall(function()
									MarketplaceService:PromptPurchase(Players.LocalPlayer, Config.General.AssetId)
								end)
							end
						end,
					},
				},
			},
		},
	}

	return SettingsMenu
end


local UserInputService = game:GetService("UserInputService")

local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local States = require(Rorooms.SourceCode.Client.UI.States)
local Components = require(Rorooms.SourceCode.Client.UI.Components)

local Children = Fusion.Children
local Themer = OnyxUI.Themer
local Peek = Fusion.peek
local OnEvent = Fusion.OnEvent

return function(Scope: Fusion.Scope<any>, Props)
	local Scope = Fusion.innerScope(Scope, Fusion, OnyxUI.Util, OnyxUI.Components, Components)
	local Theme = Themer.Theme:now()

	local TopbarButtonsHeight = Scope:Value(0)

	local CleanupHolder = {}

	local TopbarInstance = Scope:New "ScreenGui" {
		Name = "TopbarHUD",
		Parent = Props.Parent,
		ScreenInsets = Enum.ScreenInsets.DeviceSafeInsets,
		ResetOnSpawn = false,

		[Children] = {
			Scope:Frame {
				Name = "Topbar",
				AnchorPoint = Vector2.new(0.5, 0),
				Position = Scope:Spring(
					Scope:Computed(function(Use)
						if Use(States.Topbar.Visible) then
							return UDim2.new(UDim.new(0.5, 0), UDim.new(0, 8))
						else
							return UDim2.new(UDim.new(0.5, 0), UDim.new(0, (-Use(TopbarButtonsHeight)) - 2))
						end
					end),
					40,
					1
				),

				[Children] = {
					Scope:Frame {
						Name = "Dragger",
						ListEnabled = true,
						ListPadding = Scope:Computed(function(Use)
							return UDim.new(0, Use(Theme.Spacing["0.5"]))
						end),
						ListHorizontalAlignment = Enum.HorizontalAlignment.Center,
						Padding = Scope:Computed(function(Use)
							return UDim.new(0, Use(Theme.Spacing["0"]))
						end),
						PaddingBottom = Scope:Computed(function(Use)
							if
								(Use(States.Menus.CurrentMenu) ~= nil)
								or (not Use(States.Topbar.Visible))
								or UserInputService.TouchEnabled
							then
								return UDim.new(0, Use(Theme.Spacing["3"]))
							else
								return UDim.new(0, Use(Theme.Spacing["1"]))
							end
						end),

						[Children] = {
							Scope:Frame {
								Name = "TopbarButtons",
								BackgroundColor3 = Theme.Colors.Base.Main,
								BackgroundTransparency = States.CoreGui.PreferredTransparency,
								ListEnabled = true,
								ListPadding = Scope:Computed(function(Use)
									return UDim.new(0, Use(Theme.Spacing["0.25"]))
								end),
								ListFillDirection = Enum.FillDirection.Horizontal,
								ListVerticalAlignment = Enum.VerticalAlignment.Center,
								CornerRadius = Scope:Computed(function(Use)
									return UDim.new(0, Use(Theme.CornerRadius.Full))
								end),
								Padding = Scope:Computed(function(Use)
									return UDim.new(0, Use(Theme.Spacing["0.5"]) / 1.25)
								end),

								[Children] = {
									Scope:ForValues(States.Topbar.Buttons, function(Use, Scope, Button)
										return Themer.Theme:is(Theme):during(function()
											return Scope:TopbarButton(table.clone(Button))
										end)
									end),
								},
							},
							Scope:BaseButton {
								Name = "PullButton",
								BackgroundTransparency = States.CoreGui.PreferredTransparency,
								BackgroundColor3 = Theme.Colors.Base.Main,
								Visible = Scope:Computed(function(Use)
									return not (typeof(Use(States.Menus.CurrentMenu)) == "string")
								end),
								TextSize = 0,
								Size = Scope:Computed(function(Use)
									return UDim2.fromOffset(Use(Theme.Spacing["8"]), 6)
								end),
								CornerRadius = Scope:Computed(function(Use)
									return UDim.new(0, Use(Theme.CornerRadius.Full))
								end),
								StrokeColor = Theme.Colors.Neutral.Main,

								OnActivated = function()
									States.Topbar.Visible:set(not Peek(States.Topbar.Visible))
									States.Menus.CurrentMenu:set(nil)
								end,
							},
						},
					},
				},
			},
		},
	}

	local TopbarButtons = TopbarInstance.Topbar.Dragger.TopbarButtons
	local TopbarPully = TopbarInstance.Topbar.Dragger.PullButton

	local function UpdateTopbarBottomPos()
		States.Topbar.YPosition:set(TopbarPully.AbsolutePosition.Y)
	end

	table.insert(CleanupHolder, TopbarPully:GetPropertyChangedSignal("AbsoluteSize"):Connect(UpdateTopbarBottomPos))
	table.insert(CleanupHolder, TopbarPully:GetPropertyChangedSignal("AbsolutePosition"):Connect(UpdateTopbarBottomPos))
	UpdateTopbarBottomPos()

	local function UpdateTopbarButtonsHeight()
		TopbarButtonsHeight:set(TopbarButtons.AbsoluteSize.Y)
	end

	table.insert(
		CleanupHolder,
		TopbarButtons:GetPropertyChangedSignal("AbsoluteSize"):Connect(UpdateTopbarButtonsHeight)
	)
	UpdateTopbarButtonsHeight()

	table.insert(Scope, {
		function()
			Fusion.doCleanup(CleanupHolder)
		end,
	})

	local function AddDragDetector()
		local StartY = Vector2.new()
		local EndY = Vector2.new()

		Scope:New "UIDragDetector" {
			Parent = TopbarInstance.Topbar.Dragger,
			BoundingUI = TopbarInstance.Topbar,
			DragStyle = Enum.UIDragDetectorDragStyle.Scriptable,
			DragAxis = Vector2.new(0, 1),

			[OnEvent "DragStart"] = function(Position: Vector2)
				StartY = Position.Y
			end,
			[OnEvent "DragEnd"] = function(Position: Vector2)
				EndY = Position.Y

				local DifferenceY = StartY - EndY
				if math.abs(DifferenceY) >= 10 then
					States.Topbar.Visible:set(DifferenceY < 0)
					States.Menus.CurrentMenu:set(nil)
					States.Menus.ItemsMenu.Open:set(false)

					TopbarInstance.Topbar.Dragger.Position = UDim2.new()
				end
			end,
		}
	end

	AddDragDetector()

	return TopbarInstance
end


local MarketplaceService = game:GetService("MarketplaceService")
local RunService = game:GetService("RunService")

local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local Future = require(script.Parent.Parent.Parent.Parent.Parent.Parent.Future)
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local States = require(Rorooms.SourceCode.Client.UI.States)
local Components = require(Rorooms.SourceCode.Client.UI.Components)
local Assets = require(Rorooms.SourceCode.Shared.Assets)
local WorldsController = RunService:IsRunning() and require(Rorooms.SourceCode.Client.Worlds.WorldsController)

local Children = Fusion.Children
local Themer = OnyxUI.Themer
local Peek = Fusion.peek

return function(Scope: Fusion.Scope<any>, Props)
	local Scope = Fusion.innerScope(Scope, Fusion, OnyxUI.Util, OnyxUI.Components, Components)
	local Theme = Themer.Theme:now()

	local MenuOpen = Scope:Computed(function(Use)
		return Use(States.Menus.CurrentMenu) == script.Name
	end)
	local ProductInfo = Scope:Value({})

	local function UpdatePlaceInfo()
		if Peek(States.WorldPageMenu.PlaceId) == nil then
			return
		end

		task.spawn(function()
			Future.Try(function()
				return MarketplaceService:GetProductInfo(Peek(States.WorldPageMenu.PlaceId))
			end):After(function(Success, Result)
				if Success then
					ProductInfo:set(Result)
				else
					warn(Result)
				end
			end)
		end)
	end

	Scope:Observer(States.WorldPageMenu.PlaceId):onChange(function()
		UpdatePlaceInfo()
	end)
	UpdatePlaceInfo()

	local WorldPageMenu = Scope:Menu {
		Name = script.Name,
		Open = MenuOpen,
		Parent = Props.Parent,
		AutomaticSize = Enum.AutomaticSize.Y,
		Size = Scope:Computed(function(Use)
			return UDim2.fromOffset(Use(Theme.Spacing["24"]), 0)
		end),
		ListHorizontalFlex = Enum.UIFlexAlignment.Fill,
		ListPadding = Scope:Computed(function(Use)
			return UDim.new(0, Use(Theme.Spacing["0"]))
		end),
		Padding = Scope:Computed(function(Use)
			return UDim.new(0, Use(Theme.Spacing["0"]))
		end),

		[Children] = {
			Scope:Image {
				Name = "Thumbnail",
				Image = Scope:Computed(function(Use)
					local PlaceIdValue = Use(States.WorldPageMenu.PlaceId)
					if PlaceIdValue then
						return `rbxthumb://type=GameThumbnail&id={PlaceIdValue}&w=480&h=270`
					else
						return "rbxasset://textures/ui/GuiImagePlaceholder.png"
					end
				end),
				ScaleType = Enum.ScaleType.Crop,
				CornerRadius = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.CornerRadius["0"]))
				end),
				FlexMode = Enum.UIFlexMode.Fill,
				AspectRatio = 3,
				DominantAxis = Enum.DominantAxis.Width,
				AspectType = Enum.AspectType.ScaleWithParentSize,
			},
			Scope:Frame {
				Name = "Content",
				AutomaticSize = Enum.AutomaticSize.Y,
				ListEnabled = true,
				ListPadding = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.Spacing["1"]))
				end),
				ListHorizontalFlex = Enum.UIFlexAlignment.Fill,
				Padding = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.Spacing["1"]))
				end),

				[Children] = {
					Scope:Frame {
						Name = "Details",
						AutomaticSize = Enum.AutomaticSize.Y,
						ListEnabled = true,
						ListHorizontalFlex = Enum.UIFlexAlignment.Fill,
						ListPadding = Scope:Computed(function(Use)
							return UDim.new(0, Use(Theme.Spacing["0.25"]))
						end),

						[Children] = {
							Scope:Text {
								Name = "Name",
								AutomaticSize = Enum.AutomaticSize.Y,
								Text = Scope:Computed(function(Use)
									if Use(ProductInfo) and Use(ProductInfo).Name then
										return Use(ProductInfo).Name
									else
										return "Name"
									end
								end),
								TextSize = Theme.TextSize["1.5"],
								FontFace = Scope:Computed(function(Use)
									return Font.new(Use(Theme.Font.Heading), Use(Theme.FontWeight.Heading))
								end),
								TextTruncate = Enum.TextTruncate.AtEnd,
								RichText = false,
								AutoLocalize = false,
							},
							Scope:Text {
								Name = "Description",
								Text = Scope:Computed(function(Use)
									if Use(ProductInfo) and Use(ProductInfo).Description then
										return Use(ProductInfo).Description
									else
										return "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
									end
								end),
								AutomaticSize = Enum.AutomaticSize.Y,
								TextTruncate = Enum.TextTruncate.AtEnd,
								TextWrapped = false,
								RichText = false,
								AutoLocalize = false,
								ClipsDescendants = true,
								MaxSize = Scope:Computed(function(Use)
									return Vector2.new(math.huge, Use(Theme.TextSize["1"]))
								end),
							},
						},
					},
					Scope:Button {
						Name = "PlayButton",
						Color = OnyxUI.Util.Colors.Green["500"],
						AutomaticSize = Enum.AutomaticSize.Y,
						Content = { Assets.Icons.General.Play },
						ContentSize = Theme.TextSize["1.5"],

						OnActivated = function(): ()
							if WorldsController then
								States.Menus.CurrentMenu:set(nil)
								WorldsController:TeleportToWorld(Peek(States.WorldPageMenu.PlaceId))
							end
						end,
					},
				},
			},
		},
	}

	return WorldPageMenu
end


local RunService = game:GetService("RunService")
local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local States = require(Rorooms.SourceCode.Client.UI.States)
local Worlds = require(Rorooms.SourceCode.Client.UI.States.Worlds)
local Config = require(Rorooms.Config).Config
local Components = require(Rorooms.SourceCode.Client.UI.Components)
local Assets = require(Rorooms.SourceCode.Shared.Assets)

local Children = Fusion.Children
local Themer = OnyxUI.Themer
local OnChange = Fusion.OnChange
local Out = Fusion.Out

return function(Scope: Fusion.Scope<any>, Props)
	local Scope = Fusion.innerScope(Scope, Fusion, OnyxUI.Util, OnyxUI.Components, Components)
	local Theme = Themer.Theme:now()

	local MenuOpen = Scope:Computed(function(Use)
		return Use(States.Menus.CurrentMenu) == script.Name
	end)

	Scope:Observer(MenuOpen):onChange(function()
		if Fusion.peek(MenuOpen) then
			Worlds:FetchAssortedWorlds()
		end
	end)

	local AbsoluteCanvasSize = Scope:Value(Vector2.new())
	local AbsoluteWindowSize = Scope:Value(Vector2.new())

	local WorldsMenu = Scope:Menu {
		Name = script.Name,
		Open = MenuOpen,
		Parent = Props.Parent,
		AutomaticSize = Enum.AutomaticSize.Y,
		Size = UDim2.fromOffset(390, 0),
		ListHorizontalFlex = Enum.UIFlexAlignment.Fill,

		[Children] = {
			Scope:Hydrate(Scope:Scroller {
				Name = "WorldsList",
				Size = UDim2.new(UDim.new(0, 0), UDim.new(0, 205)),
				CanvasSize = UDim2.fromOffset(0, 0),
				ScrollBarThickness = Theme.StrokeThickness["1"],
				Padding = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.StrokeThickness["1"]))
				end),
				PaddingRight = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.Spacing["0.75"]))
				end),
				ListEnabled = true,
				ListPadding = Scope:Computed(function(Use)
					return UDim.new(0, Use(Theme.Spacing["1.5"]))
				end),
				ListHorizontalFlex = Enum.UIFlexAlignment.Fill,

				[Children] = {
					Scope:Card {
						ListEnabled = true,
						ListHorizontalFlex = Enum.UIFlexAlignment.Fill,
						CornerRadius = Scope:Computed(function(Use)
							return UDim.new(0, Use(Theme.CornerRadius["2"]))
						end),
						Visible = Scope:Computed(function(Use)
							return (not Use(States.Worlds.Registered))
								and (RunService:IsStudio())
								and (Config.Systems.Worlds.DiscoveryEnabled == true)
						end),

						[Children] = {
							Scope:Frame {
								ListEnabled = true,
								ListPadding = Scope:Computed(function(Use)
									return UDim.new(0, Use(Theme.Spacing["0.5"]))
								end),
								ListHorizontalFlex = Enum.UIFlexAlignment.Fill,

								[Children] = {
									Scope:Heading {
										Text = "Not registered!",
										HeadingSize = 1.2,
									},
									Scope:Text {
										Text = "Enable permissions and register to receive teleports from other worlds. Read more:",
									},
								},
							},
							Scope:TextInput {
								Text = "devforum.roblox.com/t/3248014/18",
								Disabled = true,
								TextTransparency = 0,
								StrokeTransparency = 0,
							},
						},
					},
					Scope:WorldsCategory {
						Name = "Featured",
						Title = "From creator",
						Icon = Assets.Icons.General.Star,
						Visible = Scope:Computed(function(Use)
							return (#Config.Systems.Worlds.FeaturedWorlds >= 1)
								and Config.Systems.Worlds.DiscoveryEnabled
						end),

						[Children] = {
							Scope:Frame {
								Name = "Worlds",
								AutomaticSize = Enum.AutomaticSize.Y,
								ListEnabled = true,
								ListPadding = Scope:Computed(function(Use)
									return UDim.new(0, Use(Theme.Spacing["0.75"]))
								end),
								ListFillDirection = Enum.FillDirection.Horizontal,
								ListWraps = true,

								[Children] = {
									Scope:ForValues(
										Config.Systems.Worlds.FeaturedWorlds,
										function(Use, Scope, PlaceId: number)
											return Themer.Theme:is(Theme):during(function()
												return Scope:WorldButton {
													PlaceId = PlaceId,
												}
											end)
										end
									),
								},
							},
						},
					},
					Scope:WorldsCategory {
						Name = "Global",
						Title = "Global",
						Icon = Assets.Icons.General.Globe,
						Visible = Scope:Computed(function(Use)
							return Config.Systems.Worlds.DiscoveryEnabled
						end),

						[Children] = {
							Scope:Frame {
								Name = "Worlds",
								AutomaticSize = Enum.AutomaticSize.Y,
								ListEnabled = true,
								ListPadding = Scope:Computed(function(Use)
									return UDim.new(0, Use(Theme.Spacing["0.75"]))
								end),
								ListFillDirection = Enum.FillDirection.Horizontal,
								ListWraps = true,

								[Children] = {
									Scope:ForValues(States.Worlds.AssortedWorlds, function(Use, Scope, World)
										return Themer.Theme:is(Theme):during(function()
											return Scope:WorldButton {
												PlaceId = World.PlaceId,
												Random = World.Random,
											}
										end)
									end),
								},
							},
						},
					},
				},
			}) {
				[OnChange "CanvasPosition"] = function(CanvasPosition)
					local CanvasHeight = Fusion.peek(AbsoluteCanvasSize).Y - Fusion.peek(AbsoluteWindowSize).Y

					if CanvasPosition.Y >= CanvasHeight then
						Worlds:FetchAssortedWorlds()
					end
				end,
				[Out "AbsoluteCanvasSize"] = AbsoluteCanvasSize,
				[Out "AbsoluteWindowSize"] = AbsoluteWindowSize,
			},
		},
	}

	return WorldsMenu
end


local GuiService = game:GetService("GuiService")

local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local Fusion = require(Rorooms.Parent.Fusion)
local States = require(script.Parent)
local Peek = Fusion.peek

local CoreGui = {
	Scope = Fusion.scoped(Fusion),
}

CoreGui.IsUnibarOpen = CoreGui.Scope:Computed(function(Use)
	return Use(States.CoreGui.TopbarInset).Min.X > 250
end)

function CoreGui:Start()
	States.CoreGui.TopbarInset:set(GuiService.TopbarInset)

	GuiService:GetPropertyChangedSignal("TopbarInset"):Connect(function()
		States.CoreGui.TopbarInset:set(GuiService.TopbarInset)
	end)

	GuiService:GetPropertyChangedSignal("MenuIsOpen"):Connect(function()
		States.CoreGui.RobloxMenuOpen:set(GuiService.MenuIsOpen)
	end)

	self.Scope:Observer(self.IsUnibarOpen):onChange(function()
		States.Topbar.Visible:set(not Peek(CoreGui.IsUnibarOpen))
		if Peek(CoreGui.IsUnibarOpen) then
			States.Menus.CurrentMenu:set(nil)
		end
	end)

	self.Scope:Observer(States.CoreGui.RobloxMenuOpen):onChange(function()
		States.Topbar.Visible:set(not Peek(States.CoreGui.RobloxMenuOpen))
		if Peek(States.CoreGui.RobloxMenuOpen) then
			States.Menus.CurrentMenu:set(nil)
			States.Menus.ItemsMenu.Open:set(false)
		end
	end)

	local function UpdatePrefferedTransparency()
		local Transparency = math.clamp(GuiService.PreferredTransparency / 4, 0, 0.15)
		States.CoreGui.PreferredTransparency:set(Transparency)
	end

	UpdatePrefferedTransparency()
	GuiService:GetPropertyChangedSignal("PreferredTransparency"):Connect(function()
		UpdatePrefferedTransparency()
	end)
end

return CoreGui


local RunService = game:GetService("RunService")

local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local States = require(script.Parent)
local Future = require(Rorooms.Parent.Future)
local Fusion = require(Rorooms.Parent.Fusion)
local Types = require(Rorooms.SourceCode.Shared.Types)
local ProfilesController = RunService:IsRunning() and require(Rorooms.SourceCode.Client.Profiles.ProfilesController)

local Profiles = {}

function Profiles.SafeProfileValue(
	Scope: Fusion.Scope<typeof(Fusion)>,
	ProfileValue: Fusion.Value<Fusion.Scope<any>, Types.Profile?>
)
	return Scope:Computed(function(Use): Types.Profile
		local Profile: Types.Profile = Use(ProfileValue)

		if Profile then
			return Profile
		else
			return {
				Nickname = "Name",
				DisplayName = "Name",
				Username = "Username",
				Role = nil,
				Bio = nil,
				Level = 0,
			}
		end
	end)
end

function Profiles.ProfileValue(
	Scope: Fusion.Scope<typeof(Fusion)>,
	UserId: Fusion.UsedAs<number>
): Fusion.Value<Fusion.Scope<any>, Types.Profile?>
	local ProfileValue = Scope:Value(nil)

	local function UpdateProfile()
		task.spawn(function()
			local UserIdValue = Fusion.peek(UserId) or 0

			if UserIdValue > 0 then
				local RetrievedProfile = Profiles:GetProfile(UserIdValue)
				if RetrievedProfile then
					ProfileValue:set(RetrievedProfile)
					return
				end
			end

			ProfileValue:set(nil)
		end)
	end

	Scope:Observer(UserId):onChange(function()
		UpdateProfile()
	end)
	if ProfilesController then
		ProfilesController.ProfileUpdated:Connect(function(UpdatedUserId: number)
			if UpdatedUserId == Fusion.peek(UserId) then
				Profiles:FetchProfile(UpdatedUserId)
				UpdateProfile()
			end
		end)
	end

	UpdateProfile()

	return ProfileValue
end

function Profiles:GetProfile(UserId: number): Types.Profile?
	local LoadedProfiles = Fusion.peek(States.Profiles.Loaded)
	local ExistingProfile = LoadedProfiles[UserId]

	if ExistingProfile ~= nil then
		return ExistingProfile
	else
		return self:FetchProfile(UserId)
	end
end

function Profiles:FetchProfile(UserId: number): Types.Profile?
	if UserId <= 0 then
		UserId = 1
	end

	local Profile
	local LoadedProfiles = Fusion.peek(States.Profiles.Loaded)

	local Success, Result = Future.Try(function()
		if next(States.Services.ProfilesService) ~= nil then
			local Success2, Result2 = States.Services.ProfilesService:GetProfile(UserId):await()
			if Success2 and Result2 then
				return Result2
			end
		end
		return nil
	end):Await()
	if Success and Result then
		Profile = Result
	end

	LoadedProfiles[UserId] = Profile
	States.Profiles.Loaded:set(LoadedProfiles)

	return Profile
end

return Profiles


local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local ReconcileTable = require(Rorooms.SourceCode.Shared.ExtPackages.ReconcileTable)
local States = require(script.Parent)
local Fusion = require(Rorooms.Parent.Fusion)

local Peek = Fusion.peek

type Prompt = {
	Title: string,
	Text: string,
	Buttons: {
		[number]: {
			Content: { [number]: string },
			Style: string?,
			Disabled: boolean?,
			Callback: () -> ()?,
		},
	},
}

local PROMPT_TEMPLATE = {
	Title = "",
	Text = "",
	Buttons = {},
}

local Prompts = {}

function Prompts:PushPrompt(Prompt: Prompt)
	local NewPrompts = Peek(States.Prompts)

	ReconcileTable(Prompt, PROMPT_TEMPLATE)

	for _, ExistingPrompt in ipairs(NewPrompts) do
		if ExistingPrompt.Text == Prompt.Text then
			return
		end
	end

	table.insert(NewPrompts, Prompt)

	States.Prompts:set(NewPrompts)
end

function Prompts:RemovePrompt(Prompt: Prompt)
	local NewPrompts = Peek(States.Prompts)

	for Index = #NewPrompts, 1, -1 do
		if NewPrompts[Index] == Prompt then
			table.remove(NewPrompts, Index)
			break
		end
	end

	States.Prompts:set(NewPrompts)
end

return Prompts


local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local States = require(script.Parent)
local Knit = require(Rorooms.Parent.Knit)

local RemoteProperties = {}

function RemoteProperties:Start()
	local ItemsController = require(Rorooms.SourceCode.Client.Items.ItemsController)

	ItemsController.EquippedItemsUpdated:Connect(function(EquippedItems)
		States.Items.Equipped:set(EquippedItems)
	end)

	local LevelingService = Knit.GetService("LevelingService")
	local UpdatesService = Knit.GetService("UpdatesService")

	LevelingService.Level:Observe(function(Level)
		States.Leveling.Level:set(Level)
	end)

	UpdatesService.UpToDate:Observe(function(UpToDate)
		States.Rorooms.UpToDate:set(UpToDate)
	end)
end

return RemoteProperties


local Workspace = game:GetService("Workspace")

local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local Fusion = require(Rorooms.Parent.Fusion)
local States = require(script.Parent)

local Out = Fusion.Out

local ScreenSize = {
	Scope = Fusion.scoped(Fusion),
}

function ScreenSize:Start()
	self.Scope:Hydrate(Workspace.CurrentCamera) {
		[Out "ViewportSize"] = States.CoreGui.ScreenSize,
	}
end

return ScreenSize


local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local Knit = require(Rorooms.Parent.Knit)
local States = require(script.Parent)

type KnitService = typeof(Knit.GetService)

local Services = {}

function Services:Start()
	Knit.OnStart():andThen(function()
		for ServiceName, _ in pairs(States.Services) do
			States.Services[ServiceName] = Knit.GetService(ServiceName)
		end
	end)
end

return Services


local Players = game:GetService("Players")

local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local States = require(script.Parent)
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local Fusion = require(Rorooms.Parent.Fusion)
local Assets = require(Rorooms.SourceCode.Shared.Assets)

local Peek = Fusion.peek
local Themer = OnyxUI.Themer

local Theme = Themer.Theme:now()

local Topbar = {
	Scope = Fusion.scoped(Fusion),
}

Topbar.NativeButtons = {
	Settings = {
		MenuName = "SettingsMenu",
		Icon = Assets.Icons.Topbar.Settings.Outlined,
		IconFilled = Assets.Icons.Topbar.Settings.Filled,
		LayoutOrder = 5,
		IndicatorColor = Theme.Colors.Warning.Main,
		IndicatorEnabled = Topbar.Scope:Computed(function(Use)
			return Use(States.Rorooms.UpToDate) == false
		end),
	},
	Emotes = {
		MenuName = "EmotesMenu",
		Icon = Assets.Icons.Topbar.Emotes.Outlined,
		IconFilled = Assets.Icons.Topbar.Emotes.Filled,
		LayoutOrder = 3,
	},
	Friends = {
		MenuName = "FriendsMenu",
		Icon = Assets.Icons.Topbar.Friends.Outlined,
		IconFilled = Assets.Icons.Topbar.Friends.Filled,
		LayoutOrder = 2,
	},
	Profile = {
		MenuName = "ProfileMenu",
		Icon = Assets.Icons.Topbar.Profile.Outlined,
		IconFilled = Assets.Icons.Topbar.Profile.Filled,
		LayoutOrder = 1,
		Callback = function()
			if Players.LocalPlayer then
				States.Menus.ProfileMenu.UserId:set(Players.LocalPlayer.UserId)
			else
				States.Menus.ProfileMenu.UserId:set(1)
			end
		end,
	},
	Worlds = {
		MenuName = "WorldsMenu",
		Icon = Assets.Icons.Topbar.Worlds.Outlined,
		IconFilled = Assets.Icons.Topbar.Worlds.Filled,
		LayoutOrder = 4,
	},
}

function Topbar:AddDefaultButtons()
	for Name, Button in pairs(self.NativeButtons) do
		self:AddTopbarButton(Name, Button)
	end
end

function Topbar:AddTopbarButton(
	Name: string,
	Button: {
		[string]: {
			MenuName: string,
			Icon: string,
			SizeMultiplier: number,
			LayoutOrder: number,
		},
	}
)
	local TopbarButtons = Peek(States.Topbar.Buttons)

	TopbarButtons[Name] = Button

	States.Topbar.Buttons:set(TopbarButtons)
end

function Topbar:RemoveTopbarButton(Name: string)
	local TopbarButtons = Peek(States.Topbar.Buttons)

	TopbarButtons[Name] = nil

	States.Topbar.Buttons:set(TopbarButtons)
end

return Topbar


local Rorooms = script.Parent.Parent.Parent.Parent.Parent
local Fusion = require(Rorooms.Parent.Fusion)
local States = require(script.Parent)
local Knit = require(Rorooms.Parent.Knit)

local Peek = Fusion.peek

local ROW_SIZE = 3
local RANDOM_WORLD_BASIS = ROW_SIZE * 3
local DEFAULT_WORLD_COUNT = 10 * ROW_SIZE

local TopWorldsService
local RandomWorldsService

type World = {
	PlaceId: number,
}
type Worlds = {
	[number]: World,
}

local Worlds = {}

function Worlds:FetchAssortedWorlds(Count: number?)
	if Count == nil then
		Count = DEFAULT_WORLD_COUNT
	end

	local RandomWorldsPromise = self:FetchRandomWorlds(Count, true)
	if RandomWorldsPromise ~= nil then
		RandomWorldsPromise:await()
	end

	local TopWorldsPromise = self:FetchTopWorlds(Count, true)
	if TopWorldsPromise ~= nil then
		TopWorldsPromise:await()
	end

	self:LoadAssortedWorlds(Count)
end

function Worlds:LoadAssortedWorlds(Count: number?)
	if Count == nil then
		Count = DEFAULT_WORLD_COUNT
	end

	local AssortedWorldsValue = Peek(States.Worlds.AssortedWorlds)
	local TopWorldsValue = Peek(States.Worlds.TopWorlds)
	local StartIndex = #AssortedWorldsValue
	local EndIndex = StartIndex + Count

	self:_RemovePlaceIdFromArray(TopWorldsValue, game.PlaceId)

	for Index = StartIndex, EndIndex do
		local World = TopWorldsValue[Index]
		if World then
			if math.random(1, RANDOM_WORLD_BASIS) == RANDOM_WORLD_BASIS then
				local RandomWorld = self:GetUnusedRandomWorld(AssortedWorldsValue)
				if RandomWorld ~= nil then
					RandomWorld.Random = true
					table.insert(AssortedWorldsValue, RandomWorld)
				end
			else
				if self:_FindPlaceIdInWorldsArray(AssortedWorldsValue, World.PlaceId) == nil then
					table.insert(AssortedWorldsValue, World)
				end
			end
		end
	end

	local FillerStartIndex = #AssortedWorldsValue
	local FillerEndIndex = FillerStartIndex + (EndIndex - FillerStartIndex)

	if FillerEndIndex > FillerStartIndex then
		for _ = FillerStartIndex, FillerEndIndex do
			local RandomWorld = self:GetUnusedRandomWorld(AssortedWorldsValue)
			if RandomWorld ~= nil then
				RandomWorld.Random = true
				table.insert(AssortedWorldsValue, RandomWorld)
			else
				break
			end
		end
	end

	States.Worlds.AssortedWorlds:set(AssortedWorldsValue)

	return AssortedWorldsValue
end

function Worlds:GetUnusedRandomWorld(UsedWorlds: Worlds)
	local RandomWorldsValue = Peek(States.Worlds.RandomWorlds)

	self:_RemovePlaceIdFromArray(RandomWorldsValue, game.PlaceId)

	if #RandomWorldsValue == 0 then
		return nil
	end

	local ChosenWorld = RandomWorldsValue[math.random(1, #RandomWorldsValue)]
	local ExistingIndex = self:_FindPlaceIdInWorldsArray(UsedWorlds, ChosenWorld.PlaceId)

	if #UsedWorlds >= #RandomWorldsValue then
		return nil
	elseif ExistingIndex == nil then
		return ChosenWorld
	else
		return self:GetUnusedRandomWorld(UsedWorlds)
	end
end

function Worlds:FetchTopWorlds(Count: number?, OnlyIfEmpty: boolean?)
	if Count == nil then
		Count = DEFAULT_WORLD_COUNT
	end

	if TopWorldsService then
		return TopWorldsService:GetTopWorlds(#Peek(States.Worlds.TopWorlds), Count):andThen(function(TopWorlds: Worlds?)
			if OnlyIfEmpty and #Peek(States.Worlds.TopWorlds) > 0 then
				return
			else
				self:_AddTopWorlds(TopWorlds)
			end

			return TopWorlds
		end)
	end

	return nil
end

function Worlds:_AddTopWorlds(TopWorlds: Worlds)
	local NewTopWorlds = Peek(States.Worlds.TopWorlds)

	for _, World in ipairs(TopWorlds) do
		if self:_FindPlaceIdInWorldsArray(NewTopWorlds, World.PlaceId) == nil then
			table.insert(NewTopWorlds, World)
		end
	end

	States.Worlds.TopWorlds:set(NewTopWorlds)
end

function Worlds:FetchRandomWorlds(Count: number?, OnlyIfEmpty: boolean?)
	if Count == nil then
		Count = DEFAULT_WORLD_COUNT
	end

	local StartIndex = #Peek(States.Worlds.RandomWorlds)

	if RandomWorldsService then
		return RandomWorldsService:GetRandomWorlds(StartIndex, Count):andThen(function(RandomWorlds: Worlds)
			if OnlyIfEmpty and #Peek(States.Worlds.RandomWorlds) > 0 then
				return
			else
				self:_AddRandomWorlds(RandomWorlds)
			end

			return RandomWorlds
		end)
	end

	return nil
end

function Worlds:_AddRandomWorlds(RandomWorlds: Worlds)
	local NewRandomWorlds = Peek(States.Worlds.RandomWorlds)

	for _, World in ipairs(RandomWorlds) do
		if self:_FindPlaceIdInWorldsArray(NewRandomWorlds, World.PlaceId) == nil then
			table.insert(NewRandomWorlds, World)
		end
	end

	States.Worlds.RandomWorlds:set(NewRandomWorlds)
end

function Worlds:_RemovePlaceIdFromArray(WorldsArray: { [number]: World }, PlaceId: number)
	local EntryIndex = self:_FindPlaceIdInWorldsArray(WorldsArray, PlaceId)
	if EntryIndex ~= nil then
		table.remove(WorldsArray, EntryIndex)
	end
end

function Worlds:_FindPlaceIdInWorldsArray(WorldsArray: { [number]: World }, PlaceId: number)
	for Index, World in ipairs(WorldsArray) do
		if World.PlaceId == PlaceId then
			return Index, World
		end
	end

	return nil
end

function Worlds:ClearWorlds(WorldsObject: Fusion.Value<Fusion.Scope<any>, Worlds>)
	WorldsObject:set({})
end

function Worlds:ClearRandomWorlds()
	States.Worlds.RandomWorlds:set({})
end

function Worlds:Start()
	TopWorldsService = Knit.GetService("TopWorldsService")
	RandomWorldsService = Knit.GetService("RandomWorldsService")
end

return Worlds


local Rorooms = script.Parent.Parent.Parent.Parent
local Fusion = require(Rorooms.Parent.Fusion)
local Loader = require(Rorooms.Parent.Loader)

local function UnloadedService(): { [any]: any }
	return {}
end

local Scope = Fusion.scoped(Fusion)

local States = {
	Services = {
		ProfilesService = UnloadedService(),
		WorldsService = UnloadedService(),
		ItemsService = UnloadedService(),
		EmotesService = UnloadedService(),
		TopWorldsService = UnloadedService(),
		RandomWorldsService = UnloadedService(),
		UpdatesService = UnloadedService(),
		LevelingService = UnloadedService(),
		WorldRegistryService = UnloadedService(),
	},
	Controllers = {
		UIController = nil,
		EmotesController = nil,
		ItemsController = nil,
		FriendsController = nil,
	},
	Prompts = Scope:Value({}),
	Menus = {
		CurrentMenu = Scope:Value(),
		ItemsMenu = {
			Open = Scope:Value(false),
			FocusedCategory = Scope:Value(nil),
		},
		EmotesMenu = {
			FocusedCategory = Scope:Value(nil),
		},
		ProfileMenu = {
			UserId = Scope:Value(nil),
			EditMode = Scope:Value(false),
			IsFriend = Scope:Value(false),
			Location = {
				Online = Scope:Value(false),
				InRorooms = Scope:Value(false),
				PlaceId = Scope:Value(nil),
				JobId = Scope:Value(nil),
			},
		},
	},
	Topbar = {
		YPosition = Scope:Value(0),
		Visible = Scope:Value(true),
		Buttons = Scope:Value({}),
	},
	Items = {
		Equipped = Scope:Value({}),
	},
	Profiles = {
		Loaded = Scope:Value({}),
	},
	WorldPageMenu = {
		PlaceId = Scope:Value(),
	},
	Leveling = {
		Level = Scope:Value(0),
	},
	UserSettings = {
		MuteMusic = Scope:Value(false),
		HideUI = Scope:Value(false),
	},
	Friends = {
		Online = Scope:Value({}),
		InRorooms = Scope:Value({}),
		NotInRorooms = Scope:Value({}),
	},
	CoreGui = {
		TopbarInset = Scope:Value(Rect.new(Vector2.new(), Vector2.new())),
		RobloxMenuOpen = Scope:Value(false),
		PreferredTransparency = Scope:Value(0.15),
		ScreenSize = Scope:Value(Vector2.new()),
	},
	Worlds = {
		AssortedWorlds = Scope:Value({}),
		TopWorlds = Scope:Value({}),
		RandomWorlds = Scope:Value({}),
		Registered = Scope:Value(false),
	},
	Loading = Scope:Value(false),
	Rorooms = {
		UpToDate = Scope:Value(),
	},
}

function States:_StartExtensions()
	Loader.SpawnAll(Loader.LoadChildren(script), "Start")
end

function States:_InitializeExtensions()
	Loader.LoadChildren(script)
end

function States:Start()
	self:_InitializeExtensions()
	self:_StartExtensions()
end

return States


local Players = game:GetService("Players")

local Rorooms = script.Parent.Parent.Parent.Parent
local Fusion = require(Rorooms.Parent.Fusion)
local States = require(Rorooms.SourceCode.Client.UI.States)
local OnyxUI = require(Rorooms.Parent.OnyxUI)
local OnyxUITheme = require(script.Parent.OnyxUITheme)
local Config = require(Rorooms.Config).Config

local Themer = OnyxUI.Themer

local DEFAULT_UIS = { "TopbarHUD", "PromptHUD" }

local function DeepCopyTable(Table)
	local Copy = {}
	for Key, Value in pairs(Table) do
		if type(Value) == "table" then
			Copy[Key] = DeepCopyTable(Value)
		else
			Copy[Key] = Value
		end
	end
	return Copy
end

local function ReconcileTable(Target, Template)
	for Key, Value in pairs(Template) do
		if type(Target[Key]) == "table" and type(Value) == "table" then
			ReconcileTable(Target[Key], Value)
		else
			if type(Value) == "table" then
				Target[Key] = DeepCopyTable(Value)
			else
				Target[Key] = Value
			end
		end
	end
end

local UIController = {
	Name = "UIController",

	Scope = Fusion.scoped(Fusion),
	XPMultiplierDropdownIcons = {},
}

function UIController:MountUI(Component)
	local PreferredTheme = OnyxUITheme

	ReconcileTable(OnyxUITheme, Config.Systems.UI.OnyxUITheme)

	PreferredTheme = OnyxUI.Themer.NewTheme(self.Scope, PreferredTheme)

	return Themer.Theme:is(PreferredTheme):during(function()
		local UIObject = Component(self.Scope, {
			Parent = self.RoroomsUI,
		})

		return UIObject
	end)
end

function UIController:KnitStart()
	States:Start()

	for _, GuiName in ipairs(DEFAULT_UIS) do
		local GuiModule = Rorooms.SourceCode.Client.UI.ScreenGuis:FindFirstChild(GuiName)
		if GuiModule then
			local Gui = require(GuiModule)
			self:MountUI(Gui)
		end
	end
end

UIController.RoroomsUI = UIController.Scope:New "ScreenGui" {
	Name = "RoroomsUI",
	Parent = Players.LocalPlayer:WaitForChild("PlayerGui"),
	ResetOnSpawn = false,
}

return UIController


local RunService = game:GetService("RunService")
local Rorooms = script.Parent.Parent.Parent.Parent
local Fusion = require(Rorooms.Parent.Fusion)
local States = require(Rorooms.SourceCode.Client.UI.States)
local Prompts = require(Rorooms.SourceCode.Client.UI.States.Prompts)

local Peek = Fusion.peek

local UpdatesController = {
	Name = script.Name,
	Scope = Fusion.scoped(Fusion),
}

function UpdatesController:KnitStart()
	local LastUpToDate: boolean?

	if RunService:IsStudio() then
		self.Scope:Observer(States.Rorooms.UpToDate):onChange(function()
			local UpToDate = Peek(States.Rorooms.UpToDate)
			if (UpToDate == false) and (LastUpToDate ~= UpToDate) then
				Prompts:PushPrompt({
					Title = "Update available ✨",
					Text = "Rorooms is out of date. Please update to receive the latest bug-fixes and improvements.",
					Buttons = {
						{
							Content = { "Close" },
						},
					},
				})
			end

			LastUpToDate = Peek(States.Rorooms.UpToDate)
		end)
	end
end

return UpdatesController


local MarketplaceService = game:GetService("MarketplaceService")
local TeleportService = game:GetService("TeleportService")

local Rorooms = script.Parent.Parent.Parent.Parent
local Knit = require(Rorooms.Parent.Knit)
local Topbar = require(Rorooms.SourceCode.Client.UI.States.Topbar)
local UIController = require(Rorooms.SourceCode.Client.UI.UIController)
local Prompts = require(Rorooms.SourceCode.Client.UI.States.Prompts)
local States = require(Rorooms.SourceCode.Client.UI.States)
local Future = require(Rorooms.Parent.Future)

local WorldRegistryService

local WorldsController = {
	Name = "WorldsController",
}

function WorldsController:TeleportToWorld(PlaceId: number, JobId: string?, RequireConfirmation: boolean?)
	return Future.Try(function()
		return MarketplaceService:GetProductInfo(PlaceId, Enum.InfoType.Asset)
	end):After(function(FetchSuccess, PlaceInfo)
		if FetchSuccess and (PlaceInfo ~= nil) then
			local function Teleport()
				if next(States.Services.WorldsService) ~= nil then
					States.Services.WorldsService
						:TeleportToWorld(PlaceId)
						:andThen(function(TeleportSuccess: boolean, Message: string)
							States.Menus.CurrentMenu:set(nil)
							States.Loading:set(true)

							task.wait(5)

							States.Loading:set(false)

							if not TeleportSuccess then
								Prompts:PushPrompt({
									Title = "Error",
									Text = Message,
									Buttons = {
										{
											Content = { "Dismiss" },
										},
									},
								})
							end
						end)
				end
			end
			local function AskConfirmation()
				Prompts:PushPrompt({
					Title = "Teleport",
					Text = `Do you want to teleport to {PlaceInfo.Name}?`,
					Buttons = {
						{
							Content = { "Cancel" },
							Style = "Outlined",
						},
						{
							Content = { "Teleport" },
							Callback = function()
								Teleport()
							end,
						},
					},
				})
			end

			if (JobId ~= nil) and (JobId == game.JobId) then
				Prompts:PushPrompt({
					Title = "Rejoin",
					Text = "You're already in this server. Would you like to rejoin?",
					Buttons = {
						{
							Content = { "Cancel" },
							Style = "Outlined",
						},
						{
							Content = { "Teleport" },
							Callback = function()
								Teleport()
							end,
						},
					},
				})
			else
				if RequireConfirmation then
					AskConfirmation()
				else
					Teleport()
				end
			end
		end
	end)
end

function WorldsController:KnitStart()
	UIController = Knit.GetController("UIController")
	WorldRegistryService = Knit.GetService("WorldRegistryService")

	UIController:MountUI(require(Rorooms.SourceCode.Client.UI.ScreenGuis.WorldsMenu))
	UIController:MountUI(require(Rorooms.SourceCode.Client.UI.ScreenGuis.WorldPageMenu))
	local LoadingScreen = UIController:MountUI(require(Rorooms.SourceCode.Client.UI.ScreenGuis.LoadingScreen))

	TeleportService:SetTeleportGui(LoadingScreen)

	Topbar:AddTopbarButton("Worlds", Topbar.NativeButtons.Worlds)

	WorldRegistryService.Registered:Observe(function(Registered: boolean)
		States.Worlds.Registered:set(Registered)
	end)
end

return WorldsController


local ComponentsService = {
	Name = script.Name,
}

function ComponentsService:KnitStart()
	for _, Module in ipairs(script.Parent:GetChildren()) do
		if Module:IsA("ModuleScript") and Module ~= script then
			require(Module)
		end
	end
end

return ComponentsService


local Rorooms = script.Parent.Parent.Parent.Parent
local Component = require(Rorooms.Parent.Component)
local Zone = require(Rorooms.Parent.Zone)
local Fusion = require(Rorooms.Parent.Fusion)
local AttributeBind = require(Rorooms.SourceCode.Shared.ExtPackages.AttributeBind)
local Trove = require(Rorooms.Parent.Trove)
local PlayerDataStoreService = require(Rorooms.SourceCode.Server.PlayerDataStore.PlayerDataStoreService)
local GamepassesHandler = require(Rorooms.SourceCode.Shared.ExtPackages.GamepassesHandler)

local Peek = Fusion.peek

local LockedZoneComponent = Component.new {
	Tag = "RR_LockedZone",
}

function LockedZoneComponent:Start()
	self.Zone.playerEntered:Connect(function(Player: Player)
		local CanPlayerAccess = self:_IsPlayerAccepted(Player)

		if not CanPlayerAccess then
			Player:LoadCharacter()
		end
	end)
end

function LockedZoneComponent:_IsPlayerAccepted(Player: Player)
	local LevelRequirementValue = Peek(self.LevelRequirement)
	local GamepassRequirementValue = Peek(self.GamepassRequirement)

	local Profile = PlayerDataStoreService:GetProfile(Player.UserId)
	if Profile then
		if Profile.Data.Level < LevelRequirementValue then
			return false
		end
	end

	if GamepassRequirementValue ~= nil then
		local OwnsGamepass = GamepassesHandler:PlayerOwnsGamepass(Player, GamepassRequirementValue)

		if not OwnsGamepass then
			return false
		end
	end

	return true
end

function LockedZoneComponent:Construct()
	self.Scope = Fusion.scoped(Fusion)
	self.Trove = Trove.new()

	self.LevelRequirement = self.Scope:Value()
	self.Trove:Add(AttributeBind.Bind(self.Instance, "RR_LevelRequirement", 0)):Observe(function(Value)
		self.LevelRequirement:set(Value)
	end)

	self.GamepassRequirement = self.Scope:Value()
	self.Trove:Add(AttributeBind.Bind(self.Instance, "RR_GamepassRequirement", nil)):Observe(function(Value)
		self.GamepassRequirement:set(Value)
	end)

	self.Zone = Zone.new(self.Instance)
	self.Zone:setAccuracy("Low")
end

function LockedZoneComponent:Stop()
	self.Trove:Destroy()
end

return LockedZoneComponent


local Rorooms = script.Parent.Parent.Parent.Parent
local Component = require(Rorooms.Parent.Component)

local VariantCyclerComponent = Component.new {
	Tag = `RR_{string.gsub(script.Name, "Component$", "")}`,

	Variants = {},
}

function VariantCyclerComponent:CycleVariant()
	local ActiveVariant = self.Instance:GetAttribute("RR_ActiveVariant") or 0
	if ActiveVariant == #self.Variants then
		ActiveVariant = 0
	end
	ActiveVariant += 1

	self:SetVariant(ActiveVariant)
end

function VariantCyclerComponent:SetVariant(VariantId: number?)
	if VariantId ~= nil then
		local Variant = self.Variants[VariantId]
		if Variant then
			self:_HideVariants()
			Variant.Parent = self.Instance
		end
	end

	self.Instance:SetAttribute("RR_ActiveVariant", VariantId)
end

function VariantCyclerComponent:_HideVariants()
	for _, Variant in ipairs(self.Variants) do
		Variant.Parent = nil
	end
end

function VariantCyclerComponent:_RegisterVariants()
	local Variants: { Instance } = {}

	for Count = 1, #self.Instance:GetChildren() do
		local Variant = self.Instance:FindFirstChild(Count)
		if Variant then
			table.insert(Variants, Variant)
		end
	end

	table.sort(Variants, function(VariantA, VariantB)
		return tonumber(VariantA.Name) < tonumber(VariantB.Name)
	end)

	self.Variants = Variants
	return Variants
end

function VariantCyclerComponent:_GetProximityPrompt(): ProximityPrompt
	local ProximityPrompt = self.Instance:FindFirstChild("RR_VariantCyclePrompt")
	if not ProximityPrompt then
		local Properties = {
			Name = "RR_VariantCyclePrompt",
			Parent = self.Instance,
			ActionText = "",
			RequiresLineOfSight = false,
			MaxActivationDistance = 7.5,
		}
		ProximityPrompt = Instance.new("ProximityPrompt")

		for Name, Value in pairs(Properties) do
			ProximityPrompt[Name] = Value
		end
	end

	return ProximityPrompt
end

function VariantCyclerComponent:Start()
	self:SetVariant(1)

	local Prompt = self:_GetProximityPrompt()
	Prompt.Triggered:Connect(function()
		self:CycleVariant()
	end)
end

function VariantCyclerComponent:Construct()
	if not self.Instance:IsA("BasePart") then
		warn(`{self.Tag} must be a BasePart object`, self.Instance)
		return
	end

	local Variants = self:_RegisterVariants()
	if #Variants == 0 then
		warn(`Child variants are incorrectly set up for {self.Tag}`, self.Instance)
	end
end

function VariantCyclerComponent:Stop()
	for _, Variant in ipairs(self.Variants) do
		Variant:Destroy()
	end
end

return VariantCyclerComponent


local CollectionService = game:GetService("CollectionService")
local Players = game:GetService("Players")

local CharacterDefaultsService = {
	Name = "CharacterDefaultsService",
}

function CharacterDefaultsService:KnitStart()
	Players.PlayerAdded:Connect(function(Player)
		Player.CharacterAdded:Connect(function(Char)
			CollectionService:AddTag(Char, "RR_PlayerCharacter")
		end)
	end)
end

return CharacterDefaultsService