CARLA
Loading...
Searching...
No Matches
WeatherJsonUtils.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
8
9#include "Dom/JsonObject.h"
10#include "HAL/FileManager.h"
11#include "JsonObjectConverter.h"
12#include "Misc/FileHelper.h"
13#include "Serialization/JsonSerializer.h"
14
15namespace
16{
17 TSharedRef<FJsonObject> LoadJsonRoot(const FString& Path)
18 {
19 FString InputString;
20 TSharedPtr<FJsonObject> Root;
21 if (FFileHelper::LoadFileToString(InputString, *Path))
22 {
23 TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(InputString);
24 FJsonSerializer::Deserialize(Reader, Root);
25 }
26 return Root.IsValid() ? Root.ToSharedRef() : MakeShared<FJsonObject>();
27 }
28
29 bool SaveJsonRoot(const TSharedRef<FJsonObject>& Root, const FString& Path)
30 {
31 FString OutputString;
32 TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&OutputString);
33 if (!FJsonSerializer::Serialize(Root, Writer))
34 return false;
35 IFileManager::Get().MakeDirectory(*FPaths::GetPath(Path), true);
36 return FFileHelper::SaveStringToFile(OutputString, *Path);
37 }
38
39 // "time" or "conditions" sub-object of the shared Presets.json, creating
40 // it if this is the first preset saved in that catalog.
41 TSharedRef<FJsonObject> GetOrCreateCatalog(const TSharedRef<FJsonObject>& Root, const TCHAR* CatalogKey)
42 {
43 const TSharedPtr<FJsonObject>* Existing = nullptr;
44 if (Root->TryGetObjectField(CatalogKey, Existing) && Existing->IsValid())
45 return Existing->ToSharedRef();
46 TSharedRef<FJsonObject> Catalog = MakeShared<FJsonObject>();
47 Root->SetObjectField(CatalogKey, Catalog);
48 return Catalog;
49 }
50
51 template <typename TPresetStruct>
52 bool SavePreset(const TPresetStruct& Preset, const FString& Name, const TCHAR* CatalogKey)
53 {
54 TSharedRef<FJsonObject> Root = LoadJsonRoot(UWeatherJsonUtils::GetPresetsPath());
55 TSharedRef<FJsonObject> Catalog = GetOrCreateCatalog(Root, CatalogKey);
56
57 TSharedPtr<FJsonObject> PresetObject = FJsonObjectConverter::UStructToJsonObject(Preset);
58 if (!PresetObject.IsValid())
59 return false;
60 Catalog->SetObjectField(Name, PresetObject);
61
62 return SaveJsonRoot(Root, UWeatherJsonUtils::GetPresetsPath());
63 }
64
65 template <typename TPresetStruct>
66 bool LoadPreset(TPresetStruct& OutPreset, const FString& Name, const TCHAR* CatalogKey)
67 {
68 TSharedRef<FJsonObject> Root = LoadJsonRoot(UWeatherJsonUtils::GetPresetsPath());
69 const TSharedPtr<FJsonObject>* Catalog = nullptr;
70 if (!Root->TryGetObjectField(CatalogKey, Catalog) || !Catalog->IsValid())
71 return false;
72
73 const TSharedPtr<FJsonObject>* PresetObject = nullptr;
74 if (!(*Catalog)->TryGetObjectField(Name, PresetObject) || !PresetObject->IsValid())
75 return false;
76
77 return FJsonObjectConverter::JsonObjectToUStruct(PresetObject->ToSharedRef(), &OutPreset);
78 }
79
80 TArray<FString> GetCatalogNames(const TCHAR* CatalogKey)
81 {
82 TArray<FString> Names;
83 TSharedRef<FJsonObject> Root = LoadJsonRoot(UWeatherJsonUtils::GetPresetsPath());
84 const TSharedPtr<FJsonObject>* Catalog = nullptr;
85 if (Root->TryGetObjectField(CatalogKey, Catalog) && Catalog->IsValid())
86 {
87 for (const auto& Pair : (*Catalog)->Values)
88 Names.Add(FString(Pair.Key));
89 }
90 Names.Sort();
91 return Names;
92 }
93}
94
95bool UWeatherJsonUtils::SaveTimePreset(const FWeatherTimePreset& Preset, const FString& Name)
96{
97 return SavePreset(Preset, Name, TEXT("time"));
98}
99
100bool UWeatherJsonUtils::LoadTimePreset(FWeatherTimePreset& OutPreset, const FString& Name)
101{
102 return LoadPreset(OutPreset, Name, TEXT("time"));
103}
104
106{
107 return SavePreset(Preset, Name, TEXT("conditions"));
108}
109
111{
112 return LoadPreset(OutPreset, Name, TEXT("conditions"));
113}
114
116{
117 return GetCatalogNames(TEXT("time"));
118}
119
121{
122 return GetCatalogNames(TEXT("conditions"));
123}
124
126 const FWeatherParameters& Base,
127 const FWeatherTimePreset& TimePreset,
128 const FWeatherConditionPreset& ConditionPreset)
129{
130 FWeatherParameters Result = Base;
131
132 Result.SunAzimuthAngle = TimePreset.SunAzimuthAngle;
133 Result.SunAltitudeAngle = TimePreset.SunAltitudeAngle;
134
135 Result.Cloudiness = ConditionPreset.Cloudiness;
136 Result.Precipitation = ConditionPreset.Precipitation;
137 Result.PrecipitationDeposits = ConditionPreset.PrecipitationDeposits;
138 Result.WindIntensity = ConditionPreset.WindIntensity;
139 Result.FogDensity = ConditionPreset.FogDensity;
140 Result.FogDistance = ConditionPreset.FogDistance;
141 Result.FogFalloff = ConditionPreset.FogFalloff;
142 Result.Wetness = ConditionPreset.Wetness;
143 Result.ScatteringIntensity = ConditionPreset.ScatteringIntensity;
144 Result.MieScatteringScale = ConditionPreset.MieScatteringScale;
145 Result.RayleighScatteringScale = ConditionPreset.RayleighScatteringScale;
146
147 return Result;
148}
149
150bool UWeatherJsonUtils::GetMapDefaultPresetNames(const FString& MapName, FString& OutTimeName, FString& OutConditionName)
151{
152 TSharedRef<FJsonObject> Root = LoadJsonRoot(GetMapDefaultsPath());
153 const TSharedPtr<FJsonObject>* MapEntry = nullptr;
154 if (!Root->TryGetObjectField(MapName, MapEntry) || !MapEntry->IsValid())
155 return false;
156
157 return (*MapEntry)->TryGetStringField(TEXT("time"), OutTimeName)
158 && (*MapEntry)->TryGetStringField(TEXT("condition"), OutConditionName);
159}
160
161bool UWeatherJsonUtils::SetMapDefaultPresetNames(const FString& MapName, const FString& TimeName, const FString& ConditionName)
162{
163 TSharedRef<FJsonObject> Root = LoadJsonRoot(GetMapDefaultsPath());
164
165 TSharedRef<FJsonObject> MapEntry = MakeShared<FJsonObject>();
166 MapEntry->SetStringField(TEXT("time"), TimeName);
167 MapEntry->SetStringField(TEXT("condition"), ConditionName);
168 Root->SetObjectField(MapName, MapEntry);
169
170 return SaveJsonRoot(Root, GetMapDefaultsPath());
171}
172
173bool UWeatherJsonUtils::GetMapDefaultWeather(const FString& MapName, const FWeatherParameters& Base, FWeatherParameters& OutWeather)
174{
175 TSharedRef<FJsonObject> Root = LoadJsonRoot(GetMapDefaultsPath());
176 const TSharedPtr<FJsonObject>* MapEntry = nullptr;
177 if (!Root->TryGetObjectField(MapName, MapEntry) || !MapEntry->IsValid())
178 return false;
179
180 FString TimeName, ConditionName;
181 const bool bIsPresetPair = (*MapEntry)->TryGetStringField(TEXT("time"), TimeName)
182 && (*MapEntry)->TryGetStringField(TEXT("condition"), ConditionName);
183 if (bIsPresetPair)
184 {
185 FWeatherTimePreset TimePreset;
186 FWeatherConditionPreset ConditionPreset;
187 if (!LoadTimePreset(TimePreset, TimeName) || !LoadConditionPreset(ConditionPreset, ConditionName))
188 return false;
189 OutWeather = MergeWeatherPresets(Base, TimePreset, ConditionPreset);
190 return true;
191 }
192
193 // Not a {time, condition} pair -- the entry itself is a full inline
194 // FWeatherParameters snapshot (see SetMapDefaultWeather). Start from Base
195 // so a future field this snapshot predates keeps Base's value instead of
196 // silently zeroing.
197 OutWeather = Base;
198 return FJsonObjectConverter::JsonObjectToUStruct((*MapEntry).ToSharedRef(), &OutWeather);
199}
200
202{
203 TSharedRef<FJsonObject> Root = LoadJsonRoot(GetMapDefaultsPath());
204
205 TSharedPtr<FJsonObject> WeatherObject = FJsonObjectConverter::UStructToJsonObject(Weather);
206 if (!WeatherObject.IsValid())
207 return false;
208 Root->SetObjectField(MapName, WeatherObject);
209
210 return SaveJsonRoot(Root, GetMapDefaultsPath());
211}
static FWeatherParameters MergeWeatherPresets(const FWeatherParameters &Base, const FWeatherTimePreset &TimePreset, const FWeatherConditionPreset &ConditionPreset)
static bool SaveConditionPreset(const FWeatherConditionPreset &Preset, const FString &Name)
static bool GetMapDefaultWeather(const FString &MapName, const FWeatherParameters &Base, UPARAM(ref) FWeatherParameters &OutWeather)
static FString GetPresetsPath()
static TArray< FString > GetAvailableConditionPresetNames()
static bool GetMapDefaultPresetNames(const FString &MapName, FString &OutTimeName, FString &OutConditionName)
static bool LoadConditionPreset(UPARAM(ref) FWeatherConditionPreset &OutPreset, const FString &Name)
static bool SaveTimePreset(const FWeatherTimePreset &Preset, const FString &Name)
static bool SetMapDefaultWeather(const FString &MapName, const FWeatherParameters &Weather)
static TArray< FString > GetAvailableTimePresetNames()
static FString GetMapDefaultsPath()
static bool LoadTimePreset(UPARAM(ref) FWeatherTimePreset &OutPreset, const FString &Name)
static bool SetMapDefaultPresetNames(const FString &MapName, const FString &TimeName, const FString &ConditionName)