Add regional temperature curve

This commit is contained in:
2026-05-15 21:53:10 -07:00
parent 8ee1f83b16
commit ca2c3ee3db
5 changed files with 172 additions and 5 deletions
+76 -4
View File
@@ -25,6 +25,16 @@ bool IsDayInRange(int32 DayOfYear, int32 StartDay, int32 EndDay, int32 DaysPerYe
return Day >= Start || Day <= End;
}
float GetWrappedHourDelta(float FromHour, float ToHour)
{
float Delta = FMath::Fmod(ToHour - FromHour, 24.0f);
if (Delta < 0.0f)
{
Delta += 24.0f;
}
return Delta;
}
}
AAgrarianGameState::AAgrarianGameState()
@@ -82,6 +92,12 @@ void AAgrarianGameState::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& O
DOREPLIFETIME(AAgrarianGameState, WorldHours);
DOREPLIFETIME(AAgrarianGameState, Weather);
DOREPLIFETIME(AAgrarianGameState, AmbientTemperatureC);
DOREPLIFETIME(AAgrarianGameState, RegionalDailyLowTemperatureC);
DOREPLIFETIME(AAgrarianGameState, RegionalDailyHighTemperatureC);
DOREPLIFETIME(AAgrarianGameState, RegionalObservedTemperatureC);
DOREPLIFETIME(AAgrarianGameState, ObservedTemperatureBlend);
DOREPLIFETIME(AAgrarianGameState, bHasRegionalObservedTemperature);
DOREPLIFETIME(AAgrarianGameState, RegionalWeatherSource);
DOREPLIFETIME(AAgrarianGameState, DaysPerAgrarianYear);
DOREPLIFETIME(AAgrarianGameState, ActiveSolarTileId);
DOREPLIFETIME(AAgrarianGameState, ActiveTileLatitude);
@@ -118,6 +134,56 @@ void AAgrarianGameState::SetWeather(EAgrarianWeatherType NewWeather)
}
}
void AAgrarianGameState::SetRegionalTemperatureProfile(float DailyLowTemperatureC, float DailyHighTemperatureC)
{
if (!HasAuthority())
{
return;
}
RegionalDailyLowTemperatureC = FMath::Clamp(FMath::Min(DailyLowTemperatureC, DailyHighTemperatureC), -80.0f, 70.0f);
RegionalDailyHighTemperatureC = FMath::Clamp(FMath::Max(DailyLowTemperatureC, DailyHighTemperatureC), -80.0f, 70.0f);
UpdateAmbientTemperature();
}
void AAgrarianGameState::SetRegionalObservedTemperature(float ObservedTemperatureC, float BlendWeight, const FString& WeatherSource)
{
if (!HasAuthority())
{
return;
}
RegionalObservedTemperatureC = FMath::Clamp(ObservedTemperatureC, -80.0f, 70.0f);
ObservedTemperatureBlend = FMath::Clamp(BlendWeight, 0.0f, 1.0f);
bHasRegionalObservedTemperature = ObservedTemperatureBlend > 0.0f;
RegionalWeatherSource = WeatherSource.IsEmpty() ? TEXT("server_weather_adapter") : WeatherSource;
UpdateAmbientTemperature();
}
float AAgrarianGameState::GetClearSkyTemperatureForHour(float HourOfDay) const
{
const float LowTemperature = FMath::Min(RegionalDailyLowTemperatureC, RegionalDailyHighTemperatureC);
const float HighTemperature = FMath::Max(RegionalDailyLowTemperatureC, RegionalDailyHighTemperatureC);
const float LowHour = bHasActiveTileSolarData ? SunriseHourLocal : 6.0f;
const float HighHour = bHasActiveTileSolarData ? FMath::Fmod(SolarNoonHourLocal + 3.0f, 24.0f) : 14.0f;
const float NormalizedHour = FMath::Fmod(HourOfDay, 24.0f) < 0.0f
? FMath::Fmod(HourOfDay, 24.0f) + 24.0f
: FMath::Fmod(HourOfDay, 24.0f);
const float RisingDuration = FMath::Max(0.1f, GetWrappedHourDelta(LowHour, HighHour));
const float HoursSinceLow = GetWrappedHourDelta(LowHour, NormalizedHour);
if (HoursSinceLow <= RisingDuration)
{
const float Alpha = 0.5f - (0.5f * FMath::Cos(PI * (HoursSinceLow / RisingDuration)));
return FMath::Lerp(LowTemperature, HighTemperature, Alpha);
}
const float CoolingDuration = FMath::Max(0.1f, 24.0f - RisingDuration);
const float HoursSinceHigh = GetWrappedHourDelta(HighHour, NormalizedHour);
const float Alpha = 0.5f - (0.5f * FMath::Cos(PI * (HoursSinceHigh / CoolingDuration)));
return FMath::Lerp(HighTemperature, LowTemperature, Alpha);
}
bool AAgrarianGameState::ConfigureActiveSolarTile(FName TileId, float Latitude, float Longitude, const FString& TimeZoneId, float UtcOffsetHours)
{
if (!HasAuthority() || TileId == NAME_None)
@@ -380,14 +446,20 @@ void AAgrarianGameState::UpdateSolarTimes()
void AAgrarianGameState::UpdateAmbientTemperature()
{
const float WarmestHour = bHasActiveTileSolarData ? FMath::Fmod(SolarNoonHourLocal + 3.0f, 24.0f) : 14.0f;
const float DayWarmth = FMath::Sin(((WorldHours - WarmestHour) / 24.0f) * 2.0f * PI + (PI * 0.5f)) * 8.0f;
const float ClearSkyTemperatureC = GetClearSkyTemperatureForHour(WorldHours);
const float DailyMeanTemperatureC = (RegionalDailyLowTemperatureC + RegionalDailyHighTemperatureC) * 0.5f;
const float ObservedAnchoredTemperatureC = bHasRegionalObservedTemperature
? RegionalObservedTemperatureC + (ClearSkyTemperatureC - DailyMeanTemperatureC)
: ClearSkyTemperatureC;
const float BaseTemperatureC = bHasRegionalObservedTemperature
? FMath::Lerp(ClearSkyTemperatureC, ObservedAnchoredTemperatureC, ObservedTemperatureBlend)
: ClearSkyTemperatureC;
float WeatherModifier = 0.0f;
switch (Weather)
{
case EAgrarianWeatherType::Rain:
WeatherModifier = -3.0f;
WeatherModifier = -2.0f;
break;
case EAgrarianWeatherType::ColdWind:
WeatherModifier = -8.0f;
@@ -400,5 +472,5 @@ void AAgrarianGameState::UpdateAmbientTemperature()
break;
}
AmbientTemperatureC = 10.0f + DayWarmth + WeatherModifier;
AmbientTemperatureC = FMath::Clamp(BaseTemperatureC + WeatherModifier, -80.0f, 70.0f);
}
+27
View File
@@ -34,6 +34,24 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Replicated, Category = "Agrarian|World")
float AmbientTemperatureC = 12.0f;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Replicated, Category = "Agrarian|World|Temperature")
float RegionalDailyLowTemperatureC = 9.0f;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Replicated, Category = "Agrarian|World|Temperature")
float RegionalDailyHighTemperatureC = 18.0f;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Replicated, Category = "Agrarian|World|Temperature")
float RegionalObservedTemperatureC = 12.0f;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Replicated, Category = "Agrarian|World|Temperature", meta = (ClampMin = "0.0", ClampMax = "1.0"))
float ObservedTemperatureBlend = 0.0f;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Replicated, Category = "Agrarian|World|Temperature")
bool bHasRegionalObservedTemperature = false;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Replicated, Category = "Agrarian|World|Temperature")
FString RegionalWeatherSource = TEXT("deterministic_tile_curve");
UPROPERTY(EditAnywhere, BlueprintReadOnly, Replicated, Category = "Agrarian|World|Tile Solar")
FName ActiveSolarTileId = TEXT("gz_us_ca_pacifica_utm10n_e544_n4160");
@@ -79,6 +97,15 @@ public:
UFUNCTION(BlueprintCallable, Category = "Agrarian|World")
void SetWeather(EAgrarianWeatherType NewWeather);
UFUNCTION(BlueprintCallable, Category = "Agrarian|World|Temperature")
void SetRegionalTemperatureProfile(float DailyLowTemperatureC, float DailyHighTemperatureC);
UFUNCTION(BlueprintCallable, Category = "Agrarian|World|Temperature")
void SetRegionalObservedTemperature(float ObservedTemperatureC, float BlendWeight, const FString& WeatherSource);
UFUNCTION(BlueprintPure, Category = "Agrarian|World|Temperature")
float GetClearSkyTemperatureForHour(float HourOfDay) const;
UFUNCTION(BlueprintCallable, Category = "Agrarian|World|Tile Solar")
bool ConfigureActiveSolarTile(FName TileId, float Latitude, float Longitude, const FString& TimeZoneId, float UtcOffsetHours);