Created
May 17, 2026 01:44
-
-
Save mvyasu/3123c07817f0011e3f650f95de4e11a5 to your computer and use it in GitHub Desktop.
an applyLighting function that can handle tweens and complex setups
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
| const TweenService = game:GetService("TweenService") | |
| const Lighting = game:GetService("Lighting") | |
| const TWEENABLE_TYPES: { [string]: boolean } = { | |
| number = true, | |
| Color3 = true, | |
| Vector2 = true, | |
| Vector3 = true, | |
| CFrame = true, | |
| UDim = true, | |
| UDim2 = true, | |
| Rect = true, | |
| Vector2int16 = true, | |
| Vector3int16 = true, | |
| } | |
| const CONTAINER_POOL_CLASSES: { [string]: { string } } = { | |
| Lighting = { "Sky", "Atmosphere", "PostEffect" }, | |
| Camera = { "PostEffect" }, | |
| Terrain = { "Clouds" }, | |
| } | |
| type InstanceProperties = { [string]: any } | |
| type ContainerClassName = "Lighting" | "Camera" | |
| type Preset = { | |
| Lighting: InstanceProperties, | |
| Atmosphere: InstanceProperties?, | |
| Sky: InstanceProperties?, | |
| Clouds: InstanceProperties?, | |
| PostEffects: { | |
| [ContainerClassName]: { | |
| [string]: { InstanceProperties } | InstanceProperties, | |
| }, | |
| }?, | |
| } | |
| local activeTweens: { Tween } = {} | |
| local function cancelActiveTweens() | |
| for _, tween in activeTweens do | |
| tween:Cancel() | |
| end | |
| table.clear(activeTweens) | |
| end | |
| local function separateProperties(properties: InstanceProperties): (InstanceProperties, InstanceProperties) | |
| local tweenableProps: InstanceProperties = {} | |
| local immediateProps: InstanceProperties = {} | |
| for key, value in properties do | |
| if key == "Parent" then | |
| continue | |
| end | |
| if TWEENABLE_TYPES[typeof(value)] then | |
| tweenableProps[key] = value | |
| else | |
| immediateProps[key] = value | |
| end | |
| end | |
| return tweenableProps, immediateProps | |
| end | |
| local function applyProperties(instance: Instance, properties: InstanceProperties, tweenInfo: TweenInfo?) | |
| local tweenableProps, immediateProps = separateProperties(properties) | |
| for key, value in immediateProps do | |
| (instance :: any)[key] = value | |
| end | |
| if tweenInfo ~= nil and next(tweenableProps) ~= nil then | |
| local tween = TweenService:Create(instance, tweenInfo, tweenableProps) | |
| table.insert(activeTweens, tween) | |
| tween:Play() | |
| else | |
| for key, value in tweenableProps do | |
| (instance :: any)[key] = value | |
| end | |
| end | |
| end | |
| local function buildPool(container: Instance, relevantClasses: { string }): { Instance } | |
| local pool: { Instance } = {} | |
| for _, child in container:GetChildren() do | |
| for _, className in relevantClasses do | |
| if child:IsA(className) then | |
| table.insert(pool, child) | |
| break | |
| end | |
| end | |
| end | |
| return pool | |
| end | |
| local function findBestMatch( | |
| pool: { Instance }, | |
| className: string, | |
| properties: InstanceProperties? | |
| ): (Instance?, number?) | |
| local nameMatch: Instance? = nil | |
| local nameMatchIndex: number? = nil | |
| local classMatch: Instance? = nil | |
| local classMatchIndex: number? = nil | |
| for index, object in pool do | |
| local classMatches = object.ClassName == className | |
| local nameMatches = properties ~= nil and (object :: any).Name == properties.Name | |
| if classMatches and nameMatches then | |
| return object, index | |
| end | |
| if nameMatches and nameMatch == nil then | |
| nameMatch = object | |
| nameMatchIndex = index | |
| end | |
| if classMatches and classMatch == nil then | |
| classMatch = object | |
| classMatchIndex = index | |
| end | |
| end | |
| if nameMatch ~= nil then | |
| return nameMatch, nameMatchIndex | |
| end | |
| return classMatch, classMatchIndex | |
| end | |
| local function setupObject( | |
| container: Instance, | |
| pool: { Instance }, | |
| className: string, | |
| properties: InstanceProperties?, | |
| tweenInfo: TweenInfo? | |
| ) | |
| if properties == nil then | |
| return | |
| end | |
| local existingInstance, poolIndex = findBestMatch(pool, className, properties) | |
| local instance: Instance | |
| if existingInstance ~= nil then | |
| instance = existingInstance | |
| table.remove(pool, poolIndex :: number) | |
| else | |
| instance = Instance.new(className) | |
| end | |
| applyProperties(instance, properties, tweenInfo) | |
| if instance.Parent ~= container then | |
| instance.Parent = container | |
| end | |
| end | |
| local function cleanupPool(pool: { Instance }) | |
| for _, instance in pool do | |
| instance.Parent = nil | |
| end | |
| end | |
| local function resolveContainer(containerName: ContainerClassName, camera: Camera): Instance? | |
| if containerName == "Lighting" then | |
| return Lighting | |
| elseif containerName == "Camera" then | |
| return camera | |
| end | |
| return nil | |
| end | |
| local function applyPostEffects( | |
| postEffects: { [ContainerClassName]: { [string]: { InstanceProperties } | InstanceProperties } }, | |
| containerPools: { [Instance]: { Instance } }, | |
| camera: Camera, | |
| tweenInfo: TweenInfo? | |
| ) | |
| for containerName, containerDescendants in postEffects do | |
| local container = resolveContainer(containerName, camera) | |
| if container == nil then | |
| continue | |
| end | |
| local pool = containerPools[container] | |
| if pool == nil then | |
| continue | |
| end | |
| for postEffectClass, postEffectData in containerDescendants do | |
| local _, firstValue = next(postEffectData) | |
| if typeof(firstValue) == "table" then | |
| for _, properties in postEffectData :: { InstanceProperties } do | |
| setupObject(container, pool, postEffectClass, properties, tweenInfo) | |
| end | |
| else | |
| setupObject(container, pool, postEffectClass, postEffectData :: InstanceProperties, tweenInfo) | |
| end | |
| end | |
| end | |
| end | |
| local function applyLighting(preset: Preset, tweenInfo: TweenInfo?) | |
| cancelActiveTweens() | |
| local terrain = workspace.Terrain | |
| local camera = workspace.CurrentCamera | |
| local lightingPool = buildPool(Lighting, CONTAINER_POOL_CLASSES.Lighting) | |
| local terrainPool = buildPool(terrain, CONTAINER_POOL_CLASSES.Terrain) | |
| local cameraPool = buildPool(camera, CONTAINER_POOL_CLASSES.Camera) | |
| local containerPools: { [Instance]: { Instance } } = { | |
| [Lighting] = lightingPool, | |
| [camera] = cameraPool, | |
| } | |
| applyProperties(Lighting, preset.Lighting, tweenInfo) | |
| setupObject(Lighting, lightingPool, "Sky", preset.Sky, tweenInfo) | |
| setupObject(Lighting, lightingPool, "Atmosphere", preset.Atmosphere, tweenInfo) | |
| setupObject(terrain, terrainPool, "Clouds", preset.Clouds, tweenInfo) | |
| if preset.PostEffects ~= nil then | |
| applyPostEffects(preset.PostEffects, containerPools, camera, tweenInfo) | |
| end | |
| cleanupPool(lightingPool) | |
| cleanupPool(terrainPool) | |
| cleanupPool(cameraPool) | |
| end | |
| return applyLighting |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment