Can you search for items with the same name or data for a certain parameter in the Explorer Window?

Essentially, I’m trying to find a method of finding assets in a place that have the same name using the search bar (or other methods, if necessary). The specific example I’m dealing with right now is MaterialVariants; I’m trying to parse through ~900 different MaterialVariants to check if any have redundant or conflicting names or textures, but I can’t find any search parameters in the syntax guide that would display this. Aside from manually going through and checking for conflicting names (or, worse, Textures), I haven’t seen any solution here.

Is there any search variable I can use to only display items with matching/conflicting values for a certain parameter? Failing this, is there a way to do this using a piece of code running in Output (such as grouping any such materials under a Folder or Model)?

1 Like

In the search bar of the Explorer window, you can use a variety of filters to search for the objects that match certain conditions. You can combine these together to make the search more specific.

However, I don’t think the search bar filters will be an all-encompassing solution for your question so I’ll also include some code that can be run in the command bar that should be able to find specific value matches without having to specify what value it needs to match.


Search Bar Filters

For example, if you wanted to only look for MaterialVariants that are named “CustomRoadTexture”, you could use the following search:

c:MaterialVariant and Name == "CustomRoadTexture"

c is a bespoke filter that is checking the Class.

Name is a property filter that is checking the Name property.


Or, if you wanted to look for all MaterialVariants with a BaseMaterial of Sand that has its ColorMap set to a specific texture ID, you could use the following search (replacing “ID” with the number / asset ID you want to search for):

c:MaterialVariant and BaseMaterial == "Sand" and ColorMap == "rbxassetid://ID"

This sort of idea applies for any combination of properties that you want to search for. It can have as few or as many properties as you want to search for (so you could just look for MaterialVariants, or all MaterialVariants with a specific BaseMaterial, or all MaterialVariants that have specific Color / Metalness / Roughness maps, etc.)


(Alternative solution) Command bar code

Unfortunately, I don’t know if there’s a way to specifically filter for objects that share the exact same value for one of its properties without also specifying what value to look for.


As a result, I’ve written the following code which will look through the MaterialService and group items that are found to have a match for specific properties.

By default, it’ll clone the matching items and place them into designated folders so it’ll be able to show if an object has multiple different matches, and to make sure it doesn’t ruin any organizational system that was already there. This way, you can see what matches it finds and then use a property filter on those specific matching values in the Explorer search bar to find the original items that matched.

  • This example doesn’t find matches for the “BaseMaterial”, “MaterialPattern”, and “StudsPerTile” properties by default, since those are less likely to indicate that two objects are “duplicates” (especially since MaterialPattern only has 2 different values at the moment). However, you could always choose to search for any of these properties by updating the relevant variables in the code from false to true.

(Note that this might not be the most efficient code; it’s just an example of a possible way to go about this)



Example Code

(I tested this in the Racing Starter Place and it worked really well since there are several MaterialVariants included there by default)


Edit: I forgot to link to the page where you can access the starter place; it has been added :slight_smile:

Edit 2: For anyone interested, and in case that Roblox Creator Hub page changes, here’s the announcement thread for that Racing Template Starter Place.

--[[ I'd recommend pasting this into a script, first
so that you can edit any of the "Settings" before
pasting it into the command bar and running the code
--]]

local MaterialService = game:GetService("MaterialService")

---

local Settings = {
	
	LookThroughEntireGame = false, -- If false, only looks through MaterialService
	
	LookForPropertyMatches = {
		-- To choose a property where it should look for matches, update the variable to "true"
		BaseMaterial = false,
		
		ColorMap = true,
		MetalnessMap = true,
		NormalMap = true,
		RoughnessMap = true,
		
		MaterialPattern = false,
		StudsPerTile = false,
		
		Name = true,
		Parent = false
	},
	
	ExcludeEmptyProperties = true, -- If true, properties without an assigned value will not be matched
	ContainerForDuplicateMatches = game:GetService("ServerStorage"),
	
	ClearAllClonedItemsFromPreviousSearchForMatchingItemsCheck = true
--[[ This helps make sure that the folder of matching items
does not become cluttered with matching items found from a previous test.

If you plan on running this code multiple times in a row,
setting this to true and then running the code in the command bar
will delete the "MaterialVariants: Duplicate Matching Folder"
folder that was created the previous time the code ran, and then it
will create a brand new one, only containing items from the newest test.


If you plan on removing the folder manually,
or if you want it to keep the cloned items from a previous test, keeping this
set to false will not delete anything from previous tests.
]]--

}

local MaterialVariants = {
	AllObjects = {},
}

local function initialLoop()
	warn("Running initial loop")

	local container

	if Settings.LookThroughEntireGame == true then
		container = game
	else
		container = MaterialService
	end

	for _, item in container:GetDescendants() do
		if item:IsA("MaterialVariant") then
			item:SetAttribute("TemporaryIndexAttribute", #MaterialVariants.AllObjects + 1)
			table.insert(MaterialVariants.AllObjects, item)
		end
	end
	
	print("Total MaterialVariants found in "..container.Name..": "..tostring(#MaterialVariants.AllObjects))
end
initialLoop()


local function searchForMatchingItems()
	warn("Now searching for all matching items")
	
	local totalMatches = 0
	local propertiesToSearchFor = {}
	
	local container = Settings.ContainerForDuplicateMatches
	local duplicateMatchingFolder = container:FindFirstChild("MaterialVariants: Duplicate Matching Folder")
	
	if duplicateMatchingFolder then
		if Settings.ClearAllClonedItemsFromPreviousSearchForMatchingItemsCheck == true then
			duplicateMatchingFolder:Destroy()
			duplicateMatchingFolder = nil
		end
	end
	
	local function createPropertyMatchFolders()
		for propertyToMatch, toLookThrough in Settings.LookForPropertyMatches do
			if toLookThrough == false then continue end
			
			table.insert(propertiesToSearchFor, propertyToMatch)
			
			if not duplicateMatchingFolder:FindFirstChild(propertyToMatch) then
				local propertyMatchFolder = Instance.new("Folder")
				propertyMatchFolder.Name = propertyToMatch
				propertyMatchFolder.Parent = duplicateMatchingFolder
			end
			
		end
	end
	
	
	if not duplicateMatchingFolder then
		print("Duplicate Matching Folder does not exist. Creating a new one")
		local newFolder = Instance.new("Folder")
		newFolder.Name = "MaterialVariants: Duplicate Matching Folder"
		newFolder.Parent = container
		duplicateMatchingFolder = newFolder
	end
	
	createPropertyMatchFolders()
	
	
	for index, originalItem in MaterialVariants.AllObjects do
		for otherIndex, otherItem in MaterialVariants.AllObjects do
			if otherIndex == index then continue end
			
			for _, propertyName in propertiesToSearchFor do
				
				if Settings.ExcludeEmptyProperties == true then
					
					if
						originalItem[propertyName] == nil
						or originalItem[propertyName] == ""
						or originalItem[propertyName] == " "
					then
						continue
					end
					
				end
				
				
				if originalItem[propertyName] == otherItem[propertyName] then
					
					local propertyMatchFolder = duplicateMatchingFolder:FindFirstChild(propertyName)
					local specificValueMatchFolder = propertyMatchFolder:FindFirstChild(originalItem[propertyName])
					
					if not specificValueMatchFolder then
						local verySpecificFolder = Instance.new("Folder")
						verySpecificFolder.Name = originalItem[propertyName]
						verySpecificFolder.Parent = propertyMatchFolder
						specificValueMatchFolder = verySpecificFolder
					end
					
					local itemsAddedToFolder = 0
					
					local function checkIfItemAlreadyExistsInFolder(item)
						local addItemToFolder = true
						local currentItemAttribute = item:GetAttribute("TemporaryIndexAttribute")
						
						for _, existingItem in specificValueMatchFolder:GetChildren() do
							local existingItemAttribute = existingItem:GetAttribute("TemporaryIndexAttribute")
							
							if currentItemAttribute == existingItemAttribute then
								-- In this case, the exact item already exists in the folder
								addItemToFolder = false
								break
							end
						end
						
						if addItemToFolder == true then
							itemsAddedToFolder += 1
							local clonedItem = item:Clone()
							clonedItem.Parent = specificValueMatchFolder
						end
					end
					
					checkIfItemAlreadyExistsInFolder(originalItem)
					checkIfItemAlreadyExistsInFolder(otherItem)
					
					if itemsAddedToFolder > 0 then
						totalMatches += 1
					end
					
				end
			end
			
		end
	end
	
	for _, item in MaterialVariants.AllObjects do
		if item:GetAttribute("TemporaryIndexAttribute") then
			item:SetAttribute("TemporaryIndexAttribute", nil)
		end
	end
	
	warn("Search for all matching items has concluded")
	print("Total matches found: "..tostring(totalMatches))
end
searchForMatchingItems()


If you want a somewhat brief rundown of how it organizes the matching items, the code will create a main folder called MaterialVariants: Duplicate Matching Folder so you know where to find everything. By default, it is placed into the ServerStorage, but you can choose where it goes in the “Settings” table.

Inside of those folders will be the names of the properties that you want to check for matches of. So if you want to find all MaterialVariants that could have overlaps with one or more of the following:

  • Name
  • ColorMap
  • MetalnessMap
  • NormalMap
  • RoughnessMap

Then it will create a separate folder for each of those property name inside of the MaterialVariants: Duplicate Matching Folder. Then, when the code finds two items with a matching value for a given property, it will create a new folder inside of the property name folder that has the name of the matching value. It’ll clone those items and then place it into that final folder. This way, once everything is done, you can go through and see how many duplicate matches there were of a specific value for each property.


As an example, if you had two material variants with the following properties:

#1

  • Name: “EpicMaterialVariant”
  • ColorMap: “rbxassetid://1”
  • MetalnessMap: (blank)
  • NormalMap: “rbxassetid://1337”
  • RoughnessMap: “rbxassetid://2000”

#2

  • Name: “EpicMaterialVariant”
  • ColorMap: “rbxassetid://25”
  • MetalnessMap: “rbxassetid://12345”
  • NormalMap: “rbxassetid://1337”
  • RoughnessMap: (blank)

These two had exact matches for:

  • Name
  • NormalMap

So, inside of ServerStorageMaterialVariants: Duplicate Matching Folder, 2 of the property name folders will be updated.

  1. Inside of the folder called “Name”, a new folder will be created that is called “EpicMaterialVariant”, and the two matching items will be cloned and then added there.

  2. Inside of the folder called “NormalMap”, a new folder will be created that is called “rbxassetid://1337”, and the two matching items will be cloned and then added there.

And for the sake of the example, let’s say that there happened to be another MaterialVariant that had the same value for the NormalMap as the previous two items did. In that case, it would clone this item into the folder but it would not create an additional clone of the items that were already added into the folder.

  • This helps make sure that the folder will contain the exact quantity of unique items that all had the exact same value for a specific property. (Note: The code is structured in a way where even if you have two identical items with the exact same values for each property, it will be able to distinguish those as unique items, so both of those items would be added to the folder(s) rather than just one.)

There’s a ton of different things that I’ve explained here all at once, so if you need clarification for anything in particular, let me know and I’ll try to make it easier to understand :smile:

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.