Cache real weather snapshots server side

This commit is contained in:
2026-05-15 23:34:29 -07:00
parent 5a90d532e2
commit 8ae5ecb3b0
5 changed files with 161 additions and 1 deletions
@@ -35,6 +35,12 @@ bool UAgrarianWeatherProviderSubsystem::RequestWeatherForTile(FName TileId, floa
return false;
}
AAgrarianGameState* GameState = World->GetGameState<AAgrarianGameState>();
if (TryApplyCachedSnapshot(TileId, TEXT("open-meteo"), GameState))
{
return true;
}
const FString Url = BuildOpenMeteoForecastUrl(TileId, Latitude, Longitude);
TSharedRef<IHttpRequest, ESPMode::ThreadSafe> Request = FHttpModule::Get().CreateRequest();
Request->SetURL(Url);
@@ -69,6 +75,12 @@ bool UAgrarianWeatherProviderSubsystem::RequestNoaaNwsFallbackForTile(FName Tile
return false;
}
AAgrarianGameState* GameState = World->GetGameState<AAgrarianGameState>();
if (TryApplyCachedSnapshot(TileId, TEXT("noaa-nws"), GameState))
{
return true;
}
TSharedRef<IHttpRequest, ESPMode::ThreadSafe> Request = FHttpModule::Get().CreateRequest();
Request->SetURL(BuildNoaaNwsPointsUrl(Latitude, Longitude));
Request->SetVerb(TEXT("GET"));
@@ -108,6 +120,34 @@ bool UAgrarianWeatherProviderSubsystem::ApplySnapshotToGameState(const FAgrarian
return true;
}
bool UAgrarianWeatherProviderSubsystem::TryApplyCachedSnapshot(FName TileId, const FString& Provider, AAgrarianGameState* GameState)
{
if (!GameState || !GameState->HasAuthority())
{
return false;
}
const FAgrarianCachedWeatherSnapshot* CachedSnapshot = ServerWeatherSnapshotCache.Find(MakeCacheKey(TileId, Provider));
if (!CachedSnapshot || !CachedSnapshot->IsFresh(FDateTime::UtcNow()))
{
return false;
}
LastSnapshot = CachedSnapshot->Snapshot;
return ApplySnapshotToGameState(CachedSnapshot->Snapshot, GameState);
}
bool UAgrarianWeatherProviderSubsystem::HasFreshCachedSnapshot(FName TileId, const FString& Provider) const
{
const FAgrarianCachedWeatherSnapshot* CachedSnapshot = ServerWeatherSnapshotCache.Find(MakeCacheKey(TileId, Provider));
return CachedSnapshot && CachedSnapshot->IsFresh(FDateTime::UtcNow());
}
void UAgrarianWeatherProviderSubsystem::ClearWeatherSnapshotCache()
{
ServerWeatherSnapshotCache.Empty();
}
EAgrarianWeatherType UAgrarianWeatherProviderSubsystem::MapOpenMeteoWeatherCode(int32 WeatherCode, float PrecipitationMm, float WindSpeedKmh)
{
if (WeatherCode >= 95 || WindSpeedKmh >= 55.0f)
@@ -129,6 +169,25 @@ EAgrarianWeatherType UAgrarianWeatherProviderSubsystem::MapOpenMeteoWeatherCode(
return EAgrarianWeatherType::Clear;
}
FString UAgrarianWeatherProviderSubsystem::MakeCacheKey(FName TileId, const FString& Provider) const
{
return FString::Printf(TEXT("%s:%s"), *Provider.ToLower(), *TileId.ToString());
}
void UAgrarianWeatherProviderSubsystem::CacheSnapshot(const FAgrarianWeatherProviderSnapshot& Snapshot, float TimeToLiveSeconds)
{
if (!Snapshot.bIsValid || Snapshot.TileId == NAME_None || Snapshot.Provider.IsEmpty())
{
return;
}
FAgrarianCachedWeatherSnapshot CachedSnapshot;
CachedSnapshot.Snapshot = Snapshot;
CachedSnapshot.CachedAtUtc = FDateTime::UtcNow();
CachedSnapshot.TimeToLiveSeconds = FMath::Max(60.0f, TimeToLiveSeconds);
ServerWeatherSnapshotCache.Add(MakeCacheKey(Snapshot.TileId, Snapshot.Provider), CachedSnapshot);
}
void UAgrarianWeatherProviderSubsystem::OnOpenMeteoResponse(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful, FName TileId, float Latitude, float Longitude)
{
if (!bWasSuccessful || !Response.IsValid() || Response->GetResponseCode() < 200 || Response->GetResponseCode() >= 300)
@@ -143,6 +202,7 @@ void UAgrarianWeatherProviderSubsystem::OnOpenMeteoResponse(FHttpRequestPtr Requ
}
LastSnapshot = Snapshot;
CacheSnapshot(Snapshot, WeatherSnapshotCacheTtlSeconds);
UWorld* World = GetWorld();
AAgrarianGameState* GameState = World ? World->GetGameState<AAgrarianGameState>() : nullptr;
@@ -200,6 +260,7 @@ void UAgrarianWeatherProviderSubsystem::OnNoaaNwsGridDataResponse(FHttpRequestPt
}
LastSnapshot = Snapshot;
CacheSnapshot(Snapshot, WeatherSnapshotCacheTtlSeconds);
UWorld* World = GetWorld();
AAgrarianGameState* GameState = World ? World->GetGameState<AAgrarianGameState>() : nullptr;