Last active
September 29, 2020 01:39
-
-
Save Anaminus/f12a1dae02f6c11a929a3817b7fdf21f to your computer and use it in GitHub Desktop.
Concept for Roblox game tree query filters.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local Filter = require(game.ServerStorage.Filter) | |
| local Transparent = Filter.Property("Transparency", Filter.ComparisonOp.Less, 0.95) | |
| local Uncollidable = Filter.Property("CanCollide", Filter.ComparisonOp.Equal, true) | |
| local BlockRays = Filter.Tag("BlockRays") | |
| local AllowRays = Filter.Tag("AllowRays") | |
| local Model = Filter.DescendantOf(workspace.Model) | |
| local propertyFilter = Filter.Group(Transparent, Filter.LogicalOp.And, Uncollidable) | |
| local tagFilter = Filter.Group(BlockRays, Filter.LogicalOp.And, Filter.LogicalOp.Not, AllowRays) | |
| local raycastFilter = Filter.Group(propertyFilter, Filter.LogicalOp.Or, tagFilter, Filter.LogicalOp.And, Filter.LogicalOp.Not, Model) | |
| print(Filter.Group(Filter.LogicalOp.Not, raycastFilter)) | |
| -- (not ((v.Transparency < (0.95) and v.CanCollide == (true)) or | |
| -- (CollectionService:HasTag(v, "BlockRays") and | |
| -- not CollectionService:HasTag(v, "AllowRays")) and | |
| -- not v:IsDescendantOf(Workspace.Model))) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| local Filter = require(game.ServerStorage.Filter) | |
| -- Raycasting | |
| local Transparent = Filter.Property("Transparency", Enum.ComparisonOp.LessThan, 0.95) | |
| local Uncollidable = Filter.Property("CanCollide", Enum.ComparisonOp.Equal, true) | |
| local BlockRays = Filter.Tag("BlockRays") | |
| local AllowRays = Filter.Tag("AllowRays") | |
| local Model = Filter.DescendantOf(Workspace.Model) | |
| local propertyFilter = Filter.Group(Transparent, Enum.LogicalOp.And, Uncollidable) | |
| local tagFilter = Filter.Group(BlockRays, Enum.LogicalOp.And, Enum.LogicalOp.Not, AllowRays) | |
| local raycastFilter = Filter.Group(propertyFilter, Enum.LogicalOp.Or, tagFilter, Enum.LogicalOp.And, Enum.LogicalOp.Not, Model) | |
| -- return (v.Transparency < 0.95 and v.CanCollide == true) or | |
| -- (CollectionService:HasTag(v, "BlockRays") and not CollectionService:HasTag(v, "AllowRays") and | |
| -- not v:IsDescendantOf(workspace.Model) | |
| local hit, pos, norm, mat = Workspace:FindPartOnRayWithFilter(raycastFilter) | |
| local invertedFilter = Filter.Group(Enum.LogicalOp.Not, raycastFilter) -- whitelist -> blacklist; powerful! | |
| local parts = Workspace:FindPartsInRegion3WithFilter(invertedFilter) | |
| -- Evaluate anything with filter | |
| raycastFilter:Eval(workspace.Model.Part) --> false | |
| invertedFilter:Eval(workspace.Model.Part) --> true | |
| -- Selection | |
| local humanoid = player.Character:FindFirstChildWithFilter(Filter.Class("Humanoid")) | |
| -- Recursive; could also be named FindFirstDescendantWithFilter | |
| local part = Workspace:FindFirstChildWithFilter(Filter.ClassOf("BasePart"), true) | |
| local moduleFolder = game:GetService("ReplicatedStorage"):FindFirstChildWithFilter(Filter.Group( | |
| Filter.Class("Folder"), | |
| Enum.LogicalOp.And, | |
| Filter.Property("Name", Enum.ComparisonOp.Equal, "Modules") | |
| )) | |
| local subFolders = moduleFolder:GetChildrenWithFilter(Filter.Class("Folder")) | |
| local allModules = moduleFolder:GetDescendantsWithFilter(Filter.Class("ModuleScript")) | |
| local screen = guiObject:FindFirstAncestorWithFilter(Filter.Class("ScreenGui")) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --[[ | |
| Filter.Property(name, op, value) | |
| Filter.Tag(name) | |
| Filter.DescendantOf(ancestor) | |
| Filter.AncestorOf(descendant) | |
| Filter.ChildOf(parent) | |
| Filter.ParentOf(child) | |
| Filter.Class(name) | |
| Filter.ClassOf(name) | |
| Filter.Callback(callback) | |
| Filter.Group(...) | |
| Filter.ComparisonOp.Equal | |
| Filter.ComparisonOp.NotEqual | |
| Filter.ComparisonOp.Less | |
| Filter.ComparisonOp.LessOrEqual | |
| Filter.ComparisonOp.Greater | |
| Filter.ComparisonOp.GreaterOrEqual | |
| Filter.LogicalOp.And | |
| Filter.LogicalOp.Or | |
| Filter.LogicalOp.Not | |
| filter:Eval(instance) | |
| ]] | |
| local ComparisonOps | |
| local mtComparisonOps = { | |
| __tostring = function(self) | |
| return ComparisonOps[self] | |
| end, | |
| } | |
| local Equal = setmetatable({}, mtComparisonOps) | |
| local NotEqual = setmetatable({}, mtComparisonOps) | |
| local Less = setmetatable({}, mtComparisonOps) | |
| local LessOrEqual = setmetatable({}, mtComparisonOps) | |
| local Greater = setmetatable({}, mtComparisonOps) | |
| local GreaterOrEqual = setmetatable({}, mtComparisonOps) | |
| ComparisonOps = { | |
| [Equal] = "==", | |
| [NotEqual] = "~=", | |
| [Less] = "<", | |
| [LessOrEqual] = "<=", | |
| [Greater] = ">", | |
| [GreaterOrEqual] = ">=", | |
| } | |
| local compare = { | |
| [Equal] = function(a, b) return a == b end, | |
| [NotEqual] = function(a, b) return a ~= b end, | |
| [Less] = function(a, b) return a < b end, | |
| [LessOrEqual] = function(a, b) return a <= b end, | |
| [Greater] = function(a, b) return a > b end, | |
| [GreaterOrEqual] = function(a, b) return a >= b end, | |
| } | |
| local LogicalOps | |
| local mtLogicalOps = { | |
| __tostring = function(self) | |
| return LogicalOps[self] | |
| end, | |
| } | |
| local And = setmetatable({}, mtLogicalOps) | |
| local Or = setmetatable({}, mtLogicalOps) | |
| local Not = setmetatable({}, mtLogicalOps) | |
| LogicalOps = { | |
| [And] = "and", | |
| [Or] = "or", | |
| [Not] = "not", | |
| } | |
| local Filter = { | |
| ComparisonOp = { | |
| Equal = Equal, | |
| NotEqual = NotEqual, | |
| Less = Less, | |
| LessOrEqual = LessOrEqual, | |
| Greater = Greater, | |
| GreaterOrEqual = GreaterOrEqual, | |
| }, | |
| LogicalOp = { | |
| And = And, | |
| Or = Or, | |
| Not = Not, | |
| }, | |
| } | |
| local filterTypes = {} | |
| -------------------------------- | |
| -------------------------------- | |
| local function get(t, k) | |
| return t[k] | |
| end | |
| local mtFilterProperty = { | |
| __index = { | |
| Eval = function(self, instance) | |
| local ok, result = pcall(get, instance, self.name) | |
| if not ok then | |
| return false | |
| end | |
| return compare[self.op](result, self.value) | |
| end, | |
| }, | |
| __tostring = function(self) | |
| return string.format("v.%s %s (%s)", self.name, tostring(self.op), tostring(self.value)) | |
| end, | |
| } | |
| filterTypes[mtFilterProperty] = true | |
| function Filter.Property(name, op, value) | |
| local filter = { | |
| name = name, | |
| op = op, | |
| value = value, | |
| } | |
| return setmetatable(filter, mtFilterProperty) | |
| end | |
| -------------------------------- | |
| -------------------------------- | |
| local CollectionService = game:GetService("CollectionService") | |
| local mtFilterTag = { | |
| __index = { | |
| Eval = function(self, instance) | |
| return CollectionService:HasTag(instance, self.name) | |
| end, | |
| }, | |
| __tostring = function(self) | |
| return string.format("CollectionService:HasTag(v, %q)", self.name) | |
| end, | |
| } | |
| filterTypes[mtFilterTag] = true | |
| function Filter.Tag(name) | |
| local filter = { | |
| name = name, | |
| } | |
| return setmetatable(filter, mtFilterTag) | |
| end | |
| -------------------------------- | |
| -------------------------------- | |
| local mtFilterDescendantOf = { | |
| __index = { | |
| Eval = function(self, instance) | |
| return instance:IsDescendantOf(self.instance) | |
| end, | |
| }, | |
| __tostring = function(self) | |
| return string.format("v:IsDescendantOf(%s)", self.instance:GetFullName()) | |
| end, | |
| } | |
| filterTypes[mtFilterDescendantOf] = true | |
| function Filter.DescendantOf(instance) | |
| local filter = { | |
| instance = instance, | |
| } | |
| return setmetatable(filter, mtFilterDescendantOf) | |
| end | |
| -------------------------------- | |
| -------------------------------- | |
| local mtFilterAncestorOf = { | |
| __index = { | |
| Eval = function(self, instance) | |
| return instance:IsAncestorOf(self.instance) | |
| end, | |
| }, | |
| __tostring = function(self) | |
| return string.format("v:IsAncestorOf(%s)", self.instance:GetFullName()) | |
| end, | |
| } | |
| filterTypes[mtFilterAncestorOf] = true | |
| function Filter.AncestorOf(instance) | |
| local filter = { | |
| instance = instance, | |
| } | |
| return setmetatable(filter, mtFilterAncestorOf) | |
| end | |
| -------------------------------- | |
| -------------------------------- | |
| local mtFilterChildOf = { | |
| __index = { | |
| Eval = function(self, instance) | |
| return instance.Parent == self.instance | |
| end, | |
| }, | |
| __tostring = function(self) | |
| return string.format("v.Parent == %s", self.instance:GetFullName()) | |
| end, | |
| } | |
| filterTypes[mtFilterChildOf] = true | |
| function Filter.ChildOf(instance) | |
| local filter = { | |
| instance = instance, | |
| } | |
| return setmetatable(filter, mtFilterChildOf) | |
| end | |
| -------------------------------- | |
| -------------------------------- | |
| local mtFilterParentOf = { | |
| __index = { | |
| Eval = function(self, instance) | |
| return self.Parent == instance | |
| end, | |
| }, | |
| __tostring = function(self) | |
| return string.format("%s.Parent == v", self.instance:GetFullName()) | |
| end, | |
| } | |
| filterTypes[mtFilterParentOf] = true | |
| function Filter.ParentOf(instance) | |
| local filter = { | |
| instance = instance, | |
| } | |
| return setmetatable(filter, mtFilterParentOf) | |
| end | |
| -------------------------------- | |
| -------------------------------- | |
| local mtFilterClass = { | |
| __index = { | |
| Eval = function(self, instance) | |
| return instance.ClassName == self.name | |
| end, | |
| }, | |
| __tostring = function(self) | |
| return string.format("v.ClassName == %q", self.name) | |
| end, | |
| } | |
| filterTypes[mtFilterClass] = true | |
| function Filter.Class(name) | |
| local filter = { | |
| name = name, | |
| } | |
| return setmetatable(filter, mtFilterClass) | |
| end | |
| -------------------------------- | |
| -------------------------------- | |
| local mtFilterClassOf = { | |
| __index = { | |
| Eval = function(self, instance) | |
| return instance:IsA(self.name) | |
| end, | |
| }, | |
| __tostring = function(self) | |
| return string.format("v:IsA(%q)", self.name) | |
| end, | |
| } | |
| filterTypes[mtFilterClassOf] = true | |
| function Filter.ClassOf(name) | |
| local filter = { | |
| name = name, | |
| } | |
| return setmetatable(filter, mtFilterClassOf) | |
| end | |
| -------------------------------- | |
| -------------------------------- | |
| local mtFilterCallback = { | |
| __index = { | |
| Eval = function(self, instance) | |
| return self.callback(instance) | |
| end, | |
| }, | |
| __tostring = function(self) | |
| return "callback(v)" | |
| end, | |
| } | |
| filterTypes[mtFilterCallback] = true | |
| function Filter.Callback(callback) | |
| local filter = { | |
| callback = callback, | |
| } | |
| return setmetatable(filter, mtFilterCallback) | |
| end | |
| -------------------------------- | |
| -------------------------------- | |
| local mtFilterGroup = { | |
| __index = { | |
| Eval = function(self, instance) | |
| local result = false | |
| local op = Or | |
| local items = self.items | |
| local i = 1 | |
| while i <= #items do | |
| local c = true | |
| if items[i] == Not then | |
| i = i + 1 | |
| if i > #items then | |
| return false | |
| end | |
| c = false | |
| end | |
| if not filterTypes[getmetatable(items[i])] then | |
| return false | |
| end | |
| if op == And then | |
| result = result and items[i]:Eval(instance) == c | |
| elseif op == Or then | |
| result = result or items[i]:Eval(instance) == c | |
| end | |
| i = i + 1 | |
| if i < #items and not LogicalOps[items[i]] then | |
| return false | |
| end | |
| op = items[i] | |
| i = i + 1 | |
| end | |
| if LogicalOps[items[#items]] then | |
| return false | |
| end | |
| return result | |
| end, | |
| }, | |
| __tostring = function(self) | |
| local items = self.items | |
| if #items == 0 then | |
| return "(false)" | |
| end | |
| local result = "(" | |
| local i = 1 | |
| while i <= #items do | |
| if items[i] == Not then | |
| result = result .. tostring(items[i]) .. " " | |
| i = i + 1 | |
| if i > #items then | |
| return false | |
| end | |
| end | |
| if not filterTypes[getmetatable(items[i])] then | |
| return "(false)" | |
| end | |
| result = result .. tostring(items[i]) | |
| i = i + 1 | |
| if i < #items and not LogicalOps[items[i]] then | |
| return "(false)" | |
| end | |
| if LogicalOps[items[i]] then | |
| result = result .. " " .. tostring(items[i]) .. " " | |
| end | |
| i = i + 1 | |
| end | |
| if LogicalOps[items[#items]] then | |
| return "(false)" | |
| end | |
| return result .. ")" | |
| end, | |
| } | |
| filterTypes[mtFilterGroup] = true | |
| function Filter.Group(...) | |
| local filter = { | |
| items = {}, | |
| } | |
| local items = {...} | |
| if #items == 0 then | |
| error(string.format("group must contain at least one filter")) | |
| end | |
| local i = 1 | |
| while i <= #items do | |
| if items[i] == Not then | |
| filter.items[i] = items[i] | |
| i = i + 1 | |
| if i > #items then | |
| error(string.format("expected filter after argument #%d", i)) | |
| end | |
| end | |
| if not filterTypes[getmetatable(items[i])] then | |
| error(string.format("expected filter at argument #%d", i)) | |
| end | |
| filter.items[i] = items[i] | |
| i = i + 1 | |
| if i < #items and not LogicalOps[items[i]] then | |
| error(string.format("expected LogicalOp at argument #%d", i)) | |
| end | |
| filter.items[i] = items[i] | |
| i = i + 1 | |
| end | |
| if LogicalOps[items[#items]] then | |
| error(string.format("expected filter after argument #%d", #items)) | |
| end | |
| return setmetatable(filter, mtFilterGroup) | |
| end | |
| return Filter |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment