Clients/Client2018/content/internal/AppShell/Modules/Shell/AvatarPane.lua

707 lines
23 KiB
Lua

-- Written by Kip Turner and Bo Zhang, Copyright Roblox 2017
local CoreGui = game:GetService("CoreGui")
local GuiService = game:GetService('GuiService')
local RunService = game:GetService('RunService')
local GuiRoot = CoreGui:FindFirstChild("RobloxGui")
local Modules = GuiRoot:FindFirstChild("Modules")
local ShellModules = Modules:FindFirstChild("Shell")
local PackageData = require(ShellModules:FindFirstChild('PackageData'))
local ScrollingGridModule = require(ShellModules:FindFirstChild('ScrollingGrid'))
local AvatarTile = require(ShellModules:FindFirstChild('AvatarTile'))
local Utility = require(ShellModules:FindFirstChild('Utility'))
local ScreenManager = require(ShellModules:FindFirstChild('ScreenManager'))
local GlobalSettings = require(ShellModules:FindFirstChild('GlobalSettings'))
local LoadingWidget = require(ShellModules:FindFirstChild('LoadingWidget'))
local ThumbnailLoader = require(ShellModules:FindFirstChild('ThumbnailLoader'))
local Analytics = require(ShellModules:FindFirstChild('Analytics'))
local Strings = require(ShellModules:FindFirstChild('LocalizedStrings'))
local SoundManager = require(ShellModules:FindFirstChild('SoundManager'))
local HintActionView = require(ShellModules:FindFirstChild('HintActionView'))
local XboxAppState = require(ShellModules:FindFirstChild('AppState'))
local GLOW_BASE_RPM = 2
local GLOW_TOP_RPM = -0.5
local GLOW_TRANSPARENCY = 0.2
local CATALOG_BELOW_POSITION = 320
local function CreateAvatarPane(parent)
local this = {}
local inFocus = false
local isShown = false
local AvatarObjects = {}
local OnGuiServiceChangedConn = nil
local lastParent = parent
local MainContainer = Utility.Create'Frame'
{
Name = 'AvatarPane';
Size = UDim2.new(1, 0, 1, 0);
BackgroundTransparency = 1;
Visible = false;
}
local MyAvatarContainer = Utility.Create'Frame'
{
Name = 'MyAvatarContainer';
Size = UDim2.new(0.38,0,1,0);
Position = UDim2.new(0,0,0,0);
BackgroundTransparency = 1;
ClipsDescendants = true;
Parent = MainContainer;
}
local MyNameLabel = Utility.Create'TextLabel'
{
Name = 'MyNameLabel';
Text = '';
Size = UDim2.new(1,0,0,25);
Position = UDim2.new(0,12,0,0);
TextXAlignment = 'Left';
TextColor3 = GlobalSettings.WhiteTextColor;
Font = GlobalSettings.RegularFont;
FontSize = GlobalSettings.SubHeaderSize;
BackgroundTransparency = 1;
Parent = MyAvatarContainer;
};
local ProfileImageContainer = Utility.Create'Frame'
{
Name = 'ProfileImageContainer';
Size = UDim2.new(0.68,0,0.9,-MyNameLabel.Size.Y.Offset);
Position = UDim2.new(0.16, 0, 0.05, MyNameLabel.Size.Y.Offset);
BackgroundTransparency = 1;
Parent = MyAvatarContainer;
}
local ProfileImage = Utility.Create'ImageLabel'
{
Name = 'ProfileImage';
Size = UDim2.new(0,780,0,780);
Position = UDim2.new(0.5, 0, 0.5, 0);
BackgroundTransparency = 1;
ZIndex = 3;
Parent = ProfileImageContainer;
};
local CrossfadeProfileImage = Utility.Create'ImageLabel'
{
Name = 'CrossfadeProfileImage';
Size = UDim2.new(1,0,1,0);
Position = UDim2.new(0, 0, 0, 0);
BackgroundTransparency = 1;
ImageTransparency = 1;
ZIndex = 3;
Parent = ProfileImage;
};
local CharacterGlowBase = Utility.Create'ImageLabel'
{
Name = 'CharacterGlowBase';
Size = UDim2.new(0,1015,0,1002);
BackgroundTransparency = 1;
Image = 'rbxasset://textures/ui/Shell/Images/CharacterGlow/CharacterGlowBase.png';
ImageTransparency = GLOW_TRANSPARENCY;
Parent = CrossfadeProfileImage;
AnchorPoint = Vector2.new(0.5, 0.5);
Position = UDim2.new(0.5, 0, 0.5, 0);
};
local CharacterGlowTop = Utility.Create'ImageLabel'
{
Name = 'CharacterGlowTop';
Size = UDim2.new(0,1026,0,1009);
BackgroundTransparency = 1;
Image = 'rbxasset://textures/ui/Shell/Images/CharacterGlow/CharacterGlowTop.png';
ImageTransparency = GLOW_TRANSPARENCY;
ZIndex = 2;
Parent = CrossfadeProfileImage;
AnchorPoint = Vector2.new(0.5, 0.5);
Position = UDim2.new(0.5, 0, 0.5, 0);
};
local function onSizeChanged()
ProfileImage.Size = Utility.CalculateFill(ProfileImage, ThumbnailLoader.AvatarSizes.Size352x352)
ProfileImage.AnchorPoint = Vector2.new(0.5, 0.5)
ProfileImage.Position = UDim2.new(0.5, 0, 0.5, 0)
end
-- Hint Action View
local hintActionView = HintActionView(nil, "AvatarPaneSelectAction")
hintActionView:SetImage('rbxasset://textures/ui/Shell/ButtonIcons/XButton.png')
hintActionView:SetText(Strings:LocalizedString('EquipWord'))
hintActionView:SetTransparency(1)
hintActionView:SetParent(lastParent.Parent) -- this assumes parent is HubContainer from AppHub.lua
local function UpdateEquipButton(IsOwned, IsWearing)
hintActionView:SetVisibleWithTween( (IsOwned and not IsWearing) and 0 or 1)
end
local SelectableAvatarsContainer = Utility.Create'Frame'
{
Name = 'SelectableAvatarsContainer';
Size = UDim2.new(0.6,0,1,0);
Position = UDim2.new(0.4,0,0,0);
BackgroundTransparency = 1;
Parent = MainContainer;
}
local NoCatalogStatusMessage = Utility.Create'TextLabel'
{
Name = 'NoCatalogStatusMessage';
Text = Strings:LocalizedString('DefaultErrorPhrase');
Size = UDim2.new(0.9,0,1,-125);
Position = UDim2.new(0.05, 0, 0, 0);
TextColor3 = GlobalSettings.GreyTextColor;
TextWrapped = true;
TextTransparency = GlobalSettings.FriendStatusTextTransparency;
Font = GlobalSettings.BoldFont;
FontSize = GlobalSettings.DescriptionSize;
BackgroundTransparency = 1;
Visible = false;
Parent = SelectableAvatarsContainer;
};
local MyCollectionTitle = Utility.Create'TextLabel'
{
Name = 'MyCollectionTitle';
Text = Strings:LocalizedString('AvatarOutfitsTitle');
Size = UDim2.new(1,0,0,40);
TextXAlignment = 'Left';
TextColor3 = GlobalSettings.WhiteTextColor;
Font = GlobalSettings.RegularFont;
FontSize = GlobalSettings.SubHeaderSize;
BackgroundTransparency = 1;
Visible = false;
Parent = SelectableAvatarsContainer;
};
local MyCollectionScroller = ScrollingGridModule()
MyCollectionScroller:SetSize(UDim2.new(1,0,1,-MyCollectionTitle.Size.Y.Offset - 40))
MyCollectionScroller:SetScrollDirection(MyCollectionScroller.Enum.ScrollDirection.Horizontal)
MyCollectionScroller:SetCellSize(Vector2.new(220, 220))
MyCollectionScroller:SetSpacing(Vector2.new(25,25))
MyCollectionScroller:SetPosition(UDim2.new(0,0,0,MyCollectionTitle.Size.Y.Offset))
MyCollectionScroller:SetRowColumnConstraint(1)
-- MyCollectionScroller:SetParent(SelectableAvatarsContainer)
local CatalogTitle = Utility.Create'TextLabel'
{
Name = 'CatalogTitle';
Text = Strings:LocalizedString('AvatarCatalogTitle');
Size = UDim2.new(1,0,0,40);
Position = UDim2.new(0,0,0,0);
TextXAlignment = 'Left';
TextColor3 = GlobalSettings.WhiteTextColor;
Font = GlobalSettings.RegularFont;
FontSize = GlobalSettings.SubHeaderSize;
BackgroundTransparency = 1;
Parent = SelectableAvatarsContainer;
};
local AvatarScroller = ScrollingGridModule()
AvatarScroller:SetSize(UDim2.new(1,0,1,-CatalogTitle.Size.Y.Offset - 40))
AvatarScroller:SetScrollDirection(AvatarScroller.Enum.ScrollDirection.Horizontal)
AvatarScroller:SetCellSize(Vector2.new(220, 220))
AvatarScroller:SetPosition(UDim2.new(0,0,0,40))
AvatarScroller:SetSpacing(Vector2.new(25,25))
AvatarScroller:SetRowColumnConstraint(2)
AvatarScroller:SetParent(SelectableAvatarsContainer)
local function SortMyCollectionScroller()
MyCollectionScroller:SortItems(
function(a, b)
local aObject = a and AvatarObjects[a] and AvatarObjects[a]:GetPackageInfo()
local bObject = b and AvatarObjects[b] and AvatarObjects[b]:GetPackageInfo()
local aIsEquipped = aObject and aObject:IsWearing()
local bIsEquipped = bObject and bObject:IsWearing()
local aName = aObject and aObject:GetName()
local bName = bObject and bObject:GetName()
if aIsEquipped then return true elseif bIsEquipped then return false end
if aName and bName then
return aName < bName
end
return aObject ~= nil
end)
end
--if all avatars owned, MyCollection should be 2 rows and catalog should be hidden
local function CheckAllAvatarsOwned()
if #AvatarScroller.GridItems == 0 then
MyCollectionScroller:SetRowColumnConstraint(2)
CatalogTitle.Visible = false
AvatarScroller.Visible = false
AvatarScroller:SetParent(nil)
else
MyCollectionScroller:SetRowColumnConstraint(1)
CatalogTitle.Visible = true
AvatarScroller.Visible = true
AvatarScroller:SetParent(SelectableAvatarsContainer)
end
end
local function OnAddToMyCollectionScroller()
CatalogTitle.Position = UDim2.new(0,0,0, CATALOG_BELOW_POSITION)
AvatarScroller:SetPosition(UDim2.new(0,0,0,CATALOG_BELOW_POSITION + 40))
AvatarScroller:SetRowColumnConstraint(1)
MyCollectionTitle.Visible = true
MyCollectionScroller:SetParent(SelectableAvatarsContainer)
CheckAllAvatarsOwned()
SortMyCollectionScroller()
end
local LoaderSpinner = nil
local GlobalFadeCount = 1
local function CrossfadeAvatarImage(frontImage, fadeImage, imageSource, duration)
if not imageSource then return end
duration = duration or 0.75
GlobalFadeCount = GlobalFadeCount + 1
local thisFadeCount = GlobalFadeCount
local fadeoutDuration = duration
spawn(function()
local dummyImage = nil
if LoaderSpinner then
LoaderSpinner:Cleanup()
end
--If imageSource if a function, then it's maybe a async call to get new image and we show the loaderspinner.
--Otherwise, if the imageSource is a valid new image, we just do the Crossfade (without the spinner)
if type(imageSource) == 'function' then
local newLoaderSpinner = LoadingWidget({Parent = frontImage, ZIndex = 3}, {
function() dummyImage = imageSource() end
})
LoaderSpinner = newLoaderSpinner
newLoaderSpinner:AwaitFinished()
newLoaderSpinner:Cleanup()
elseif type(imageSource) == 'table' and imageSource.Image then
dummyImage = imageSource
end
if thisFadeCount == GlobalFadeCount then
--Avoid updating with same image
if dummyImage and frontImage and dummyImage.Image ~= frontImage.Image then
local noPreviousImage = (frontImage.Image == "" and fadeImage.Image == "")
if noPreviousImage then
fadeoutDuration = 0
else
fadeImage.Image = frontImage.Image
end
Utility.PropertyTweener(fadeImage, 'ImageTransparency', noPreviousImage and 0 or frontImage.ImageTransparency, 1, fadeoutDuration, Utility.EaseInOutQuad, true)
Utility.PropertyTweener(CharacterGlowBase, 'ImageTransparency', CharacterGlowBase.ImageTransparency, 1, fadeoutDuration, Utility.EaseInOutQuad, true)
Utility.PropertyTweener(CharacterGlowTop, 'ImageTransparency', CharacterGlowTop.ImageTransparency, 1, fadeoutDuration, Utility.EaseInOutQuad, true)
frontImage.ImageTransparency = 1
frontImage.Image = dummyImage.Image
Utility.PropertyTweener(frontImage, 'ImageTransparency', frontImage.ImageTransparency, 0, duration, Utility.EaseInOutQuad, true)
Utility.PropertyTweener(CharacterGlowBase, 'ImageTransparency', CharacterGlowBase.ImageTransparency, GLOW_TRANSPARENCY, duration, Utility.EaseInOutQuad, true)
Utility.PropertyTweener(CharacterGlowTop, 'ImageTransparency', CharacterGlowTop.ImageTransparency, GLOW_TRANSPARENCY, duration, Utility.EaseInOutQuad, true)
end
end
end)
end
local function UpdateProfileImage(imageSource)
MyNameLabel.Text = XboxAppState.store:getState().XboxUser.gamertag
CrossfadeAvatarImage(ProfileImage, CrossfadeProfileImage, imageSource)
end
local function onOwnershipChanged(tile, nowOwns)
-- Move purchased packages into my MyCollection
if nowOwns then
local guiObject = tile and tile:GetGuiObject()
if guiObject and AvatarScroller:ContainsItem(guiObject) then
AvatarScroller:RemoveItem(guiObject)
MyCollectionScroller:AddItem(guiObject)
OnAddToMyCollectionScroller()
if inFocus then
GuiService.SelectedCoreObject = guiObject
end
end
end
end
local ownershipChangedCns = {}
local function listenToOwnershipChanged(tile)
local packageInfo = tile and tile:GetPackageInfo()
if packageInfo and not packageInfo:IsOwned() and (packageInfo.OwnershipChanged ~= nil) then
if not ownershipChangedCns[tile] then
ownershipChangedCns[tile] = packageInfo.OwnershipChanged:connect(function(nowOwns)
onOwnershipChanged(tile, nowOwns)
end)
end
end
end
local function removeListenToOwnershipChanged(tile)
if ownershipChangedCns[tile] then
ownershipChangedCns[tile]:disconnect()
ownershipChangedCns[tile] = nil
end
end
local function onEquipChanged()
local selectedObject = GuiService.SelectedCoreObject
if AvatarObjects[selectedObject] then
local packageInfo = AvatarObjects[selectedObject]:GetPackageInfo()
if packageInfo then
UpdateEquipButton(packageInfo:IsOwned(), packageInfo:IsWearing())
end
else
-- user can select avatar tab button
UpdateEquipButton(false, false)
end
SortMyCollectionScroller()
end
local lastSelectedObject = GuiService.SelectedCoreObject
local function OnSelectedCoreObjectChanged()
local selectedObject = GuiService.SelectedCoreObject
if AvatarObjects[lastSelectedObject] then
AvatarObjects[lastSelectedObject]:RemoveFocus()
end
if AvatarObjects[selectedObject] then
AvatarObjects[selectedObject]:Focus()
lastSelectedObject = selectedObject
end
onEquipChanged()
end
function this:GetDefaultSelectableObject()
if MyCollectionScroller:GetFirstVisibleItem() then
return MyCollectionScroller:GetFirstVisibleItem()
end
if AvatarScroller:GetFirstVisibleItem() then
return AvatarScroller:GetFirstVisibleItem()
end
--In case GetFirstVisibleItem breaks
if MyCollectionScroller.GridItems[1] then
return MyCollectionScroller.GridItems[1]
end
if AvatarScroller.GridItems[1] then
return AvatarScroller.GridItems[1]
end
end
local packagesData = nil
local packagesDataConns = {}
local AvatarWebDataInitializeLoader = nil
local function removeListenToPackagesDataUpdate()
for _, conn in pairs(packagesDataConns) do
conn:disconnect()
end
packagesDataConns = {}
end
local function listenToPackagesDataUpdate()
if packagesData and packagesDataConns then
table.insert(packagesDataConns, packagesData.OnDifferentWearing:connect(function(assetId) onEquipChanged() end))
table.insert(packagesDataConns, packagesData.OnDifferentOwned:connect(function(assetId, owned) onEquipChanged() end))
table.insert(packagesDataConns, packagesData.OnProfileImageUpdateEnd:connect(function(newProfileImage)
UpdateProfileImage(newProfileImage)
end))
table.insert(packagesDataConns, packagesData.OnProfileImageUpdateBegin:connect(function()
UpdateProfileImage(function()
return packagesData.OnProfileImageUpdateEnd.wait()
end)
end))
end
end
local function LoadAvatarWebData()
local function clearCatalogPackages()
AvatarScroller:RemoveAllItems()
MyCollectionScroller:RemoveAllItems()
for k,_ in pairs(AvatarObjects) do
AvatarObjects[k] = nil
end
AvatarObjects = {}
end
local function loadCatalogPackages(packages)
clearCatalogPackages()
if packages then
for _, packageInfo in pairs(packages) do
local avatarItemContainer = AvatarTile(packageInfo)
AvatarObjects[avatarItemContainer:GetGuiObject()] = avatarItemContainer
if packageInfo:IsOwned() then
MyCollectionScroller:AddItem(avatarItemContainer:GetGuiObject())
OnAddToMyCollectionScroller()
else
AvatarScroller:AddItem(avatarItemContainer:GetGuiObject())
listenToOwnershipChanged(avatarItemContainer)
end
if isShown then
avatarItemContainer:Show()
end
end
end
end
--Wait until initialize is done
if AvatarWebDataInitializeLoader then return end
if PackageData:HasCachedData() then --Sync process to get and update packagesData, no spinner
local prevVersion = packagesData and packagesData.Version or nil
packagesData = PackageData:GetCachedData()
--If init or packagesData got updated
if not prevVersion or prevVersion ~= packagesData.Version then
SelectableAvatarsContainer.Visible = false
UpdateProfileImage(packagesData.ProfileImage.Data)
loadCatalogPackages(packagesData.Packages.Data)
SelectableAvatarsContainer.Visible = true
removeListenToPackagesDataUpdate()
listenToPackagesDataUpdate()
end
else --Async process to get and update packagesData, show spinner
SelectableAvatarsContainer.Visible = false
local containerSize = SelectableAvatarsContainer.Size
AvatarWebDataInitializeLoader = LoadingWidget(
{Parent = MainContainer, Position = SelectableAvatarsContainer.Position + UDim2.new(containerSize.X.Scale / 2, containerSize.X.Offset / 2, containerSize.Y.Scale / 2, containerSize.Y.Offset / 2)},
{function()
packagesData = PackageData:GetCachedData()
if packagesData and packagesData.Packages then
loadCatalogPackages(packagesData.Packages.Data)
end
end}
)
spawn(function()
NoCatalogStatusMessage.Visible = false
UpdateProfileImage(function()
if AvatarWebDataInitializeLoader then
AvatarWebDataInitializeLoader:AwaitFinished()
end
if packagesData and packagesData.ProfileImage then
return packagesData.ProfileImage.Data
end
end)
AvatarWebDataInitializeLoader:AwaitFinished()
AvatarWebDataInitializeLoader:Cleanup()
AvatarWebDataInitializeLoader = nil
SelectableAvatarsContainer.Visible = true
removeListenToPackagesDataUpdate()
if not packagesData then
NoCatalogStatusMessage.Visible = true
end
--Hook connections if the pane is still visible after loading
if isShown then
listenToPackagesDataUpdate()
end
if inFocus and isShown and GuiService.SelectedCoreObject == nil then
GuiService.SelectedCoreObject = this:GetDefaultSelectableObject()
end
if this.TransitionTweens == nil or #this.TransitionTweens == 0 then
this.TransitionTweens = ScreenManager:FadeInSitu(SelectableAvatarsContainer)
end
end)
end
end
LoadAvatarWebData()
--[[ Public API ]]--
function this:GetName()
return Strings:LocalizedString('AvatarWord')
end
function this:GetAnalyticsInfo()
return {[Analytics.WidgetNames('WidgetId')] = Analytics.WidgetNames('AvatarPaneId')}
end
function this:IsFocused()
return inFocus
end
local debounceSelect = false
function this:OnSelectAction()
if debounceSelect then return end
debounceSelect = true
local selectedObject = GuiService.SelectedCoreObject
if selectedObject and AvatarObjects[selectedObject] then
if AvatarObjects[selectedObject]:Select() then
SoundManager:Play('ButtonPress')
end
end
debounceSelect = false
end
function this:OpenEquippedPackage()
if isShown and inFocus then
for _, avatarItemContainer in pairs(AvatarObjects) do
local packageInfo = avatarItemContainer:GetPackageInfo()
if packageInfo then
if packageInfo:IsWearing() then
avatarItemContainer:OnClick()
end
end
end
end
end
--[[ End Public API ]]--
local profileImageChangeCn = nil
function this:Show()
isShown = true
Utility.DisconnectEvent(profileImageChangeCn)
profileImageChangeCn = ProfileImageContainer:GetPropertyChangedSignal('AbsoluteSize'):connect(function()
onSizeChanged()
end)
onSizeChanged()
local lastUpdate = tick()
RunService:BindToRenderStep("UpdateAvatarGlow", Enum.RenderPriority.Camera.Value,
function()
local now = tick()
local delta = now - lastUpdate
CharacterGlowBase.Rotation = CharacterGlowBase.Rotation + delta * GLOW_BASE_RPM * 6 -- 6 = 360 / 60
CharacterGlowTop.Rotation = CharacterGlowTop.Rotation + delta * GLOW_TOP_RPM * 6
lastUpdate = now
end)
if packagesData then
listenToPackagesDataUpdate()
UpdateProfileImage(packagesData.ProfileImage.Data)
end
LoadAvatarWebData()
for _, avatarItemContainer in pairs(AvatarObjects) do
avatarItemContainer:Show()
listenToOwnershipChanged(avatarItemContainer)
local packageInfo = avatarItemContainer and avatarItemContainer:GetPackageInfo()
if packageInfo then
onOwnershipChanged(avatarItemContainer, packageInfo:IsOwned())
end
end
local seenXButtonPressed = false
local seenXSelectedObject = nil
local function onSelectAvatar(actionName, inputState, inputObject)
if inputState == Enum.UserInputState.Begin then
seenXButtonPressed = true
seenXSelectedObject = GuiService.SelectedCoreObject
elseif inputState == Enum.UserInputState.End and seenXButtonPressed then
if seenXSelectedObject and seenXSelectedObject == GuiService.SelectedCoreObject then
self:OnSelectAction()
end
seenXButtonPressed = false
seenXSelectedObject = nil
end
end
hintActionView:BindAction(onSelectAvatar, Enum.KeyCode.ButtonX)
self.TransitionTweens = ScreenManager:DefaultFadeIn(MainContainer)
SortMyCollectionScroller()
MainContainer.Parent = lastParent
MainContainer.Visible = true
ScreenManager:PlayDefaultOpenSound()
end
function this:Hide()
isShown = false
MainContainer.Visible = false
removeListenToPackagesDataUpdate()
profileImageChangeCn = Utility.DisconnectEvent(profileImageChangeCn)
RunService:UnbindFromRenderStep("UpdateAvatarGlow")
hintActionView:UnbindAction()
hintActionView:SetTransparency(1)
for _, avatarItemContainer in pairs(AvatarObjects) do
avatarItemContainer:Hide()
removeListenToOwnershipChanged(avatarItemContainer)
end
ScreenManager:DefaultCancelFade(self.TransitionTweens)
self.TransitionTweens = nil
-- Clean out saved selected object so when we tab back
-- we will start with the default selection
lastSelectedObject = nil
self.SavedSelectObject = nil
end
function this:Focus()
inFocus = true
Utility.DisconnectEvent(OnGuiServiceChangedConn)
OnGuiServiceChangedConn = GuiService:GetPropertyChangedSignal('SelectedCoreObject'):connect(function()
OnSelectedCoreObjectChanged()
end)
if self.SavedSelectObject and self.SavedSelectObject:IsDescendantOf(MainContainer) then
GuiService.SelectedCoreObject = self.SavedSelectObject
else
local defaultSelection = self:GetDefaultSelectableObject()
if defaultSelection then
GuiService.SelectedCoreObject = defaultSelection
end
end
end
function this:RemoveFocus()
inFocus = false
--Remove Focus on AvatarObjects
if AvatarObjects and AvatarObjects[lastSelectedObject] then
AvatarObjects[lastSelectedObject]:RemoveFocus()
end
OnGuiServiceChangedConn = Utility.DisconnectEvent(OnGuiServiceChangedConn)
local selectedObject = GuiService.SelectedCoreObject
if isShown then
if selectedObject and selectedObject:IsDescendantOf(MainContainer) then
self.SavedSelectObject = GuiService.SelectedCoreObject
GuiService.SelectedCoreObject = nil
else
self.SavedSelectObject = lastSelectedObject
end
end
OnSelectedCoreObjectChanged()
end
function this:SetPosition(newPosition)
MainContainer.Position = newPosition
end
function this:SetParent(newParent)
lastParent = newParent
MainContainer.Parent = newParent
end
return this
end
return CreateAvatarPane