SimpleWeather V2.0 - A Easy To Use Weather Module

Fork the module or add new weather; thats what I did. The weather.WeatherTypes = { is very powerful

wow this is amazing. it’s a shame that it’s only client-sided and rain still appears under shelter

This is a really cool module, i like that the default weather types dont change the ambient/time which in my game is required.

Also, to anyone saying that rain doesnt dissapear under shelter, you are wrong. The rain system this uses was made for large areas, not buildings with thin roofs that are very small. You only see the rain under bigger shelter, where its not noticeable enough.

i remade the module cause storing everything in replicatedstorage for my use was bad and now you can just call SimpleWeather:Start(“weathername”) instead of adding attribute to, heres code:

--[[
Credits are not required,  but  they  are  greatly  appreciated!  :)

    SimpleWeather Module by JordanGetMeBackmyAcc & sans_DAM

    Special  thanks:
    	- buildthomas for the Rain System.
   		- sleitnick for the EZ Camera Shake Module.
]]

local SimpleWeather = {Weathers = {}}

local Lighting = game:GetService("Lighting")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local ContentProvider = game:GetService("ContentProvider")
local Debris = game:GetService("Debris")

local CurrentCamera = workspace.CurrentCamera
local Terrain = workspace.Terrain

local RainModule = require(script:WaitForChild("Rain"))
local CameraShaker = require(script:WaitForChild("CameraShaker")).new(Enum.RenderPriority.Camera.Value, function(shakeCF)
	CurrentCamera.CFrame = CurrentCamera.CFrame * shakeCF
end)

for _, weathers in pairs(script.Weathers.Lighting:GetChildren()) do
	local weatherName = weathers.Name
	local sky = script.Weathers.Skys:FindFirstChild(weatherName) or script.Weathers.Skys.Default

	SimpleWeather.Weathers[weatherName] = {
		Lighting = weathers,
		Sky = sky
	}
end

task.spawn(function()
	ContentProvider:PreloadAsync({script.Weathers.Skys})
end)

function ChangeWeather(weatherName)
	local data = SimpleWeather.Weathers[weatherName]
	if data then
		local LightingProperties : Folder = data.Lighting
		local Sky : Folder = data.Sky

		local tweenInfo = TweenInfo.new(0.4, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut)
		local tweenInfo2 = TweenInfo.new(1.5, Enum.EasingStyle.Linear, Enum.EasingDirection.InOut)

		if LightingProperties then
			if Lighting:FindFirstChildOfClass("Atmosphere") then
				if LightingProperties:FindFirstChild("AtmosphereDensity") then
					TweenService:Create(Lighting:FindFirstChildOfClass("Atmosphere"), tweenInfo, {Density = LightingProperties.AtmosphereDensity.Value}):Play()
				end
				if LightingProperties:FindFirstChild("AtmosphereOffset") then
					TweenService:Create(Lighting:FindFirstChildOfClass("Atmosphere"), tweenInfo, {Offset = LightingProperties.AtmosphereOffset.Value}):Play()
				end
				if LightingProperties:FindFirstChild("AtmosphereColor") then
					TweenService:Create(Lighting:FindFirstChildOfClass("Atmosphere"), tweenInfo, {Color = LightingProperties.AtmosphereColor.Value}):Play()
				else
					TweenService:Create(Lighting:FindFirstChildOfClass("Atmosphere"), tweenInfo, {Color = Color3.fromRGB(199, 170, 107)}):Play()
				end
				if LightingProperties:FindFirstChild("AtmosphereDecay") then
					TweenService:Create(Lighting:FindFirstChildOfClass("Atmosphere"), tweenInfo, {Decay = LightingProperties.AtmosphereDecay.Value}):Play()
				else
					TweenService:Create(Lighting:FindFirstChildOfClass("Atmosphere"), tweenInfo, {Decay =  Color3.fromRGB(92, 60, 13)}):Play()
				end
				if LightingProperties:FindFirstChild("AtmosphereGlare") then
					TweenService:Create(Lighting:FindFirstChildOfClass("Atmosphere"), tweenInfo, {Glare = LightingProperties.AtmosphereGlare.Value}):Play()
				else
					TweenService:Create(Lighting:FindFirstChildOfClass("Atmosphere"), tweenInfo, {Glare = 0}):Play()
				end
				if LightingProperties:FindFirstChild("AtmosphereHaze") then
					TweenService:Create(Lighting:FindFirstChildOfClass("Atmosphere"), tweenInfo, {Haze = LightingProperties.AtmosphereHaze.Value}):Play()
				else
					TweenService:Create(Lighting:FindFirstChildOfClass("Atmosphere"), tweenInfo, {Haze = 0}):Play()
				end
			end

			if Terrain:FindFirstChildOfClass("Clouds") then
				if LightingProperties:FindFirstChild("CloudsCover") then
					TweenService:Create(Terrain:FindFirstChildOfClass("Clouds"), tweenInfo2, {Cover = LightingProperties.CloudsCover.Value}):Play()
				end
				if LightingProperties:FindFirstChild("CloudsDensity") then
					TweenService:Create(Terrain:FindFirstChildOfClass("Clouds"), tweenInfo2, {Density = LightingProperties.CloudsDensity.Value}):Play()
				end
			end

			if LightingProperties:FindFirstChild("GrassDirection") then
				TweenService:Create(workspace, tweenInfo2, {GlobalWind = LightingProperties.GrassDirection.Value}):Play()
			end

			if LightingProperties:FindFirstChild("WaterWaveSize") then
				TweenService:Create(Terrain, tweenInfo2, {WaterWaveSize = LightingProperties.WaterWaveSize.Value}):Play()
			end

			if LightingProperties:FindFirstChild("WaterWaveSpeed") then
				TweenService:Create(Terrain, tweenInfo2, {WaterWaveSpeed = LightingProperties.WaterWaveSpeed.Value}):Play()
			end

			for _, properties in pairs(LightingProperties:GetChildren()) do
				pcall(function()
					local targetProperty = game.Lighting[properties.Name]
					local targetValue = properties

					if targetValue:IsA("Color3Value") then
						targetValue = Color3.fromRGB(targetValue.Value.R, targetValue.Value.G, targetValue.Value.B)
					elseif targetValue:IsA("NumberValue") then
						targetValue = tonumber(targetValue.Value)
					elseif targetValue:IsA("BoolValue") then
						targetValue = tostring(targetValue.Value) == "true"
					end

					local tween = TweenService:Create(Lighting, tweenInfo, { [properties.Name] = targetValue})
					tween:Play()
				end)
			end
		end

		if Sky then
			if Lighting:FindFirstChildOfClass("Sky") then
				Lighting:FindFirstChildOfClass("Sky"):Destroy()
			end
			Sky.Sky:Clone().Parent = Lighting
		end
	end
end

function SimpleWeather:Start(weatherName)
	weatherName = weatherName or "Default"

	if self.Started then
		for _, signals in pairs(self.Signals) do
			if typeof(signals) ~= "thread" then
				pcall(function() signals:Disconnect() end)
			else
				task.cancel(signals)
			end
		end
		RainModule:Disable(TweenInfo.new(0.5))
	end

	self.Started = true

	self.Fog = script:WaitForChild("Assets").Fog:Clone()
	self.Snow = script:WaitForChild("Assets").Snow:Clone()

	self.Fog.Parent = CurrentCamera
	self.Snow.Parent = CurrentCamera

	local weatherData = SimpleWeather.Weathers[weatherName]
	local weatherLighting = weatherData and weatherData.Lighting

	self.State = {
		RainEnabled = false,
		Rain = false,
		Fog = false,
		Snow = false,
		Thunderstorm = false,
		CurrentWeather = weatherName
	}

	if weatherLighting then
		self.State.Rain = weatherLighting:FindFirstChild("Rains") and weatherLighting.Rains.Value or false
		self.State.Fog = weatherLighting:FindFirstChild("Fog") and weatherLighting.Fog.Value or false
		self.State.Snow = weatherLighting:FindFirstChild("Snow") and weatherLighting.Snow.Value or false
		self.State.Thunderstorm = weatherLighting:FindFirstChild("Thunderstorm") and weatherLighting.Thunderstorm.Value or false
	end

	CameraShaker:Start()
	RainModule:SetCollisionMode(RainModule.CollisionMode.Blacklist, self.Fog)
	RainModule:SetCollisionMode(RainModule.CollisionMode.Blacklist, self.Snow)

	RainModule:SetCollisionMode(
		RainModule.CollisionMode.Function,
		function(p)
			return p.Transparency <= 1 and p.CanCollide and not p:IsA("MeshPart")
		end
	)

	self.Signals = {}

	ChangeWeather(weatherName)

	self.Signals.Signal1 = RunService.RenderStepped:Connect(function()
		self.Fog.CFrame = CurrentCamera.CFrame
		self.Snow.CFrame = CurrentCamera.CFrame

		if self.State.Fog then
			self.Fog.ParticleEmitter.Enabled = true
		else
			self.Fog.ParticleEmitter.Enabled = false
		end

		if self.State.Snow then
			self.Snow.ParticleEmitter.Enabled = true
		else
			self.Snow.ParticleEmitter.Enabled = false
		end

		if self.State.Rain then
			if not self.State.RainEnabled then
				self.State.RainEnabled = true
				RainModule:Enable(TweenInfo.new(1))
			end
		else
			if self.State.RainEnabled then
				self.State.RainEnabled = false
				RainModule:Disable(TweenInfo.new(1))
			end
		end
	end)

	self.Signals.Signal2 = task.spawn(function()
		while true do
			task.wait(math.random(60, 90))
			if not self.Started then break end
			if self.State.Thunderstorm then
				local player = game:GetService("Players").LocalPlayer
				local character = player.Character or player.CharacterAdded:Wait()
				local hrp = character:WaitForChild("HumanoidRootPart")

				local offset = Vector3.new(math.random(-90, 90), 0, math.random(-90, 90))
				local rayOrigin = hrp.Position + offset + Vector3.new(0, 100, 0)
				local rayDirection = Vector3.new(0, -200, 0)

				local rayResult = workspace:Raycast(rayOrigin, rayDirection)
				if rayResult then
					local lightning = script.Assets.Lightning:Clone()
					lightning.Parent = workspace

					local heightOffset = lightning.Size.Y / 2
					lightning.CFrame = CFrame.new(rayResult.Position + Vector3.new(0, heightOffset, 0))

					local debrisAttach = lightning:FindFirstChild("DebrisBlock", true)
					if debrisAttach and debrisAttach:IsA("Attachment") then
						local debrisParent = debrisAttach.Parent
						if debrisParent and debrisParent:IsA("BasePart") then
							debrisParent.Position = rayResult.Position + Vector3.new(0, 0.1, 0)
							debrisParent.Anchored = true

							local debrisEmitter = debrisAttach:FindFirstChildOfClass("ParticleEmitter")
							if debrisEmitter then
								debrisEmitter:Emit(50)
								if rayResult.Instance:IsA("BasePart") then
									debrisEmitter.Color = ColorSequence.new(rayResult.Instance.Color)
								elseif rayResult.Instance:IsA("Terrain") then
									debrisEmitter.Color = ColorSequence.new(Terrain:GetMaterialColor(rayResult.Material))
								end
							end
						end
					end

					CameraShaker:ShakeOnce(2, 0.6, 0.1, 0.3)
					lightning.lightning_strike:Play()
					lightning.Lightning.Enabled = true
					task.delay(1, function()
						lightning.Lightning.Enabled = false
					end)

					Debris:AddItem(lightning, lightning.lightning_strike.TimeLength + 5)
				end
			end
		end
	end)
end

function SimpleWeather:Stop()
	if self.Started then
		self.Started = false
		self.State.RainEnabled = false

		for _, signals in pairs(self.Signals) do
			if typeof(signals) ~= "thread" then
				pcall(function() signals:Disconnect() end)
			else
				task.cancel(signals)
			end
		end

		CameraShaker:Stop()
		RainModule:Disable(TweenInfo.new(1))
	end
end

return SimpleWeather
1 Like

I WAS going to build my own system for my game, but this seems like such a great save of time, thank you SO much, this is AWESOME!!!