Rozdział 6.3: System pogody
Wprowadzenie
DayZ posiada w pełni dynamiczny system pogody kontrolowany przez klasę Weather. System zarządza zachmurzeniem, deszczem, opadami śniegu, mgłą, wiatrem i burzami. Pogodę można konfigurować przez skrypt (Weather API), przez cfgweather.xml w folderze misji lub przez skryptową maszynę stanów pogody. Ten rozdział obejmuje skryptowe API do odczytu i programowego sterowania pogodą.
Dostęp do obiektu Weather
Weather weather = GetGame().GetWeather();Obiekt Weather jest singletonem zarządzanym przez silnik. Jest zawsze dostępny po inicjalizacji świata gry.
Zjawiska pogodowe
Każde zjawisko pogodowe (zachmurzenie, mgła, deszcz, opady śniegu, siła wiatru, kierunek wiatru) jest reprezentowane przez obiekt WeatherPhenomenon. Dostęp do nich odbywa się przez metody getter na Weather.
Pobieranie obiektów zjawisk
proto native WeatherPhenomenon GetOvercast();
proto native WeatherPhenomenon GetFog();
proto native WeatherPhenomenon GetRain();
proto native WeatherPhenomenon GetSnowfall();
proto native WeatherPhenomenon GetWindMagnitude();
proto native WeatherPhenomenon GetWindDirection();API WeatherPhenomenon
Każde zjawisko współdzieli to samo interfejs:
class WeatherPhenomenon
{
// Aktualny stan
proto native float GetActual(); // Aktualna interpolowana wartość (0.0 - 1.0 dla większości)
proto native float GetForecast(); // Docelowa wartość do interpolacji
proto native float GetNextChange(); // Sekundy do obliczenia następnej prognozy
// Ustaw prognozę (tylko serwer)
proto native void Set(float forecast, float time = 0, float minDuration = 0);
// forecast: wartość docelowa
// time: sekundy do interpolacji do tej wartości (0 = natychmiast)
// minDuration: minimalny czas utrzymywania wartości przed automatyczną zmianą
// Limity (aktualna wartość jest zawsze utrzymywana w [fnMin, fnMax])
proto native void SetLimits(float fnMin, float fnMax);
proto void GetLimits(out float fnMin, out float fnMax);
// Limity czasu prognozy (zakres sekund, w którym obliczana jest następna prognoza; domyślnie 300-3600)
proto native void SetForecastTimeLimits(float ftMin, float ftMax);
proto void GetForecastTimeLimits(out float ftMin, out float ftMax);
// Limity zmiany prognozy (o ile wartość prognozy może się zmienić przy każdym przeliczeniu; domyślnie 0-1)
proto native void SetForecastChangeLimits(float fcMin, float fcMax);
proto void GetForecastChangeLimits(out float fcMin, out float fcMax);
}Przykład --- odczyt aktualnego stanu pogody:
Weather w = GetGame().GetWeather();
float overcast = w.GetOvercast().GetActual();
float rain = w.GetRain().GetActual();
float fog = w.GetFog().GetActual();
float snow = w.GetSnowfall().GetActual();
float windSpeed = w.GetWindMagnitude().GetActual();
float windDir = w.GetWindDirection().GetActual();
Print(string.Format("Overcast: %1, Rain: %2, Fog: %3", overcast, rain, fog));Przykład --- wymuś czystą pogodę (serwer):
void ForceClearWeather()
{
Weather w = GetGame().GetWeather();
w.GetOvercast().Set(0.0, 30, 600); // Czyste niebo, 30s przejście, utrzymaj 10 min
w.GetRain().Set(0.0, 10, 600); // Bez deszczu
w.GetFog().Set(0.0, 30, 600); // Bez mgły
w.GetSnowfall().Set(0.0, 10, 600); // Bez śniegu
}Przykład --- stwórz burzę:
void ForceStorm()
{
Weather w = GetGame().GetWeather();
w.GetOvercast().Set(1.0, 60, 1800); // Pełne zachmurzenie, 60s narastanie, utrzymaj 30 min
w.GetRain().Set(0.8, 120, 1800); // Silny deszcz
w.GetFog().Set(0.3, 120, 1800); // Lekka mgła
w.GetWindMagnitude().Set(15.0, 60, 1800); // Silny wiatr (m/s)
}Progi deszczu
Deszcz jest powiązany z poziomem zachmurzenia. Silnik renderuje deszcz tylko gdy zachmurzenie przekracza próg. Możesz to skonfigurować przez cfgweather.xml:
<rain>
<thresholds min="0.5" max="1.0" end="120" />
</rain>min/max: zakres zachmurzenia, w którym deszcz jest dozwolonyend: sekundy na zatrzymanie deszczu jeśli zachmurzenie spadnie poniżej progu
W skrypcie deszcz nie pojawi się wizualnie jeśli zachmurzenie jest zbyt niskie, nawet jeśli GetRain().GetActual() zwraca niezerową wartość.
Wiatr
Wiatr używa dwóch zjawisk: siły (prędkość w m/s) i kierunku (kąt w radianach).
Wektor wiatru
proto native vector GetWind(); // Wektor kierunku wiatru (przestrzeń świata)
proto native float GetWindSpeed(); // Prędkość wiatru w m/sPrzykład --- pobranie informacji o wietrze:
Weather w = GetGame().GetWeather();
vector windVec = w.GetWind();
float windSpd = w.GetWindSpeed();
Print(string.Format("Wind: %1 m/s, direction: %2", windSpd, windVec));Burze (błyskawice)
proto native void SetStorm(float density, float threshold, float timeout);| Parametr | Opis |
|---|---|
density | Gęstość błyskawic (0.0 - 1.0) |
threshold | Minimalny poziom zachmurzenia dla pojawienia się błyskawic (0.0 - 1.0) |
timeout | Sekundy między uderzeniami piorunów |
Przykład --- włącz częste błyskawice:
GetGame().GetWeather().SetStorm(1.0, 0.6, 10);
// Pełna gęstość, wyzwala się przy 60% zachmurzenia, uderzenia co 10 sekundKontrola MissionWeather
Aby przejąć ręczną kontrolę nad pogodą (wyłączając automatyczną maszynę stanów pogody), wywołaj:
void MissionWeather(bool use);Gdy wywołane jest MissionWeather(true), silnik zatrzymuje automatyczne przejścia pogodowe i tylko twoje skryptowe wywołania Set() kontrolują pogodę.
Przykład --- pełna ręczna kontrola w init.c:
void main()
{
// Przejmij ręczną kontrolę nad pogodą
GetGame().GetWeather().MissionWeather(true);
// Ustaw pożądaną pogodę
GetGame().GetWeather().GetOvercast().Set(0.3, 0, 0);
GetGame().GetWeather().GetRain().Set(0.0, 0, 0);
GetGame().GetWeather().GetFog().Set(0.1, 0, 0);
}Data i czas
Data i czas gry wpływają na oświetlenie, pozycję słońca i cykl dzień/noc. Są one kontrolowane przez obiekt World, nie Weather, ale są ściśle powiązane.
Pobieranie aktualnej daty/czasu
int year, month, day, hour, minute;
GetGame().GetWorld().GetDate(year, month, day, hour, minute);Ustawianie daty/czasu (tylko serwer)
proto native void SetDate(int year, int month, int day, int hour, int minute);Przykład --- ustawienie czasu na południe:
int year, month, day, hour, minute;
GetGame().GetWorld().GetDate(year, month, day, hour, minute);
GetGame().GetWorld().SetDate(year, month, day, 12, 0);Przyspieszenie czasu
Przyspieszenie czasu jest konfigurowane w serverDZ.cfg przez:
serverTimeAcceleration = 12; // 12x czas rzeczywisty
serverNightTimeAcceleration = 4; // 4x przyspieszenie w nocyW skrypcie możesz zmienić przyspieszenie czasu w trakcie działania (głównie do debugowania) za pomocą GetGame().GetWorld().SetTimeMultiplier(float timeMultiplier), gdzie timeMultiplier to wartość przyspieszenia 0-64 (lub -1, aby przywrócić wartość z konfiguracji). Nie ma skryptowego gettera dla aktualnego mnożnika.
Maszyna stanów pogody WorldData
Vanilla DayZ używa skryptowanej maszyny stanów pogody w klasach WorldData (np. ChernarusPlusData, EnochData, SakhalData). Kluczowy punkt nadpisania to:
class WorldData
{
bool WeatherOnBeforeChange(EWeatherPhenomenon type, float actual, float change,
float time);
}Nadpisz tę metodę w klasie modded WorldData, aby przechwytywać i modyfikować przejścia pogodowe:
modded class ChernarusPlusData
{
// Zwróć true, gdy skrypt modyfikuje stan zjawiska;
// zwróć false, aby silnik zastosował swoją obliczoną zmianę.
override bool WeatherOnBeforeChange(EWeatherPhenomenon type, float actual,
float change, float time)
{
// Zapobiegaj przekroczeniu 0.5 przez deszcz
if (type == EWeatherPhenomenon.RAIN && change > 0.5)
{
GetGame().GetWeather().GetRain().Set(0.5, time, 300);
return true;
}
return super.WeatherOnBeforeChange(type, actual, change, time);
}
}cfgweather.xml
Plik cfgweather.xml w folderze misji zapewnia deklaratywny sposób konfiguracji pogody bez skryptowania. Gdy jest obecny, nadpisuje domyślne parametry maszyny stanów pogody.
Kluczowa struktura:
<weather reset="0" enable="1">
<overcast>
<current actual="0.45" time="120" duration="240" />
<limits min="0.0" max="1.0" />
<timelimits min="900" max="1800" />
<changelimits min="0.0" max="1.0" />
</overcast>
<fog>...</fog>
<rain>
...
<thresholds min="0.5" max="1.0" end="120" />
</rain>
<snowfall>...</snowfall>
<windMagnitude>...</windMagnitude>
<windDirection>...</windDirection>
<storm density="1.0" threshold="0.7" timeout="25"/>
</weather>| Atrybut | Opis |
|---|---|
reset | Czy resetować pogodę z pamięci przy starcie serwera |
enable | Czy ten plik jest aktywny |
actual | Wartość początkowa |
time | Sekundy do osiągnięcia wartości początkowej |
duration | Sekundy utrzymywania wartości początkowej |
limits min/max | Zakres wartości zjawiska |
timelimits min/max | Zakres czasu trwania przejścia (sekundy) |
changelimits min/max | Zakres wielkości zmiany na przejście |
Podsumowanie
| Koncept | Kluczowy punkt |
|---|---|
| Dostęp | GetGame().GetWeather() zwraca singleton Weather |
| Zjawiska | GetOvercast(), GetRain(), GetFog(), GetSnowfall(), GetWindMagnitude(), GetWindDirection() |
| Odczyt | phenomenon.GetActual() dla aktualnej wartości (0.0 - 1.0) |
| Zapis | phenomenon.Set(prognoza, czasPrzejścia, czasUtrzymania) (tylko serwer) |
| Burze | SetStorm(gęstość, próg, limit_czasu) |
| Tryb ręczny | MissionWeather(true) wyłącza automatyczne zmiany pogody |
| Data/Czas | GetGame().GetWorld().GetDate() / SetDate() |
| Plik konfiguracji | cfgweather.xml w folderze misji dla deklaratywnej konfiguracji |
Dobre praktyki
- Wywołaj
MissionWeather(true)przed ustawianiem pogody winit.c. Bez tego automatyczna maszyna stanów pogody nadpisze twoje wywołaniaSet()w ciągu sekund. Zawsze najpierw przejmij ręczną kontrolę, jeśli chcesz deterministyczną pogodę. - Zawsze podawaj parametr
minDurationwSet(). UstawienieminDurationna 0 oznacza, że system pogody może natychmiast przejść od twojej wartości. Użyj co najmniej 300-600 sekund, aby utrzymać pożądany stan. - Ustaw zachmurzenie przed deszczem. Deszcz jest wizualnie powiązany z progami zachmurzenia. Jeśli zachmurzenie jest poniżej progu skonfigurowanego w
cfgweather.xml, deszcz nie będzie renderowany, nawet jeśliGetRain().GetActual()zwraca niezerową wartość. - Używaj
WeatherOnBeforeChange()dla ogólnoserwerowej polityki pogodowej. Nadpisz to wmodded class ChernarusPlusData(lub odpowiedniej podklasie WorldData), aby ograniczać lub przekierowywać przejścia pogodowe bez walki z maszyną stanów. - Odczytuj pogodę po obu stronach, zapisuj tylko na serwerze.
GetActual()iGetForecast()działają na kliencie i serwerze, aleSet()działa tylko na serwerze.
Kompatybilność i wpływ
Kompatybilność modów: Mody pogodowe powszechnie nadpisują
WeatherOnBeforeChange()w podklasach WorldData. Tylko jeden łańcuch nadpisań jednego moda działa dla klasy WorldData każdej mapy.
- Kolejność ładowania: Jeśli wiele modów nadpisuje
WeatherOnBeforeChangena tej samej podklasie WorldData (np.ChernarusPlusData), wszystkie muszą wywoływaćsuper, w przeciwnym razie wcześniejsze mody tracą swoją logikę pogodową. - Konflikty modded klas: Jeśli jeden mod wywołuje
MissionWeather(true), a inny oczekuje automatycznej pogody, są fundamentalnie niekompatybilne. Dokumentuj, czy twój mod przejmuje ręczną kontrolę nad pogodą. - Wpływ na wydajność: Wywołania Weather API są lekkie. Interpolacja zjawisk działa w silniku, nie w skrypcie. Częste wywołania
Set()(co klatkę) są marnotrawstwem, ale nie są szkodliwe. - Serwer/Klient: Wszystkie wywołania
Set()działają tylko na serwerze. Klienci otrzymują stan pogody przez automatyczną synchronizację silnika. WywołaniaSet()po stronie klienta są po cichu ignorowane.
Zaobserwowane w prawdziwych modach
Te wzorce zostały potwierdzone przez analizę kodu źródłowego profesjonalnych modów DayZ.
| Wzorzec | Mod | Plik/Lokalizacja |
|---|---|---|
MissionWeather(true) + skryptowany cykl pogodowy z CallLater | Expansion | Kontroler pogody w inicjalizacji misji |
Nadpisanie WeatherOnBeforeChange aby zapobiec deszczowi w określonych obszarach | COT Weather Module | Modded ChernarusPlusData |
Komenda admina do wymuszenia pogody czystej/burzowej przez Set() z długim czasem utrzymania | VPP Admin Tools | Panel administracji pogodą |
cfgweather.xml z niestandardowymi progami dla map tylko ze śniegiem | Namalsk | Konfiguracja w folderze misji |
<< Poprzedni: Pojazdy | Pogoda | Następny: Kamery >>
