Why would someone want a toggle for all effects instead of a settings menu where you can enable or disable specific effects to fit your liking?
Well, that’s no easy task and that would take forever for me to do so
I’ve done it, it wasn’t that hard.
Oh sorry, I’m just a game designer who doesn’t know a lot of coding, because I’m kinda new here, I’m a solo dev btw.
Take for example, games that on-join let you pick PC or Mobile performance.
If you were using a phone (which can’t handle the heavy game), you would probably wanna get the best optimization for your phone to handle a heavy game. So it’s easier to just toggle all effects rather than toggle lots of options.
And plus, you’re missing the point. It’s fine if you want to make a settings GUI with multiple options, go ahead! But I made this for people who want to make a single low-quality button.
PERCLEAN - V2.0 (NEW UPDATE)
- Added the feature of being able to toggle specific effects instead of all effects
- Added new function
perclean.SetLowQualityType(...)
for new feature above (more information on documentation inside Module) - Fixed some small bugs
- Added more documentation to functions
Woah, a new update and a new logo, I’ll try it out, thanks for updating us.
PERCLEAN - V2.5 (NEW UPDATE)
-
NEW FUNCTION! You can now implement a RenderDistance system to your game
(with optional part whitelists) - Completely rewrote the entire module
- Put everything in two functions ( EnableLowQuality() & DisableLowQuality())
- Optimized the module (removed useless functions and made the code cleaner)
- Better enable/disable system for easier implementation of new toggleable effects
- Made a GitHub documentation for the module
For this update, I completely went from scratch, rewriting the entire module. I wrote Perclean a pretty long time ago, and back then I wasn’t as good of a programmer as I am now. And plus, the code was pretty messy so yeah.
I’ll probably add more documentation for each and every single toggleable effect included in the module.
Anyways yeah, this may or may not be the last update (unless I think of something else to add in this module, feel free to suggest!)
Yo bro, its a nice thing, i have still a question.
How to use the
“renderdistance”
and what exactly is (parameter 1, parameter 2) are the Numbers right ?
…
Is this right ?
Actually, nah.
The second parameter is the render distance value itself, and the third parameter is optional. Basically, you could make a table of parts that you want to whitelist. So no matter how far you are you can see those specific parts.
Documentation for all functions and how to use them can be read here.
Speaking of render distance, I accidentally forgot about making the function work whenever you DONT have a whitelist table. I guess it wasn’t actually optional before LOL-
Fixed the issue, should be working now.
Okay so now i understand render distance.
But i still don’t understand the module with:
local conState = {
castshadow = false or true??? what does false or true do?
lighting = ??
etc….
…
What i mean is, what if it’s on true on what if it’s on false?
What is changing if i change it?
Maybe im just dumb but e idk…
You don’t have to change anything in the module, that table just makes my life easier for when toggling.
I like the idea of this module but I wish there was a gui button and everything was client because there high end pcs that want to use full graphics.
You could easily implement it to a client GUI yourself. I’ve done something like this before for a friend of mine.
You can use the module for server-side AND client-side.
Example:
-- example localscript is located under a guibutton
local p = require(workspace.PercleanModule)
local button = script.Parent
button.MouseButton1Click:Connect(function()
p.EnableLowQuality("lighting")
end)
When disabling the shadows low quality, it seems to set every part’s CastShadow to true regardless of their setting before. Is there someway to exclude parts from this, as there are some parts that shouldn’t cast shadows regardless of the shadow setting.
Why not one function; ToggleLowQuality(true)
?
Hey everyone!
I made a small fork to this module for usage in my game and decided to release it in case anyone else here wants to use it.
My fork adds the option HideParticles to the effects, letting you disable all particles, beams, trails, etc from the game.
Usage is pretty simple, the one argument is has is a whitelist table. Usage example below:
local p = require(script.PercleanModule)
-- enabling
p.EnableLowQuality("hideparticles", {workspace.Baseplate.ParticleEmitter}) -- 2nd argument is an optional whitelist.
-- disabling
p.DisableLowQuality("hideparticles")
Quick note: You can also add a particles parent, so for example {workspace.Tool.Handle}
and any particles inside the handle will be ignored.
I did add checks to make sure newly added particles and/or particles that move around a lot (for example a tool with particles) are still functional with this fork.
Get the model on the Roblox website!
Or
View The Source
--[[
@author: Downrest
@author: SpiralAPI
@fork: spiralapi/perclean
@description: A simple performance module with multiple options that help optimize or make a game "low-quality" for potato devices
@documentation: https://github.com/Downrest/Perclean
]]
local PercleanModule = {}
local RS = game:GetService("ReplicatedStorage")
local RNS = game:GetService("RunService")
local PS = game:GetService("Players")
local LT = game:GetService("Lighting")
local conState = {
castshadow = false,
lighting = false,
partrendering = false,
renderdistance = false,
hideparticles = false
}
local getWorkspace = workspace
local newInstance = Instance.new
local stringMatch = string.match
local mathHuge = math.huge
local taskWait = task.wait
local taskSpawn = task.spawn
local affectedParticles = {}
function PercleanModule.EnableLowQuality(effectType, optionalParameter, optionalParameter2)
local percleanCon
if not RS:FindFirstChild("PercleanConfigurables") then
percleanCon = newInstance("Folder")
percleanCon.Name = "PercleanConfigurables"
percleanCon.Parent = RS
else
percleanCon = RS:FindFirstChild("PercleanConfigurables")
end
if effectType then
if stringMatch(effectType, "castshadow") then
if conState.castshadow == false then
conState.castshadow = true
for i,v in ipairs(getWorkspace:GetDescendants()) do
if v:IsA("UnionOperation") or v:IsA("PartOperation") or v:IsA("Part") or v:IsA("TrussPart") or v:IsA("WedgePart") then
v.CastShadow = false
end
end
else
warn("[PERCLEAN] CASTSHADOW HAS ALREADY BEEN ENABLED")
end
elseif stringMatch(effectType, "lighting") then
if conState.lighting == false then
conState.lighting = true
local lightingCon
local originalFog
if not percleanCon:FindFirstChild("Lighting") then
lightingCon = newInstance("Folder")
lightingCon.Name = "Lighting"
lightingCon.Parent = percleanCon
originalFog = newInstance("NumberValue")
originalFog.Name = "OriginalFog"
originalFog.Parent = lightingCon
if not LT:FindFirstChildWhichIsA("Atmosphere") then
originalFog.Value = LT.FogEnd
LT.FogEnd = mathHuge
else
warn("[PERCLEAN] FOG CANNOT BE CHANGED DUE TO ATMOSPHERE INSTANCE INSIDE LIGHTING")
end
else
lightingCon = percleanCon:FindFirstChild("Lighting")
originalFog = lightingCon:FindFirstChild("OriginalFog")
if not LT:FindFirstChildWhichIsA("Atmosphere") then
originalFog.Value = LT.FogEnd
LT.FogEnd = mathHuge
else
warn("[PERCLEAN] FOG CANNOT BE CHANGED DUE TO ATMOSPHERE INSTANCE INSIDE LIGHTING")
end
end
for i,v in ipairs(LT:GetChildren()) do
if not v:IsA("Sky") and not v:IsA("NumberValue") then
v:Clone().Parent = lightingCon
v:Destroy()
end
end
LT.GlobalShadows = false
LT.EnvironmentDiffuseScale = 0
LT.EnvironmentSpecularScale = 0
else
warn("[PERCLEAN] LIGHTING HAS ALREADY BEEN ENABLED")
end
elseif stringMatch(effectType, "partrendering") then
if conState.partrendering == false then
conState.partrendering = true
for i,v in ipairs(getWorkspace:GetDescendants()) do
if v:IsA("PartOperation") or v:IsA("Part") or v:IsA("TrussPart") or v:IsA("WedgePart") then
if v.Material == Enum.Material.Glass then
v.Transparency = 1
v.Reflectance = 0
end
elseif v:IsA("UnionOperation") then
if v.Material == Enum.Material.Glass then
v.Transparency = 1
v.Reflectance = 0
end
v.SmoothingAngle = 1
v.RenderFidelity = Enum.RenderFidelity.Automatic
end
end
else
warn("PERCLEAN] PARTRENDERING HAS ALREADY BEEN ENABLED")
end
elseif stringMatch(effectType, "renderdistance") then
if conState.renderdistance == false then
conState.renderdistance = true
if RNS:IsClient() then
local player = PS.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
if optionalParameter then
taskSpawn(function()
while taskWait(.2) do
if conState.renderdistance == false then
break
end
for i,v in ipairs(workspace:GetDescendants()) do
if v:IsA("Part") or v:IsA("MeshPart") or v:IsA("TrussPart") or v:IsA("WedgePart") or v:IsA("CornerWedgePart") or v:IsA("PartOperation") or v:IsA("UnionOperation") and not v:IsDescendantOf(character) then
if optionalParameter2 then
for i = 1, #optionalParameter2, 1 do
optionalParameter2[i].Transparency = 0
end
if (character.Head.Position - v.Position).Magnitude > optionalParameter then
v.Transparency = 1
else
v.Transparency = 0
end
else
if (character.Head.Position - v.Position).Magnitude > optionalParameter then
v.Transparency = 1
else
v.Transparency = 0
end
end
end
end
end
end)
else
error("[PERCLEAN] PLEASE INSERT A PARAMETER FOR THE DISTANCE")
end
else
warn("[PERCLEAN] YOU CANNOT RUN THIS FUNCTION IN SERVER, ONLY IN CLIENT")
end
else
warn("[PERCLEAN] RENDERDISTANCE HAS ALREADY BEEN ENABLED")
end
elseif stringMatch(effectType, "hideparticles") then
if conState.hideparticles == false then
conState.renderdistance = true
if RNS:IsClient() then
local whitelist
if optionalParameter then
if type(optionalParameter) == "table" then
whitelist = optionalParameter
else
warn("[PERCLEAN] PLEASE INSERT A TABLE FOR PARTICLE WHITELIST")
end
else
whitelist = {}
end
local function checkParticle(particle)
if particle:IsA("ParticleEmitter") or particle:IsA("Beam") or particle:IsA("Trail") or particle:IsA("Sparkles") or particle:IsA("Smoke") or particle:IsA("Fire") then
if whitelist[particle] == nil and whitelist[particle.Parent] == nil then
particle.Enabled = false
table.insert(affectedParticles, particle)
end
end
end
for i, v in pairs(workspace:GetDescendants()) do
checkParticle(v)
end
_G.ParticleConnection = game.Workspace.DescendantAdded:Connect(function(desc)
checkParticle(desc)
end)
else
warn("[PERCLEAN] YOU CANNOT RUN THIS FUNCTION IN SERVER, ONLY IN CLIENT")
end
else
warn("[PERCLEAN] HIDEPARTICLES HAS ALREADY BEEN ENABLED")
end
end
end
end
function PercleanModule.DisableLowQuality(effectType)
local percleanCon
if not RS:FindFirstChild("PercleanConfigurables") then
percleanCon = newInstance("Folder")
percleanCon.Name = "PercleanConfigurables"
percleanCon.Parent = RS
else
percleanCon = RS:FindFirstChild("PercleanConfigurables")
end
if effectType then
if stringMatch(effectType, "castshadow") then
if conState.castshadow == true then
conState.castshadow = false
for i,v in ipairs(getWorkspace:GetDescendants()) do
if v:IsA("UnionOperation") or v:IsA("PartOperation") or v:IsA("Part") or v:IsA("TrussPart") or v:IsA("WedgePart") then
v.CastShadow = true
end
end
else
warn("[PERCLEAN] CASTSHADOW HAS ALREADY BEEN DISABLED")
end
elseif stringMatch(effectType, "lighting") then
if conState.lighting == true then
conState.lighting = false
local lightingCon
local originalFog
if not percleanCon:FindFirstChild("Lighting") then
lightingCon = newInstance("Folder")
lightingCon.Name = "Lighting"
lightingCon.Parent = percleanCon
if not LT:FindFirstChildWhichIsA("Atmosphere") then
if originalFog then
LT.FogEnd = originalFog.Value
else
warn("[PERCLEAN] ORIGINAL FOG VALUE CANNOT BE FOUND, UNABLE TO CHANGE FOG")
end
else
warn("[PERCLEAN] FOG CANNOT BE CHANGED DUE TO ATMOSPHERE INSTANCE INSIDE LIGHTING")
end
else
lightingCon = percleanCon:FindFirstChild("Lighting")
originalFog = lightingCon:FindFirstChild("OriginalFog")
if not LT:FindFirstChildWhichIsA("Atmosphere") then
if originalFog then
LT.FogEnd = originalFog.Value
else
warn("[PERCLEAN] ORIGINAL FOG VALUE CANNOT BE FOUND, UNABLE TO CHANGE FOG")
end
else
warn("[PERCLEAN] FOG CANNOT BE CHANGED DUE TO ATMOSPHERE INSTANCE INSIDE LIGHTING")
end
end
for i,v in ipairs(lightingCon:GetChildren()) do
if not v:IsA("Sky") and not v:IsA("NumberValue") then
v:Clone().Parent = LT
v:Destroy()
end
end
LT.GlobalShadows = true
LT.EnvironmentDiffuseScale = 1
LT.EnvironmentSpecularScale = 1
else
warn("[PERCLEAN] LIGHTING HAS ALREADY BEEN DISABLED")
end
elseif stringMatch(effectType, "partrendering") then
if conState.partrendering == true then
conState.partrendering = false
for i,v in ipairs(getWorkspace:GetDescendants()) do
if v:IsA("PartOperation") or v:IsA("Part") or v:IsA("TrussPart") or v:IsA("WedgePart") then
if v.Material == Enum.Material.Glass then
v.Transparency = .5
v.Reflectance = 1
end
elseif v:IsA("UnionOperation") then
if v.Material == Enum.Material.Glass then
v.Transparency = .5
v.Reflectance = 1
end
v.SmoothingAngle = 1
v.RenderFidelity = Enum.RenderFidelity.Performance
end
end
else
warn("PERCLEAN] PARTRENDERING HAS ALREADY BEEN DISABLED")
end
elseif stringMatch(effectType, "renderdistance") then
if conState.renderdistance == true then
if RNS:IsClient() then
local player = PS.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
for i,v in ipairs(game:GetDescendants()) do
if v:IsA("Part") and not v:IsDescendantOf(character) then
v.Transparency = 0
end
end
conState.renderdistance = false
else
warn("[PERCLEAN] YOU CANNOT RUN THIS FUNCTION IN SERVER, ONLY IN CLIENT")
end
else
warn("[PERCLEAN] RENDERDISTANCE HAS ALREADY BEEN DISABLED")
end
elseif stringMatch(effectType, "hideparticles") then
if conState.renderdistance == true then
if RNS:IsClient() then
for i, particle in pairs(workspace:GetDescendants()) do
if particle:IsA("ParticleEmitter") or particle:IsA("Beam") or particle:IsA("Trail") or particle:IsA("Sparkles") or particle:IsA("Smoke") or particle:IsA("Fire") then
particle.Enabled = true
end
end
for i, particle in pairs(affectedParticles) do -- if your wondering why bother its because it stops particles that were removed during a period of less detail from hiding when it is turned off.
particle.Enabled = true
affectedParticles[particle] = nil
end
_G.ParticleConnection:Disconnect() -- gotta keep your game tidy
conState.renderdistance = false
else
warn("[PERCLEAN] YOU CANNOT RUN THIS FUNCTION IN SERVER, ONLY IN CLIENT")
end
else
warn("[PERCLEAN] HIDEPARTICLES HAS ALREADY BEEN DISABLED")
end
end
end
end
return PercleanModule
Oh hey, that’s a pretty cool fork you got there.
New Version Out!
I present to you… GraphicsEditor!
GraphicsEditor supersedes Perclean. The difference is, that I rewrote the module from scratch. Unlike Perclean, this utilizes OOP instead of folders for its inner workings. It is also more efficient, has more options, is easier to use, and the code is more organized which makes it easier to update this module.
You can think of this as an update to Perclean, only now it has a different name.
I WILL NOT BE MAINTANING PERCLEAN ANYMORE, SWITCH TO GRAPHICSEDITOR FOR FREQUENT UPDATES!
Do note that it still functions the exact way as Perclean and has the same purpose!