مزامنة الطقس FiveM: سكريبتات الطقس والوقت الديناميكية
مزامنة الطقس والوقت عبر خادم FiveM الخاص بك. دورات ديناميكية، رعد، ثلج، حزم المواسم وأفضل سكربتات الطقس لضبط الأجواء.
Agency Scripts
المؤسس والمطور الرئيسي في Agency Scripts
المشكلة مع الطقس غير المتزامن
بشكل افتراضي، يتعامل GTA V مع الطقس والوقت بشكل مستقل على كل عميل. هذا يعني أن لاعبًا واحدًا يمكن أن يقود في ضوء الشمس الساطع بينما يرى لاعب آخر يقف بجانبه عاصفة رعدية. بالنسبة لخوادم اللعب التمثيلي، هذا يكسر الانغماس تمامًا. تخيل محاولة تنسيق مشهد حيث يشتكي شخصية من المطر بينما تظهر شاشة لاعب آخر سماء صافية. يضمن نظام مزامنة الطقس والوقت أن يختبر كل لاعب على الخادم نفس البيئة في نفس اللحظة، وهو أمر أساسي للعب تمثيلي متسق، وظروف قيادة واقعية، وتنسيق الفعاليات. في هذا الدرس، سنبني نظام مزامنة طقس كامل مع سرعة وقت قابلة للتكوين، انتقالات موسمية، تصويت على الطقس، وأحداث انقطاع التيار.
إدارة حالة الطقس على جانب الخادم
الخادم هو المصدر الوحيد للحقيقة للطقس والوقت. يحتفظ بنوع الطقس الحالي، نوع الطقس التالي للانتقالات، والساعة داخل اللعبة. يتزامن كل عميل مع هذه الحالة عند الانضمام ويتلقى تحديثات كلما تغير الطقس. تدعم GTA V مجموعة محددة من أنواع الطقس بما في ذلك CLEAR, EXTRASUNNY, CLOUDS, OVERCAST, RAIN, THUNDER, CLEARING, FOGGY, SMOG, SNOW, SNOWLIGHT, BLIZZARD، و XMAS. عرّف قواعد انتقال منطقية حتى يتدفق الطقس بشكل طبيعي بدلاً من القفز من عاصفة ثلجية إلى مشمس جداً بدون حالة وسيطة.
-- 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},
}
تقدم الوقت ودورة التزامن
يعمل نظام الوقت كحلقة على جانب الخادم تزيد الساعة داخل اللعبة بناءً على السرعة المكونة. timeSpeed تعني 2 أن كل ثانية حقيقية تتقدم ساعة اللعبة بمقدار دقيقتين. هذا يخلق دورة ليل ونهار تستغرق حوالي 12 دقيقة حقيقية لساعات اللعبة الـ24 كاملة. يبث الخادم الوقت الحالي وحالة الطقس لجميع العملاء على فترات منتظمة ويدفع تحديثات فورية عندما يغير المسؤول الطقس أو يطلق حدث انقطاع التيار. اللاعبون الجدد الذين ينضمون في منتصف الجلسة يتلقون الحالة الحالية من خلال حدث تزامن مخصص ليطابقوا الجميع فورًا.
-- 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)
تطبيق الطقس على جانب العميل
على العميل، تحتاج إلى تجاوز أنظمة الطقس والوقت الأصلية في GTA. الوظائف الأساسية هي SetWeatherTypeNowPersist لتغييرات الطقس الفورية، SetWeatherTypeTransition لدمج سلس بين حالتين من الطقس، و NetworkOverrideClockTime لتعيين ساعة اللعبة. يجب عليك استدعاء NetworkOverrideClockTime كل إطار لمنع اللعبة من العودة إلى حساب الوقت الخاص بها. بالنسبة لانتقالات الطقس، تدعم GTA عامل دمج بين 0.0 و1.0 يسمح لك بالتداخل السلس بين حالتي طقس خلال عدة ثوانٍ، مما يخلق انتقالات واقعية حيث تتدحرج السحب تدريجيًا قبل بدء المطر.
-- 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)
نظام تصويت الطقس
نظام تصويت على الطقس يتيح لمجتمعك تحديد الطقس ديمقراطيًا. يمكن للاعبين الإدلاء بصوتهم لنوع الطقس المفضل لديهم، وبعد فترة التصويت يفوز الخيار الأكثر شعبية. يعمل هذا جيدًا للأحداث حيث تريد مشاركة اللاعبين، مثل تحديد ما إذا كان لقاء السيارات يحدث تحت سماء صافية أو عواصف درامية. حدد التصويت مرة واحدة لكل دورة لمنع الرسائل المزعجة، وعرض عدد الأصوات الحالي من خلال نظام الإشعارات أو طبقة NUI بسيطة. يجمع السيرفر الأصوات، يحصيها عند انتهاء الفترة، ويطبق الطقس الفائز من خلال انتقال سلس حتى يختبر جميع اللاعبين التغيير في نفس الوقت.
-- 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
نظام موسمي وتأثيرات الطقس على طريقة اللعب
يضيف نظام المواسم طبقة من العمق يغفل عنها معظم الخوادم. من خلال تتبع التقويم داخل اللعبة أو مطابقة الأشهر الواقعية مع الفصول، يمكنك وزن احتمالات الطقس وفقاً لذلك. يفضل الصيف الطقس الصافي والمشمس مع عواصف رعدية عرضية، بينما يحول الشتاء التوازن نحو الثلج، السماء الغائمة، والضباب. يمكن أن تؤثر الفصول أيضاً على آليات اللعب بخلاف المرئيات فقط. أثناء المطر، يمكنك تقليل تماسك المركبات من خلال تفعيل معدل تعديل التعامل على جميع المركبات النشطة. يمكن أن يقلل الضباب من مسافة العرض لشخصيات AI، مما يجعل اللعب الخفي أكثر جدوى. يمكن أن يبطئ الثلج سرعة حركة اللاعب قليلاً ويتطلب ملابس شتوية لتجنب استنزاف الصحة البطيء. تخلق هذه اللمسات الصغيرة عالماً غامراً يشعر بالحياة والاستجابة لبيئته.
أحداث انقطاع التيار الكهربائي وأدوات الإدارة
أحداث انقطاع التيار هي أداة قوية لأحداث الخادم وسيناريوهات لعب الأدوار. الـ SetArtificialLightsState native يعطل جميع مصادر الضوء الاصطناعي في عالم اللعبة، مما يغمر المدينة في الظلام. مع حالة الطقس الغائم أو الضبابي، يخلق هذا بيئة جوية مثالية لأحداث الرعب، سيناريوهات السطو، أو لعب الأدوار في البقاء. يجب أن توفر أوامر الإدارة تحكمًا كاملاً في نظام الطقس: تجميد الوقت، تعيين ساعات محددة، فرض أنواع الطقس، تفعيل انقطاعات التيار، وبدء تصويتات الطقس. احمِ هذه الأوامر بأذونات ace بحيث يمكن فقط للموظفين المخولين تعديل البيئة. يصبح نظام الطقس المصمم جيدًا أداة سرد يستخدمها المسؤولون لضبط المزاج لكل حدث وسيناريو على خادمك.
-- 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)