Skip to content

Kapitola 6.3: Systém počasí ​


Úvod ​

DayZ má plně dynamický systém počasí řízený prostřednictvím třídy Weather. Systém spravuje oblačnost, déšť, sněžení, mlhu, vítr a bouřky. Počasí lze konfigurovat prostřednictvím skriptu (Weather API), prostřednictvím cfgweather.xml ve složce mise, nebo prostřednictvím skriptovaného stavového automatu počasí. Tato kapitola pokrývá skriptové API pro čtení a programové řízení počasí.


Přístup k objektu Weather ​

c
Weather weather = GetGame().GetWeather();

Objekt Weather je singleton spravovaný enginem. Je vždy dostupný po inicializaci herního světa.


Meteorologické jevy ​

Každý meteorologický jev (oblačnost, mlha, déšť, sněžení, síla větru, směr větru) je reprezentován objektem WeatherPhenomenon. Přistupujete k nim prostřednictvím getter metod na Weather.

Získání objektů jevů ​

c
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ždý jev sdílí stejné rozhraní:

c
class WeatherPhenomenon
{
    // Aktuální stav
    proto native float GetActual();          // Aktuální interpolovaná hodnota (0.0 - 1.0 pro většinu)
    proto native float GetForecast();        // Cílová hodnota k interpolaci
    proto native float GetNextChange();      // Sekundy do výpočtu další předpovědi

    // Nastavit předpověď (pouze server)
    proto native void Set(float forecast, float time = 0, float minDuration = 0);
    // forecast: cílová hodnota
    // time:     sekundy pro interpolaci k této hodnotě (0 = okamžitě)
    // minDuration: minimální doba, po kterou hodnota drží před automatickou změnou

    // Limity (aktuální hodnota je vždy držena v [fnMin, fnMax])
    proto native void SetLimits(float fnMin, float fnMax);
    proto void        GetLimits(out float fnMin, out float fnMax);

    // Limity času předpovědi (rozsah sekund, ve kterém se počítá další předpověď; výchozí 300-3600)
    proto native void SetForecastTimeLimits(float ftMin, float ftMax);
    proto void        GetForecastTimeLimits(out float ftMin, out float ftMax);

    // Limity změny předpovědi (o kolik se hodnota předpovědi může změnit při každém přepočtu; výchozí 0-1)
    proto native void SetForecastChangeLimits(float fcMin, float fcMax);
    proto void        GetForecastChangeLimits(out float fcMin, out float fcMax);
}

Příklad --- čtení aktuálního stavu počasí:

c
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));

Příklad --- vynutit jasné počasí (server):

c
void ForceClearWeather()
{
    Weather w = GetGame().GetWeather();
    w.GetOvercast().Set(0.0, 30, 600);    // Jasná obloha, 30s přechod, držet 10 min
    w.GetRain().Set(0.0, 10, 600);        // Bez deště
    w.GetFog().Set(0.0, 30, 600);         // Bez mlhy
    w.GetSnowfall().Set(0.0, 10, 600);    // Bez sněhu
}

Příklad --- vytvořit bouři:

c
void ForceStorm()
{
    Weather w = GetGame().GetWeather();
    w.GetOvercast().Set(1.0, 60, 1800);   // Plná oblačnost, 60s nárůst, držet 30 min
    w.GetRain().Set(0.8, 120, 1800);      // Silný déšť
    w.GetFog().Set(0.3, 120, 1800);       // Lehká mlha
    w.GetWindMagnitude().Set(15.0, 60, 1800);  // Silný vítr (m/s)
}

Prahy deště ​

Déšť je vázán na úrovně oblačnosti. Engine vykresluje déšť pouze když oblačnost překročí práh. To můžete konfigurovat přes cfgweather.xml:

xml
<rain>
    <thresholds min="0.5" max="1.0" end="120" />
</rain>
  • min / max: rozsah oblačnosti, kde je déšť povolen
  • end: sekundy pro zastavení deště, pokud oblačnost klesne pod práh

Ve skriptu se déšť vizuálně neobjeví, pokud je oblačnost příliš nízká, i když GetRain().GetActual() vrací nenulovou hodnotu.


Vítr ​

Vítr používá dva jevy: sílu (rychlost v m/s) a směr (úhel v radiánech).

Vektor větru ​

c
proto native vector GetWind();           // Vektor směru větru (světový prostor)
proto native float  GetWindSpeed();      // Rychlost větru v m/s

Příklad --- získat informace o větru:

c
Weather w = GetGame().GetWeather();
vector windVec = w.GetWind();
float windSpd = w.GetWindSpeed();
Print(string.Format("Wind: %1 m/s, direction: %2", windSpd, windVec));

Bouřky (blesky) ​

c
proto native void SetStorm(float density, float threshold, float timeout);
ParametrPopis
densityHustota blesků (0.0 - 1.0)
thresholdMinimální úroveň oblačnosti pro výskyt blesků (0.0 - 1.0)
timeoutSekundy mezi údery blesků

Příklad --- povolit časté blesky:

c
GetGame().GetWeather().SetStorm(1.0, 0.6, 10);
// Plná hustota, spouští se při 60% oblačnosti, údery každých 10 sekund

Řízení MissionWeather ​

Pro převzetí manuální kontroly nad počasím (vypnutí automatického stavového automatu počasí) volejte:

c
void MissionWeather(bool use);

Při zavolání MissionWeather(true) engine zastaví automatické přechody počasí a pouze vaše skriptové volání Set() řídí počasí.

Příklad --- plná manuální kontrola v init.c:

c
void main()
{
    // Převzít manuální kontrolu nad počasím
    GetGame().GetWeather().MissionWeather(true);

    // Nastavit požadované počasí
    GetGame().GetWeather().GetOvercast().Set(0.3, 0, 0);
    GetGame().GetWeather().GetRain().Set(0.0, 0, 0);
    GetGame().GetWeather().GetFog().Set(0.1, 0, 0);
}

Datum a čas ​

Herní datum a čas ovlivňují osvětlení, pozici slunce a cyklus den/noc. Tyto jsou řízeny prostřednictvím objektu World, ne Weather, ale úzce s ním souvisí.

Získání aktuálního data/času ​

c
int year, month, day, hour, minute;
GetGame().GetWorld().GetDate(year, month, day, hour, minute);

Nastavení data/času (pouze server) ​

c
proto native void SetDate(int year, int month, int day, int hour, int minute);

Příklad --- nastavit čas na poledne:

c
int year, month, day, hour, minute;
GetGame().GetWorld().GetDate(year, month, day, hour, minute);
GetGame().GetWorld().SetDate(year, month, day, 12, 0);

Zrychlení času ​

Zrychlení času je konfigurováno v serverDZ.cfg přes:

serverTimeAcceleration = 12;      // 12x reálný čas
serverNightTimeAcceleration = 4;  // 4x zrychlení během noci

Ve skriptu můžete změnit zrychlení času za běhu (většinou pro ladění) pomocí GetGame().GetWorld().SetTimeMultiplier(float timeMultiplier), kde timeMultiplier je hodnota zrychlení 0-64 (nebo -1 pro reset zpět na hodnotu z konfigurace). Pro aktuální multiplikátor neexistuje skriptový getter.


Stavový automat počasí WorldData ​

Vanilla DayZ používá skriptovaný stavový automat počasí ve třídách WorldData (např. ChernarusPlusData, EnochData, SakhalData). Klíčový bod pro přepsání je:

c
class WorldData
{
    bool WeatherOnBeforeChange(EWeatherPhenomenon type, float actual, float change,
                                float time);
}

Přepište tuto metodu ve třídě modded WorldData pro zachycení a úpravu přechodů počasí:

c
modded class ChernarusPlusData
{
    // Vraťte true, když skript upraví stav jevu;
    // vraťte false, aby engine použil svou vypočtenou změnu.
    override bool WeatherOnBeforeChange(EWeatherPhenomenon type, float actual,
                                         float change, float time)
    {
        // Zabránit dešti v překročení 0.5
        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 ​

Soubor cfgweather.xml ve složce mise poskytuje deklarativní způsob konfigurace počasí bez skriptování. Pokud je přítomen, přepíše výchozí parametry stavového automatu počasí.

Klíčová struktura:

xml
<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>
AtributPopis
resetZda resetovat počasí z úložiště při startu serveru
enableZda je tento soubor aktivní
actualPočáteční hodnota
timeSekundy pro dosažení počáteční hodnoty
durationSekundy, po které počáteční hodnota drží
limits min/maxRozsah pro hodnotu jevu
timelimits min/maxRozsah pro dobu trvání přechodu (sekundy)
changelimits min/maxRozsah pro velikost změny za přechod

Shrnutí ​

KonceptKlíčový bod
PřístupGetGame().GetWeather() vrací singleton Weather
JevyGetOvercast(), GetRain(), GetFog(), GetSnowfall(), GetWindMagnitude(), GetWindDirection()
Čteníphenomenon.GetActual() pro aktuální hodnotu (0.0 - 1.0)
Zápisphenomenon.Set(předpověď, časPřechodu, dobaDržení) (pouze server)
BouřkySetStorm(hustota, práh, časový limit)
Manuální režimMissionWeather(true) vypne automatické změny počasí
Datum/ČasGetGame().GetWorld().GetDate() / SetDate()
Konfigurační souborcfgweather.xml ve složce mise pro deklarativní nastavení

Osvědčené postupy ​

  • Volejte MissionWeather(true) před nastavením počasí v init.c. Bez toho automatický stavový automat počasí přepíše vaše volání Set() během sekund. Vždy nejdříve převezměte manuální kontrolu, pokud chcete deterministické počasí.
  • Vždy zadávejte parametr minDuration v Set(). Nastavení minDuration na 0 znamená, že systém počasí může okamžitě přejít od vaší hodnoty. Použijte alespoň 300-600 sekund pro udržení požadovaného stavu.
  • Nastavte oblačnost před deštěm. Déšť je vizuálně vázán na prahy oblačnosti. Pokud je oblačnost pod prahem konfigurovaným v cfgweather.xml, déšť se nevykreslí, i když GetRain().GetActual() vrací nenulovou hodnotu.
  • Používejte WeatherOnBeforeChange() pro celoserverovou politiku počasí. Přepište to ve třídě modded class ChernarusPlusData (nebo příslušné podtřídě WorldData) pro omezení nebo přesměrování přechodů počasí bez boje se stavovým automatem.
  • Čtěte počasí na obou stranách, zapisujte pouze na serveru. GetActual() a GetForecast() fungují na klientovi i serveru, ale Set() má efekt pouze na serveru.

Kompatibilita a dopad ​

Kompatibilita modů: Mody počasí běžně přepisují WeatherOnBeforeChange() v podtřídách WorldData. Pouze jeden řetězec přepsání jednoho modu běží pro každou třídu WorldData příslušné mapy.

  • Pořadí načítání: Pokud více modů přepisuje WeatherOnBeforeChange na stejné podtřídě WorldData (např. ChernarusPlusData), všechny musí volat super, jinak dřívější mody ztratí svou logiku počasí.
  • Konflikty modded tříd: Pokud jeden mod volá MissionWeather(true) a druhý očekává automatické počasí, jsou zásadně nekompatibilní. Dokumentujte, zda váš mod přebírá manuální kontrolu nad počasím.
  • Dopad na výkon: Volání Weather API jsou lehká. Interpolace jevů běží v enginu, ne ve skriptu. Časté volání Set() (každý snímek) je plýtvání, ale neškodí.
  • Server/Klient: Všechna volání Set() jsou pouze serverová. Klienti přijímají stav počasí prostřednictvím automatické synchronizace enginu. Klientská volání Set() jsou tiše ignorována.

Pozorováno v reálných modech ​

Tyto vzory byly potvrzeny studiem zdrojového kódu profesionálních DayZ modů.

VzorModSoubor/Umístění
MissionWeather(true) + skriptovaný cyklus počasí s CallLaterExpansionKontroler počasí v inicializaci mise
Přepsání WeatherOnBeforeChange pro zabránění deště v konkrétních oblastechCOT Weather ModuleModded ChernarusPlusData
Admin příkaz pro vynucení jasna/bouře přes Set() s dlouhou dobou drženíVPP Admin ToolsPanel správy počasí
cfgweather.xml s vlastními prahy pro mapy pouze se sněhemNamalskKonfigurace ve složce mise

<< Předchozí: Vozidla | Počasí | Další: Kamery >>

Released under CC BY-SA 4.0 | Code examples under MIT License