Bloga Geri Dön
Tutorial7 dk. okuma

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)

Başlamaya Hazır mısınız?

Scriptleri mağazamızdan edinin veya destek, güncellemeler ve gelecek yeniliklere göz atmak için Discord'a katılın.