FiveM Hava Durumu Senkronizasyonu: Dinamik Hava ve Zaman Scriptleri
FiveM sunucunuz genelinde hava durumunu ve zamanı senkronize edin. Dinamik döngüler, gök gürültüsü, kar, mevsim paketleri ve atmosferi belirleyen en iyi hava durumu scriptleri.
Agency Scripts
Agency Scripts Kurucusu ve Baş Geliştiricisi
Senkronize Olmayan Hava Durumu Sorunu
Varsayılan olarak GTA V, hava durumunu ve zamanı her istemcide bağımsız olarak işler. Bu, bir oyuncu pırıl pırıl güneş altında araç kullanırken hemen yanındaki diğer bir oyuncunun fırtına görmesi anlamına gelir. Roleplay sunucuları için bu durum rol atmosferini tamamen bozar. Bir karakterin yağmurdan şikayet ettiği, başka bir oyuncunun ekranında ise havanın açık olduğu bir sahneyi koordine etmeye çalıştığınızı hayal edin. Senkronize bir hava durumu ve zaman sistemi, sunucudaki her oyuncunun aynı anda aynı ortamı deneyimlemesini sağlar: Bu da tutarlı roleplay, gerçekçi sürüş koşulları ve etkinlik koordinasyonu için temel bir gerekliliktir. Bu rehberde; yapılandırılabilir zaman hızı, mevsimsel geçişler, hava durumu oylaması ve blackout etkinlikleri içeren eksiksiz bir hava durumu senkronizasyon sistemi geliştireceğiz.
Sunucu Taraflı Hava Durumu Yönetimi
Sunucu, hava durumu ve saat için tek doğru kaynaktır. Mevcut hava durumu türünü, geçişler için bir sonraki hava durumu türünü ve oyun içi saati yönetir. Her client katıldığında bu duruma senkronize olur ve hava durumu her değiştiğinde güncellemeleri alır. GTA V, şunlar dahil olmak üzere belirli bir hava durumu türü kümesini destekler: CLEAR, EXTRASUNNY, CLOUDS, OVERCAST, RAIN, THUNDER, CLEARING, FOGGY, SMOG, SNOW, SNOWLIGHT, BLIZZARD, ve XMAS. Hava durumunun ara bir durum olmadan kar fırtınasından çok güneşliye aniden atlaması yerine doğal bir şekilde akması için mantıksal geçiş kuralları tanımlayın.
-- server.lua
local Config = {
timeSpeed = 2, -- how many in-game minutes per real second
syncInterval = 30000, -- full sync broadcast every 30s
autoChange = true, -- automatic weather cycling
changeCooldown = 600, -- seconds between automatic changes
}
local State = {
weather = 'CLEAR',
nextWeather = 'CLOUDS',
hour = 12,
minute = 0,
frozen = false,
blackout = false,
season = 'summer',
}
local weatherTransitions = {
EXTRASUNNY = {'CLEAR', 'CLOUDS'},
CLEAR = {'EXTRASUNNY', 'CLOUDS', 'OVERCAST'},
CLOUDS = {'CLEAR', 'OVERCAST', 'RAIN'},
OVERCAST = {'CLOUDS', 'RAIN', 'THUNDER', 'FOGGY'},
RAIN = {'OVERCAST', 'THUNDER', 'CLEARING'},
THUNDER = {'RAIN', 'OVERCAST'},
CLEARING = {'CLEAR', 'CLOUDS'},
FOGGY = {'CLEAR', 'CLOUDS', 'SMOG'},
SMOG = {'FOGGY', 'CLEAR'},
}
local seasonWeights = {
summer = {EXTRASUNNY = 30, CLEAR = 30, CLOUDS = 20, RAIN = 10, THUNDER = 5, FOGGY = 5},
winter = {CLOUDS = 20, OVERCAST = 20, SNOW = 25, SNOWLIGHT = 15, BLIZZARD = 10, FOGGY = 10},
spring = {CLEAR = 25, CLOUDS = 25, RAIN = 20, CLEARING = 15, FOGGY = 10, OVERCAST = 5},
autumn = {CLOUDS = 25, OVERCAST = 25, RAIN = 20, FOGGY = 15, CLEAR = 10, SMOG = 5},
}
Zaman İlerlemesi ve Senkronizasyon Döngüsü
Zaman sistemi, oyun içi saati yapılandırılan hıza göre artıran sunucu tarafı bir döngü olarak çalışır. Bir timeSpeed değerinin 2 olması, gerçek dünyadaki her saniyenin oyun içi saati 2 dakika ilerlettiği anlamına gelir. Bu, tam bir 24 oyun içi saat için yaklaşık 12 gerçek dünya dakikası süren bir gece gündüz döngüsü oluşturur. Sunucu, mevcut saati ve hava durumunu düzenli aralıklarla tüm istemcilere yayınlar ve bir yönetici hava durumunu değiştirdiğinde veya bir elektrik kesintisi etkinliği tetiklediğinde anlık güncellemeler gönderir. Oturumun ortasında katılan yeni oyuncular, geçerli durumu özel bir senkronizasyon olayı aracılığıyla alır, böylece diğer herkesle anında eşitlenirler.
-- Time progression loop (server.lua continued)
CreateThread(function()
while true do
Wait(1000)
if not State.frozen then
State.minute = State.minute + Config.timeSpeed
if State.minute >= 60 then
State.hour = State.hour + math.floor(State.minute / 60)
State.minute = State.minute % 60
end
if State.hour >= 24 then
State.hour = State.hour % 24
end
end
end
end)
-- Periodic full sync
CreateThread(function()
while true do
Wait(Config.syncInterval)
TriggerClientEvent('weather:fullSync', -1, State)
end
end)
-- Sync new players on join
AddEventHandler('playerJoining', function()
local src = source
Wait(2000)
TriggerClientEvent('weather:fullSync', src, State)
end)
Client Tarafı Hava Durumu Uygulaması
Client üzerinde GTA'nın yerel hava durumu ve zaman sistemlerini geçersiz kılmanız gerekir. Temel native'ler: SetWeatherTypeNowPersist anlık hava durumu değişiklikleri için, SetWeatherTypeTransition iki hava durumu arasında pürüzsüz geçiş için ve NetworkOverrideClockTime oyun içi saati ayarlamak için. Şunu çağırmalısınız: NetworkOverrideClockTime oyunun kendi zaman hesaplamasına geri dönmesini önlemek için her karede (frame). Hava durumu geçişleri için GTA, iki hava durumu durumu arasında birkaç saniye boyunca sorunsuz bir şekilde enterpolasyon yapmanızı sağlayan 0.0 ile 1.0 arasında bir blend factor destekler; bu da yağmur başlamadan önce bulutların yavaşça toplandığı gerçekçi geçişler oluşturur.
-- client.lua
local currentWeather = 'CLEAR'
local nextWeather = 'CLEAR'
local weatherBlend = 0.0
local hour, minute = 12, 0
local blackout = false
RegisterNetEvent('weather:fullSync', function(state)
currentWeather = state.weather
nextWeather = state.nextWeather or state.weather
hour = state.hour
minute = state.minute
blackout = state.blackout or false
applyWeather()
end)
function applyWeather()
ClearOverrideWeather()
ClearWeatherTypePersist()
SetWeatherTypeNowPersist(currentWeather)
if currentWeather ~= nextWeather then
SetWeatherTypeTransition(
GetHashKey(currentWeather),
GetHashKey(nextWeather),
weatherBlend
)
end
if blackout then
SetArtificialLightsState(true)
SetArtificialLightsStateAffectsVehicles(false)
else
SetArtificialLightsState(false)
end
end
-- Override clock every frame
CreateThread(function()
while true do
Wait(0)
NetworkOverrideClockTime(hour, minute, 0)
end
end)
Hava Durumu Oylama Sistemi
Hava durumu oylama sistemi, topluluğunuzun hava durumuna demokratik olarak karar vermesini sağlar. Oyuncular tercih ettikleri hava türü için oy kullanabilir ve oylama süresinin ardından en popüler seçenek kazanır. Bu, bir araba buluşmasının açık hava altında mı yoksa fırtınalı bir gökyüzünde mi gerçekleşeceğine karar vermek gibi oyuncu katılımı istediğiniz etkinlikler için oldukça uygundur. İstenmeyen oyları önlemek için oylamayı döngü başına bir kez ile sınırlayın ve güncel oy sayılarını bildirim sisteminiz veya basit bir NUI katmanı aracılığıyla gösterin. Sunucu oyları toplar, süre dolduğunda sayar ve kazanan hava durumunu yumuşak bir geçişle uygular, böylece tüm oyuncular değişikliği aynı anda deneyimler.
-- Weather voting (server.lua)
local votes = {}
local voteCooldown = {}
local votingOpen = false
local voteOptions = {'CLEAR', 'RAIN', 'THUNDER', 'FOGGY', 'SNOW'}
RegisterCommand('voteweather', function(source, args)
if not votingOpen then
TriggerClientEvent('chat:addMessage', source, {args = {'Weather', 'No vote is currently active.'}})
return
end
if voteCooldown[source] then
TriggerClientEvent('chat:addMessage', source, {args = {'Weather', 'You already voted this round.'}})
return
end
local choice = string.upper(args[1] or '')
local valid = false
for _, opt in ipairs(voteOptions) do
if opt == choice then valid = true break end
end
if not valid then
TriggerClientEvent('chat:addMessage', source, {
args = {'Weather', 'Options: ' .. table.concat(voteOptions, ', ')}
})
return
end
votes[choice] = (votes[choice] or 0) + 1
voteCooldown[source] = true
TriggerClientEvent('chat:addMessage', -1, {
args = {'Weather', GetPlayerName(source) .. ' voted for ' .. choice}
})
end, false)
function startWeatherVote()
votes = {}
voteCooldown = {}
votingOpen = true
TriggerClientEvent('chat:addMessage', -1, {
args = {'Weather', 'Weather vote started! Use /voteweather [type]. Options: ' .. table.concat(voteOptions, ', ')}
})
SetTimeout(60000, function()
votingOpen = false
local winner, maxVotes = 'CLEAR', 0
for weather, count in pairs(votes) do
if count > maxVotes then winner = weather; maxVotes = count end
end
transitionWeather(winner)
TriggerClientEvent('chat:addMessage', -1, {
args = {'Weather', 'Vote ended! Weather changing to: ' .. winner}
})
end)
end
Sezonluk Sistem ve Oynanış Üzerindeki Hava Durumu Etkileri
Mevsimsel bir sistem, çoğu sunucunun gözden kaçırdığı bir derinlik katmanı ekler. Oyun içi takvimi takip ederek veya gerçek dünyadaki ayları mevsimlerle eşleştirerek hava durumu olasılıklarını buna göre ağırlıklandırabilirsiniz. Yaz mevsimi ara sıra görülen gök gürültülü fırtınalarla birlikte açık ve güneşli havayı öne çıkarırken, kış mevsimi dengeyi kar, kapalı gökyüzü ve sise doğru kaydırır. Mevsimler yalnızca görsellerin ötesinde oynanış mekaniklerini de etkileyebilir. Yağmur sırasında tüm aktif araçlarda bir handling düzenleyicisi tetikleyerek araç çekişini azaltabilirsiniz. Sis, yapay zeka pedlerinin render mesafesini azaltarak gizlilik odaklı oynanışı daha uygulanabilir kılabilir. Kar, oyuncunun hareket hızını biraz yavaşlatabilir ve yavaş bir can kaybını önlemek için kışlık kıyafet gerektirebilir. Bu küçük dokunuşlar, canlı hissettiren ve çevresine tepki veren sürükleyici bir dünya yaratır.
Blackout Etkinlikleri ve Admin Kontrolleri
Blackout etkinlikleri, sunucu etkinlikleri ve rol yapma senaryoları için güçlü bir araçtır. Bu SetArtificialLightsState native, oyun dünyasındaki tüm yapay ışık kaynaklarını devre dışı bırakarak şehri karanlığa gömer. Kapalı veya sisli bir hava durumuyla birleştiğinde korku etkinlikleri, soygun senaryoları veya hayatta kalma rol yapma deneyimi için mükemmel, inanılmaz derecede atmosferik bir ortam oluşturur. Yönetici komutları hava durumu sistemi üzerinde tam kontrol sağlamalıdır: zamanı dondurma, belirli saatleri ayarlama, hava türlerini zorlama, elektrik kesintilerini tetikleme ve hava durumu oylamaları başlatma. Bu komutları ace izinleriyle koruyun, böylece ortamı yalnızca yetkili personel değiştirebilir. İyi tasarlanmış bir hava durumu sistemi, yöneticilerin sunucunuzdaki her etkinlik ve senaryo için uygun atmosferi yaratmak amacıyla kullandığı bir hikaye anlatımı aracına dönüşür.
-- Admin commands (server.lua)
RegisterCommand('setweather', function(source, args)
if source > 0 and not IsPlayerAceAllowed(source, 'command.setweather') then return end
local weather = string.upper(args[1] or 'CLEAR')
transitionWeather(weather)
TriggerClientEvent('chat:addMessage', -1, {
args = {'Admin', 'Weather changed to ' .. weather}
})
end, true)
RegisterCommand('settime', function(source, args)
if source > 0 and not IsPlayerAceAllowed(source, 'command.settime') then return end
State.hour = tonumber(args[1]) or 12
State.minute = tonumber(args[2]) or 0
TriggerClientEvent('weather:fullSync', -1, State)
end, true)
RegisterCommand('blackout', function(source, args)
if source > 0 and not IsPlayerAceAllowed(source, 'command.blackout') then return end
State.blackout = not State.blackout
TriggerClientEvent('weather:fullSync', -1, State)
TriggerClientEvent('chat:addMessage', -1, {
args = {'Admin', 'Blackout ' .. (State.blackout and 'enabled' or 'disabled')}
})
end, true)
RegisterCommand('freezetime', function(source, args)
if source > 0 and not IsPlayerAceAllowed(source, 'command.freezetime') then return end
State.frozen = not State.frozen
TriggerClientEvent('chat:addMessage', -1, {
args = {'Admin', 'Time ' .. (State.frozen and 'frozen' or 'unfrozen')}
})
end, true)