#31 Add methods for saving and loading weather presets to config file
This commit is contained in:
parent
4d400256d8
commit
b546d86e6b
|
@ -3,8 +3,54 @@
|
|||
#include "Carla.h"
|
||||
#include "DynamicWeather.h"
|
||||
|
||||
#include "IniFile.h"
|
||||
|
||||
#include "Components/ArrowComponent.h"
|
||||
|
||||
static bool GetWeatherIniFileName(FString &FileName)
|
||||
{
|
||||
FileName = FPaths::Combine(FPaths::GameConfigDir(), TEXT("CarlaWeather.ini"));
|
||||
const bool bFileExists = FPaths::FileExists(FileName);
|
||||
if (!bFileExists) {
|
||||
UE_LOG(LogCarla, Error, TEXT("\"%s\" no such file"), *FileName);
|
||||
}
|
||||
return bFileExists;
|
||||
}
|
||||
|
||||
static bool CheckWeatherValidity(const FWeatherDescription &Weather)
|
||||
{
|
||||
if (Weather.Name.IsEmpty()) {
|
||||
UE_LOG(LogCarla, Error, TEXT("Weather doesn't have a name, please provide one"));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
TArray<FWeatherDescription> ADynamicWeather::LoadWeatherDescriptionsFromFile()
|
||||
{
|
||||
TArray<FWeatherDescription> Descriptions;
|
||||
|
||||
// Try to load config file.
|
||||
FString FileName;
|
||||
if (GetWeatherIniFileName(FileName)) {
|
||||
IniFile ConfigFile(FileName);
|
||||
|
||||
// For every section in the config file add a weather description.
|
||||
for (auto &Item : ConfigFile.GetFConfigFile()) {
|
||||
Descriptions.AddDefaulted(1u);
|
||||
Descriptions.Last().ReadFromConfigFile(ConfigFile, Item.Key);
|
||||
}
|
||||
}
|
||||
|
||||
// If no description was found, append a defaulted one.
|
||||
if (Descriptions.Num() == 0) {
|
||||
UE_LOG(LogCarla, Warning, TEXT("No weather description found"));
|
||||
Descriptions.AddDefaulted(1u);
|
||||
}
|
||||
|
||||
return Descriptions;
|
||||
}
|
||||
|
||||
ADynamicWeather::ADynamicWeather(const FObjectInitializer& ObjectInitializer)
|
||||
{
|
||||
PrimaryActorTick.bCanEverTick = false;
|
||||
|
@ -42,6 +88,22 @@ void ADynamicWeather::PostEditChangeProperty(FPropertyChangedEvent &Event)
|
|||
} else {
|
||||
AdjustSunPositionBasedOnActorRotation();
|
||||
}
|
||||
if (bSaveToConfigFile) {
|
||||
bSaveToConfigFile = false;
|
||||
if (SaveToConfigFile()) {
|
||||
UE_LOG(LogCarla, Log, TEXT("Weather \"%s\" saved to config file"), *Weather.Name);
|
||||
} else {
|
||||
UE_LOG(LogCarla, Error, TEXT("Error saving weather to config file"));
|
||||
}
|
||||
}
|
||||
if (bLoadFromConfigFile) {
|
||||
bLoadFromConfigFile = false;
|
||||
if (LoadFromConfigFile()) {
|
||||
UE_LOG(LogCarla, Log, TEXT("Weather \"%s\" loaded from config file"), *Weather.Name);
|
||||
} else {
|
||||
UE_LOG(LogCarla, Error, TEXT("Error loading weather from config file"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ADynamicWeather::EditorApplyRotation(
|
||||
|
@ -81,3 +143,35 @@ void ADynamicWeather::AdjustSunPositionBasedOnActorRotation()
|
|||
Weather.SunPolarAngle = FMath::RadiansToDegrees(SphericalCoords.X);
|
||||
Weather.SunAzimuthAngle = FMath::RadiansToDegrees(SphericalCoords.Y);
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
|
||||
bool ADynamicWeather::LoadFromConfigFile()
|
||||
{
|
||||
FString FileName;
|
||||
if (GetWeatherIniFileName(FileName) && CheckWeatherValidity(Weather)) {
|
||||
IniFile ConfigFile(FileName);
|
||||
if (!ConfigFile.HasSection(Weather.Name)) {
|
||||
UE_LOG(LogCarla, Error, TEXT("Weather \"%s\" is not present in config file"), *Weather.Name);
|
||||
return false;
|
||||
}
|
||||
Weather.ReadFromConfigFile(ConfigFile, Weather.Name);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ADynamicWeather::SaveToConfigFile() const
|
||||
{
|
||||
FString FileName;
|
||||
if (GetWeatherIniFileName(FileName) && CheckWeatherValidity(Weather)) {
|
||||
IniFile ConfigFile(FileName);
|
||||
Weather.WriteToConfigFile(ConfigFile);
|
||||
return ConfigFile.Write(FileName);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // WITH_EDITOR
|
||||
|
|
|
@ -15,6 +15,9 @@ class CARLA_API ADynamicWeather : public AActor
|
|||
|
||||
public:
|
||||
|
||||
/// If none is found return the default one.
|
||||
static TArray<FWeatherDescription> LoadWeatherDescriptionsFromFile();
|
||||
|
||||
ADynamicWeather(const FObjectInitializer& ObjectInitializer);
|
||||
|
||||
virtual void OnConstruction(const FTransform &Transform) override;
|
||||
|
@ -50,11 +53,27 @@ private:
|
|||
|
||||
void AdjustSunPositionBasedOnActorRotation();
|
||||
|
||||
#if WITH_EDITOR
|
||||
|
||||
bool LoadFromConfigFile();
|
||||
|
||||
bool SaveToConfigFile() const;
|
||||
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
#if WITH_EDITORONLY_DATA
|
||||
UPROPERTY()
|
||||
UArrowComponent* ArrowComponent;
|
||||
UArrowComponent *ArrowComponent;
|
||||
#endif // WITH_EDITORONLY_DATA
|
||||
|
||||
UPROPERTY(Category = "Weather", EditAnywhere)
|
||||
#if WITH_EDITOR
|
||||
UPROPERTY(Category = "Weather Description", EditAnywhere)
|
||||
bool bLoadFromConfigFile = false;
|
||||
|
||||
UPROPERTY(Category = "Weather Description", EditAnywhere)
|
||||
bool bSaveToConfigFile = false;
|
||||
#endif // WITH_EDITOR
|
||||
|
||||
UPROPERTY(Category = "Weather Description", EditAnywhere)
|
||||
FWeatherDescription Weather;
|
||||
};
|
||||
|
|
|
@ -4,66 +4,25 @@
|
|||
#include "CarlaSettings.h"
|
||||
|
||||
#include "CommandLine.h"
|
||||
#include "ConfigCacheIni.h"
|
||||
|
||||
#include <limits>
|
||||
#include "IniFile.h"
|
||||
|
||||
// INI file sections.
|
||||
#define S_CARLA_SERVER TEXT("CARLA/Server")
|
||||
#define S_CARLA_SCENECAPTURE TEXT("CARLA/SceneCapture")
|
||||
|
||||
template <typename TARGET, typename SOURCE>
|
||||
static void SafeCastTo(SOURCE source, TARGET &target)
|
||||
{
|
||||
if ((source >= std::numeric_limits<TARGET>::lowest()) &&
|
||||
(source <= std::numeric_limits<TARGET>::max())) {
|
||||
target = static_cast<TARGET>(source);
|
||||
} else {
|
||||
UE_LOG(LogCarla, Error, TEXT("CarlaSettings: Type cast failed"));
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// -- INIFile ------------------------------------------------------------------
|
||||
// -- MyIniFile ----------------------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
class INIFile {
|
||||
class MyIniFile : public IniFile {
|
||||
public:
|
||||
|
||||
explicit INIFile(const FString &FileName)
|
||||
{
|
||||
ConfigFile.Read(FileName);
|
||||
}
|
||||
|
||||
void GetBool(const TCHAR* Section, const TCHAR* Key, bool &Target) const
|
||||
{
|
||||
bool Value;
|
||||
if (ConfigFile.GetBool(Section, Key, Value)) {
|
||||
Target = Value;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void GetInt(const TCHAR* Section, const TCHAR* Key, T &Target) const
|
||||
{
|
||||
int64 Value;
|
||||
if (ConfigFile.GetInt64(Section, Key, Value)) {
|
||||
SafeCastTo<T>(Value, Target);
|
||||
}
|
||||
}
|
||||
|
||||
void GetString(const TCHAR* Section, const TCHAR* Key, FString &Target) const
|
||||
{
|
||||
FString Value;
|
||||
if (ConfigFile.GetString(Section, Key, Value)) {
|
||||
Target = Value;
|
||||
}
|
||||
}
|
||||
explicit MyIniFile(const FString &FileName) : IniFile(FileName) {}
|
||||
|
||||
void GetPostProcessEffect(const TCHAR* Section, const TCHAR* Key, EPostProcessEffect &Target) const
|
||||
{
|
||||
FString ValueString;
|
||||
if (ConfigFile.GetString(Section, Key, ValueString)) {
|
||||
if (GetFConfigFile().GetString(Section, Key, ValueString)) {
|
||||
if (ValueString == "None") {
|
||||
Target = EPostProcessEffect::None;
|
||||
} else if (ValueString == "SceneFinal") {
|
||||
|
@ -78,18 +37,14 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
FConfigFile ConfigFile;
|
||||
};
|
||||
|
||||
// =============================================================================
|
||||
// -- Other static methods -----------------------------------------------------
|
||||
// -- Static methods -----------------------------------------------------------
|
||||
// =============================================================================
|
||||
|
||||
static void GetCameraDescription(
|
||||
const INIFile &ConfigFile,
|
||||
const MyIniFile &ConfigFile,
|
||||
const TCHAR* Section,
|
||||
FCameraDescription &Camera)
|
||||
{
|
||||
|
@ -120,7 +75,7 @@ static bool RequestedSemanticSegmentation(const FCameraDescription &Camera)
|
|||
static void LoadSettingsFromFile(const FString &FileName, UCarlaSettings &Settings)
|
||||
{
|
||||
UE_LOG(LogCarla, Log, TEXT("Loading settings from \"%s\""), *FileName);
|
||||
INIFile ConfigFile(FileName);
|
||||
MyIniFile ConfigFile(FileName);
|
||||
// CarlaServer.
|
||||
ConfigFile.GetBool(S_CARLA_SERVER, TEXT("UseNetworking"), Settings.bUseNetworking);
|
||||
ConfigFile.GetInt(S_CARLA_SERVER, TEXT("WorldPort"), Settings.WorldPort);
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ConfigCacheIni.h"
|
||||
|
||||
#include <limits>
|
||||
|
||||
/// Wrapper around Unreal's INI file. In get functions, @a Target value is only
|
||||
/// set if it was present in the INI file, otherwise it keeps its value.
|
||||
class CARLA_API IniFile : private NonCopyable
|
||||
{
|
||||
private:
|
||||
|
||||
template <typename TARGET, typename SOURCE>
|
||||
static void SafeCastTo(SOURCE source, TARGET &target)
|
||||
{
|
||||
if ((source >= std::numeric_limits<TARGET>::lowest()) &&
|
||||
(source <= std::numeric_limits<TARGET>::max())) {
|
||||
target = static_cast<TARGET>(source);
|
||||
} else {
|
||||
UE_LOG(LogCarla, Error, TEXT("IniFile: Type cast failed"));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
// ===========================================================================
|
||||
/// @name Constructor
|
||||
// ===========================================================================
|
||||
/// @{
|
||||
|
||||
explicit IniFile(const FString &FileName)
|
||||
{
|
||||
ConfigFile.Read(FileName);
|
||||
}
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
/// @name Other functions
|
||||
// ===========================================================================
|
||||
/// @{
|
||||
|
||||
void AddSectionIfMissing(const FString &Section)
|
||||
{
|
||||
ConfigFile.FindOrAddSection(Section);
|
||||
}
|
||||
|
||||
bool HasSection(const FString &Section) const
|
||||
{
|
||||
return (ConfigFile.Num() > 0) && (ConfigFile.Find(Section) != nullptr);
|
||||
}
|
||||
|
||||
/// Write contents to disk.
|
||||
bool Write(const FString &Filename)
|
||||
{
|
||||
return ConfigFile.Write(Filename);
|
||||
}
|
||||
|
||||
/// Retrieve Unreal's FConfigFile.
|
||||
const FConfigFile &GetFConfigFile() const
|
||||
{
|
||||
return ConfigFile;
|
||||
}
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
/// @name Get functions
|
||||
// ===========================================================================
|
||||
/// @{
|
||||
|
||||
template <typename T>
|
||||
void GetInt(const TCHAR* Section, const TCHAR* Key, T &Target) const
|
||||
{
|
||||
int64 Value;
|
||||
if (ConfigFile.GetInt64(Section, Key, Value)) {
|
||||
SafeCastTo<T>(Value, Target);
|
||||
}
|
||||
}
|
||||
|
||||
void GetString(const TCHAR* Section, const TCHAR* Key, FString &Target) const
|
||||
{
|
||||
FString Value;
|
||||
if (ConfigFile.GetString(Section, Key, Value)) {
|
||||
Target = Value;
|
||||
}
|
||||
}
|
||||
|
||||
void GetBool(const TCHAR* Section, const TCHAR* Key, bool &Target) const
|
||||
{
|
||||
bool Value;
|
||||
if (ConfigFile.GetBool(Section, Key, Value)) {
|
||||
Target = Value;
|
||||
}
|
||||
}
|
||||
|
||||
void GetFloat(const TCHAR* Section, const TCHAR* Key, float &Target) const
|
||||
{
|
||||
FString Value;
|
||||
if (ConfigFile.GetString(Section, Key, Value)) {
|
||||
Target = FCString::Atof(*Value);
|
||||
}
|
||||
}
|
||||
|
||||
void GetLinearColor(const TCHAR* Section, const TCHAR* Key, FLinearColor &Target) const
|
||||
{
|
||||
FString Value;
|
||||
if (ConfigFile.GetString(Section, Key, Value)) {
|
||||
Target.InitFromString(Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// @}
|
||||
// ===========================================================================
|
||||
/// @name Set functions
|
||||
// ===========================================================================
|
||||
/// @{
|
||||
|
||||
void SetInt(const TCHAR* Section, const TCHAR* Key, const int64 Value)
|
||||
{
|
||||
ConfigFile.SetInt64(Section, Key, Value);
|
||||
}
|
||||
|
||||
void SetString(const TCHAR* Section, const TCHAR* Key, const TCHAR* Value)
|
||||
{
|
||||
ConfigFile.SetString(Section, Key, Value);
|
||||
}
|
||||
|
||||
void SetString(const TCHAR* Section, const TCHAR* Key, const FString &Value)
|
||||
{
|
||||
SetString(Section, Key, *Value);
|
||||
}
|
||||
|
||||
void SetBool(const TCHAR* Section, const TCHAR* Key, const bool Value)
|
||||
{
|
||||
SetString(Section, Key, Value ? TEXT("True") : TEXT("False"));
|
||||
}
|
||||
|
||||
void SetFloat(const TCHAR* Section, const TCHAR* Key, const float Value)
|
||||
{
|
||||
SetString(Section, Key, FText::AsNumber(Value).ToString());
|
||||
}
|
||||
|
||||
void SetLinearColor(const TCHAR* Section, const TCHAR* Key, const FLinearColor &Value)
|
||||
{
|
||||
SetString(Section, Key, Value.ToString());
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
|
||||
FConfigFile ConfigFile;
|
||||
};
|
|
@ -0,0 +1,88 @@
|
|||
// CARLA, Copyright (C) 2017 Computer Vision Center (CVC)
|
||||
|
||||
#include "Carla.h"
|
||||
#include "WeatherDescription.h"
|
||||
|
||||
#include "IniFile.h"
|
||||
|
||||
static FString PrecipitationTypeToString(EPrecipitationType PrecipitationType)
|
||||
{
|
||||
const UEnum* ptr = FindObject<UEnum>(ANY_PACKAGE, TEXT("EPrecipitationType"), true);
|
||||
if(!ptr)
|
||||
return FString("Rain");
|
||||
return ptr->GetEnumName(static_cast<int32>(PrecipitationType));
|
||||
}
|
||||
|
||||
static void LoadPrecipitationType(
|
||||
const IniFile &ConfigFile,
|
||||
const TCHAR* Section,
|
||||
const TCHAR* Key,
|
||||
EPrecipitationType &Target)
|
||||
{
|
||||
FString ValueString;
|
||||
if (ConfigFile.GetFConfigFile().GetString(Section, Key, ValueString)) {
|
||||
if (ValueString == "Rain") {
|
||||
Target = EPrecipitationType::Rain;
|
||||
} else {
|
||||
UE_LOG(LogCarla, Error, TEXT("Invalid precipitation type \"%s\" in INI file"), *ValueString);
|
||||
Target = EPrecipitationType::Rain;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FWeatherDescription::ReadFromConfigFile(const IniFile &ConfigFile, const FString &Section)
|
||||
{
|
||||
Name = Section;
|
||||
#define CARLA_LOAD_FROM_INI(Type, Key) ConfigFile.Get ## Type(*Section, TEXT(#Key), Key);
|
||||
// Sun.
|
||||
CARLA_LOAD_FROM_INI(Float, SunPolarAngle)
|
||||
CARLA_LOAD_FROM_INI(Float, SunAzimuthAngle)
|
||||
CARLA_LOAD_FROM_INI(Float, SunBrightness)
|
||||
CARLA_LOAD_FROM_INI(Float, SunDirectionalLightIntensity)
|
||||
CARLA_LOAD_FROM_INI(LinearColor, SunDirectionalLightColor)
|
||||
CARLA_LOAD_FROM_INI(Float, SunIndirectLightIntensity)
|
||||
// Sky.
|
||||
CARLA_LOAD_FROM_INI(Float, CloudOpacity)
|
||||
CARLA_LOAD_FROM_INI(Float, HorizontFalloff)
|
||||
CARLA_LOAD_FROM_INI(LinearColor, ZenithColor)
|
||||
CARLA_LOAD_FROM_INI(LinearColor, HorizonColor)
|
||||
CARLA_LOAD_FROM_INI(LinearColor, CloudColor)
|
||||
CARLA_LOAD_FROM_INI(LinearColor, OverallSkyColor)
|
||||
CARLA_LOAD_FROM_INI(Float, SkyLightIntensity)
|
||||
CARLA_LOAD_FROM_INI(LinearColor, SkyLightColor)
|
||||
// Precipitation.
|
||||
CARLA_LOAD_FROM_INI(Bool, bPrecipitation)
|
||||
LoadPrecipitationType(ConfigFile, *Section, TEXT("PrecipitationType"), PrecipitationType);
|
||||
CARLA_LOAD_FROM_INI(Float, PrecipitationAmount)
|
||||
CARLA_LOAD_FROM_INI(Float, PrecipitationAccumulation)
|
||||
#undef CARLA_LOAD_FROM_INI
|
||||
}
|
||||
|
||||
void FWeatherDescription::WriteToConfigFile(IniFile &ConfigFile) const
|
||||
{
|
||||
const FString &Section = Name;
|
||||
ConfigFile.AddSectionIfMissing(Section);
|
||||
#define CARLA_WRITE_TO_INI(Type, Key) ConfigFile.Set ## Type(*Section, TEXT(#Key), Key);
|
||||
// Sun.
|
||||
CARLA_WRITE_TO_INI(Float, SunPolarAngle)
|
||||
CARLA_WRITE_TO_INI(Float, SunAzimuthAngle)
|
||||
CARLA_WRITE_TO_INI(Float, SunBrightness)
|
||||
CARLA_WRITE_TO_INI(Float, SunDirectionalLightIntensity)
|
||||
CARLA_WRITE_TO_INI(LinearColor, SunDirectionalLightColor)
|
||||
CARLA_WRITE_TO_INI(Float, SunIndirectLightIntensity)
|
||||
// Sky.
|
||||
CARLA_WRITE_TO_INI(Float, CloudOpacity)
|
||||
CARLA_WRITE_TO_INI(Float, HorizontFalloff)
|
||||
CARLA_WRITE_TO_INI(LinearColor, ZenithColor)
|
||||
CARLA_WRITE_TO_INI(LinearColor, HorizonColor)
|
||||
CARLA_WRITE_TO_INI(LinearColor, CloudColor)
|
||||
CARLA_WRITE_TO_INI(LinearColor, OverallSkyColor)
|
||||
CARLA_WRITE_TO_INI(Float, SkyLightIntensity)
|
||||
CARLA_WRITE_TO_INI(LinearColor, SkyLightColor)
|
||||
// Precipitation.
|
||||
CARLA_WRITE_TO_INI(Bool, bPrecipitation)
|
||||
ConfigFile.SetString(*Section, TEXT("PrecipitationType"), PrecipitationTypeToString(PrecipitationType));
|
||||
CARLA_WRITE_TO_INI(Float, PrecipitationAmount)
|
||||
CARLA_WRITE_TO_INI(Float, PrecipitationAccumulation)
|
||||
#undef CARLA_WRITE_TO_INI
|
||||
}
|
|
@ -4,10 +4,12 @@
|
|||
|
||||
#include "WeatherDescription.generated.h"
|
||||
|
||||
class IniFile;
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EPrecipitationType : uint8
|
||||
{
|
||||
Rain UMETA(DisplayName = "Rain"),
|
||||
Rain UMETA(DisplayName = "Rain")
|
||||
};
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
|
@ -15,6 +17,10 @@ struct FWeatherDescription
|
|||
{
|
||||
GENERATED_USTRUCT_BODY()
|
||||
|
||||
void ReadFromConfigFile(const IniFile &ConfigFile, const FString &Section);
|
||||
|
||||
void WriteToConfigFile(IniFile &ConfigFile) const;
|
||||
|
||||
// ===========================================================================
|
||||
/// @name Weather
|
||||
// ===========================================================================
|
||||
|
|
Loading…
Reference in New Issue