· 6 years ago · Jul 15, 2019, 06:16 AM
1local GUI_BUTTONS_USED=20; --Number of buttons to view.
2--local UPDATE_DELTA=1; --How many seconds should the buttons update.
3do --Remove old "ParentTreeGUI's"
4 local ScreenGui_Old=script.Parent:FindFirstChild("ParentTreeGUI");
5 if ScreenGui_Old then
6 ScreenGui_Old:Destroy();
7 end
8end
9local Sprites={}
10Sprites.AddNew=function(self,class_name,name,parent,properties)
11 if not self[name] then
12 self[name]=Instance.new(class_name,parent);
13 self[name].Name=name;
14 local properties=properties or function(self_sprite) end;
15 properties(self[name]); --Pass functions to edit ROBLOX Instances.
16 end
17end
18--Generic function AddNew to add a roblox instance to the Game,
19--and change properties of the instance in an anonymous function if needed.
20Sprites:AddNew("ScreenGui","ParentTreeGUI",script.Parent);
21Sprites:AddNew("ImageButton","GUIContainer",Sprites["ParentTreeGUI"],function(self_sprite)
22 self_sprite.Size=UDim2.new(1,0,0.7,0);
23 self_sprite.BackgroundColor3=Color3.new(85/255,170/255,255/255);
24 self_sprite.ClipsDescendants=true; --Render GUI things only inside this frame.
25 self_sprite.AutoButtonColor=false;
26end);
27Sprites:AddNew("ScrollingFrame","InstanceButtonsContainer",Sprites["GUIContainer"],function(self_sprite)
28 self_sprite.Size=UDim2.new(0.4,0,1,0);
29 self_sprite.BackgroundTransparency=1;
30 self_sprite.BorderSizePixel=0;
31end);
32--[[Sprites:AddNew("Frame","SliderContainer",Sprites["GUIContainer"],function(self_sprite)
33 self_sprite.Position=UDim2.new(0.4,0,0,0);
34 self_sprite.Size=UDim2.new(0.1,0,1,0);
35 self_sprite.BackgroundColor3=Color3.new(85/255,85/255,255/255);
36 --self_sprite.Style=Enum.FrameStyle.RobloxSquare;
37 self_sprite.ZIndex=2;
38end);
39Sprites:AddNew("ImageButton","Slider",Sprites["SliderContainer"],function(self_sprite)
40 self_sprite.Size=UDim2.new(1,0,1,0);
41 self_sprite.Image="http://www.roblox.com/asset/?id=38011242";
42 self_sprite.Style=Enum.ButtonStyle.RobloxRoundButton;
43 self_sprite.ZIndex=2;
44end);]]
45Sprites:AddNew("TextButton","TextButtonTemplate",Sprites["InstanceButtonsContainer"],function(self_sprite)
46 self_sprite.Size=UDim2.new(1,0,1/GUI_BUTTONS_USED,0);
47 self_sprite.Style=Enum.ButtonStyle.RobloxRoundDefaultButton;
48 self_sprite.BackgroundColor3=Color3.new(63/255,63/255,63/255);
49 self_sprite.TextColor3=Color3.new(255/255,255/255,255/255);
50 self_sprite.Visible=false; --Hide template for :Clone()ing.
51 self_sprite.TextScaled=true;
52end);
53Sprites:AddNew("TextLabel","ParentsBox",Sprites["GUIContainer"],function(self_sprite)
54 self_sprite.Position=UDim2.new(0.5,0,0,0);
55 self_sprite.Size=UDim2.new(0.5,0,0.5,0);
56 self_sprite.TextColor3=Color3.new(255/255,255/255,255/255);
57 self_sprite.TextScaled=true;
58end);
59Sprites:AddNew("TextLabel","Purpose",Sprites["GUIContainer"],function(self_sprite)
60 self_sprite.Position=UDim2.new(0.5,0,0.5,0);
61 self_sprite.Size=UDim2.new(0.5,0,0.5,0);
62 self_sprite.Font=Enum.Font.ArialBold;
63 self_sprite.Text="The whole purpose of this script-GUI-thing was to show an Instance's Children/Classes (The leftmost buttons), and prints what an Instance's parent/\"grandparents\" are (Example: In Game.Workspace.BasePlate, BasePlate's Parent is Workspace, and Workspace's Parent is Game). The first leftmost button goes to an Instance's parent. Just click buttons and the scroll bar to see how it works. Note: Some Children called \"Instance\" in the Parent Game might use Game:GetService(StringClassNameOfInstance), or it might not be accessible at all or something.";
64 self_sprite.TextScaled=true;
65end);
66local ButtonSprites={};
67if not pcall(function() ButtonSprites.PointTo=Workspace.BasePlate; end) then
68 ButtonSprites.PointTo=Workspace;
69end --If Workspace.BasePlate is deleted or non-existant for some reason.
70ButtonSprites.ParentsTable={};
71ButtonSprites.ParentsString="";
72ButtonSprites.DeleteAllButtons=function(self)
73 for i,_ in ipairs(self) do
74 self[i]:Destroy(); --Destroy all Button Instances from table inserts in ButtonSprites:CreateButton().
75 self[i]=nil;
76 end
77end
78local ParentsBox=Sprites["ParentsBox"];
79ButtonSprites.ChangeParentString=function(self)
80 self.ParentsString="";
81 --[[for _,Instance in ipairs(self.ParentsTable) do
82 self.ParentsString=self.ParentsString..tostring(Instance).." ";
83 end]]
84 for i=#self.ParentsTable,1,-1 do
85
86 if string.match(tostring(self.ParentsTable[i]),"%s") then
87 self.ParentsString=self.ParentsString.."[\""..tostring(self.ParentsTable[i]).."\"]";
88 else --If Instance Name have spaces, do ["This"] instead of .This
89 self.ParentsString=self.ParentsString.."."..tostring(self.ParentsTable[i]);
90 end
91 if self.ParentsTable[i]==Game then
92 self.ParentsString="Game";
93 --tostring(Game) doesn't say "Game" for some reason.
94 end
95 end --Print Parents backwards just like in scripts (Ex: Game.Workspace.BasePlate.)
96
97
98 ParentsBox.Text="Pointing to Instance: "..self.ParentsString
99 .." ("..self.PointTo.ClassName..")";
100 --Show Instance's parent tree and class name.
101end
102ButtonSprites.UpdateParentsTree=function(self,Instance)
103 --Finds parents of an instance such as "Part" (If parent is Workspace,
104 --it would make a table such as {Part,Workspace,Game}).
105 self.PointTo=Instance; --Update Pointer.
106 local ParentsTable={};
107 table.insert(ParentsTable,#ParentsTable+1,Instance);
108 while Instance.Parent do --When Instance!=Game (Game.Parent returns nil)...
109 Instance=Instance.Parent;
110 table.insert(ParentsTable,#ParentsTable+1,Instance);
111 end
112 self.ParentsTable=ParentsTable;
113 self:ChangeParentString();
114end
115local TextButtonTemplate=Sprites["TextButtonTemplate"];
116local InstanceButtonsContainer=Sprites["InstanceButtonsContainer"];
117local DoButtonsUpdateRoutine=function() end;
118ButtonSprites.CreateButton=function(self,Instance)
119 local Button=TextButtonTemplate:Clone();
120 Button.Parent=InstanceButtonsContainer;
121 if not pcall(function()
122 Button.Name=tostring(Instance);
123 end) then
124 Button.Name="(Inaccessible Instance)";
125 end
126 if not pcall(function()
127 Button.Text=tostring(Instance).." ("..(Instance.ClassName)..")";
128 end) then
129 Button.Text="(Inaccessible Instance)";
130 end --If an object doesn't have the member ClassName nor cannot be accessible at all...
131 Button.Visible=true;
132 table.insert(self,#self+1,Button);
133 --Add to ButtonSprites to be deleted later.
134 if pcall(function() assert(Instance.Parent); end) then
135 Button.MouseButton1Down:connect(function()
136 table.insert(self.ParentsTable,1,Instance);
137 --Insert Instance as the "New Parent".
138 self.PointTo=Instance; --Change pointer to this instance.
139 self:ChangeParentString();
140 DoButtonsUpdateRoutine();
141 end);
142 else
143 --print(tostring(Instance).." does not have the member Instance.Parent.");
144 Button.Text=Button.Text.." (Type Inaccessible)";
145 end --Add event listener if the member Parent is accessible.
146 return Button; --Return Button for :CreateNewButtons();
147end
148local GoBackButton=TextButtonTemplate:Clone();
149GoBackButton.Parent=InstanceButtonsContainer;
150GoBackButton.Name="GoBackButton";
151GoBackButton.Visible=true;
152--Create a button that can go to an instance's parent
153--Example: If clicking the button when the GUI is pointing at Workspace,
154--the GUI will now point to Game.
155DoButtonsUpdateRoutine=function() end
156ButtonSprites.AddEventListenersToPointer=function(self)
157 --Whenever the Instance Pointer (ButtonSprites.PointTo) has added/deleted children,
158 --or it's "grandparents" are :Destroy()ed, tell the events to update the buttons.
159 local InstancePointer=self.PointTo;
160 InstancePointer.ChildAdded:connect(DoButtonsUpdateRoutine);
161 InstancePointer.ChildRemoved:connect(DoButtonsUpdateRoutine);
162 InstancePointer.AncestryChanged:connect(function(GrandParent,NewParent)
163 if NewParent then
164 --If Parent of Ancestor/GrandParent still exists, track the Instance to
165 --the new location.
166 self:UpdateParentsTree(self.PointTo);
167 else
168 end
169 DoButtonsUpdateRoutine()
170 end);
171end
172ButtonSprites.CreateNewButtons=function(self)
173 local InstancePointer=self.PointTo;
174 while not InstancePointer.Parent and InstancePointer~=Game do
175 --If an Instance is :Destroy()ed, traverse through the Instance's non-deleted parents,
176 --but exclude self.PointTo if the Instance is "Game" (It has no parents :( ).
177 table.remove(self.ParentsTable,1); --Remove :Destroy()ed Instance from ParentsTable.
178 local NewParent=self.ParentsTable[1]; --Get Parent from :Destroy()ed Instance.
179 InstancePointer=NewParent;
180 self.PointTo=NewParent;
181 self:ChangeParentString();
182 end
183 ButtonSprites:AddEventListenersToPointer()
184 for i,Instance in ipairs(InstancePointer:GetChildren()) do
185 self:CreateButton(Instance).Position
186 =UDim2.new(0,0,i/GUI_BUTTONS_USED,0);
187 --For each created button, position down for the Instance's i is in.
188
189 --table.insert(self,#self+1,Instance);
190 end
191end
192
193DoButtonsUpdateRoutine=function() end
194GoBackButton.MouseButton1Down:connect(function()
195 if ButtonSprites.PointTo~=Game then
196 --Go back to Instance's parent if Instance~=Game.
197 table.remove(ButtonSprites.ParentsTable,1);
198 local NewParent=ButtonSprites.ParentsTable[1];
199 ButtonSprites.PointTo=NewParent;
200 ButtonSprites:ChangeParentString();
201 DoButtonsUpdateRoutine();
202 end
203end);
204local InstanceButtonsContainer=Sprites["InstanceButtonsContainer"];
205ButtonSprites:UpdateParentsTree(ButtonSprites.PointTo); --Initialize Parent Table.
206DoButtonsUpdateRoutine=function()
207 ButtonSprites:DeleteAllButtons();
208 ButtonSprites:CreateNewButtons();
209 GoBackButton.Text=tostring(ButtonSprites.PointTo)
210 .." ("..ButtonSprites.PointTo.ClassName..")'s Parent";
211 if ButtonSprites.PointTo==Game then
212 GoBackButton.Text="Game (DataModel) has no Parents.";
213 end
214end
215DoButtonsUpdateRoutine(); --Initialize buttons.
216Sprite=nil;