├── .gitattributes ├── .gitignore ├── Content ├── DemoMap.umap └── TimeDebug.uasset ├── LICENSE ├── README.md ├── Resources └── Icon128.png ├── Source ├── Private │ ├── TimeDateStruct.cpp │ ├── TimeFunctionLibrary.h │ ├── TimeManager.cpp │ └── TimePlugin.cpp ├── Public │ ├── TimeDateStruct.h │ ├── TimeManager.h │ └── TimePlugin.h └── TimePlugin.Build.cs ├── TimePlugin.uplugin └── index-1.html /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Visual Studio 2015 user specific files 2 | .vs/ 3 | 4 | # Visual Studio 2015 database file 5 | *.VC.db 6 | 7 | # Compiled Object files 8 | *.slo 9 | *.lo 10 | *.o 11 | *.obj 12 | 13 | # Precompiled Headers 14 | *.gch 15 | *.pch 16 | 17 | # Compiled Dynamic libraries 18 | *.so 19 | *.dylib 20 | *.dll 21 | 22 | # Fortran module files 23 | *.mod 24 | 25 | # Compiled Static libraries 26 | *.lai 27 | *.la 28 | *.a 29 | *.lib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.ipa 36 | 37 | # These project files can be generated by the engine 38 | *.xcodeproj 39 | *.xcworkspace 40 | *.sln 41 | *.suo 42 | *.opensdf 43 | *.sdf 44 | *.VC.db 45 | *.VC.opendb 46 | 47 | # Precompiled Assets 48 | SourceArt/**/*.png 49 | SourceArt/**/*.tga 50 | 51 | # Binary Files 52 | Binaries/* 53 | Plugins/*/Binaries/* 54 | 55 | # Builds 56 | Build/* 57 | 58 | # Whitelist PakBlacklist-.txt files 59 | !Build/*/ 60 | Build/*/** 61 | !Build/*/PakBlacklist*.txt 62 | 63 | # Don't ignore icon files in Build 64 | !Build/**/*.ico 65 | 66 | # Built data for maps 67 | *_BuiltData.uasset 68 | 69 | # Configuration files generated by the Editor 70 | Saved/* 71 | 72 | # Compiled source files for the engine to use 73 | Intermediate/* 74 | Plugins/*/Intermediate/* 75 | 76 | # Cache files for the editor to use 77 | DerivedDataCache/* 78 | -------------------------------------------------------------------------------- /Content/DemoMap.umap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UE4-OceanProject/TimePlugin/72a76ac001c3a7350a1ce3cdfbe9add9a988f4bd/Content/DemoMap.umap -------------------------------------------------------------------------------- /Content/TimeDebug.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UE4-OceanProject/TimePlugin/72a76ac001c3a7350a1ce3cdfbe9add9a988f4bd/Content/TimeDebug.uasset -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2018 DotCam, TK-Master & Zoc & EvoPulse 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | -Free for use in any UE4 project- 13 | Anyone is free to copy, modify, publish, use, or compile this software, 14 | either in source code form or as a compiled binary, for use in any 15 | Unreal Engine 4 game, simulation, arch-viz, or other related UE4 projects, 16 | both commercial or non-commercial. Attribution is not required. 17 | 18 | -Not for Resale- 19 | This software can not be resold on the Unreal Engine 4 Marketplace, 20 | or any other website as "Content" for UE4 in any form whatsoever. 21 | You can not re-sell this software as a standalone product in whole, 22 | part, or modified form. 23 | 24 | The above copyright notice and this permission notice shall be included in all 25 | copies or substantial portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 33 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TimePlugin 2 | 3 | Adjustable Latitude, Longitude, and Time Zones with a complete calendar and time component that can provide a 1:1 simulation of real world data in the past, present, or future. -------------------------------------------------------------------------------- /Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/UE4-OceanProject/TimePlugin/72a76ac001c3a7350a1ce3cdfbe9add9a988f4bd/Resources/Icon128.png -------------------------------------------------------------------------------- /Source/Private/TimeDateStruct.cpp: -------------------------------------------------------------------------------- 1 | // For copyright see LICENSE in EnvironmentProject root dir, or: 2 | //https://github.com/UE4-OceanProject/OceanProject/blob/Master-Environment-Project/LICENSE 3 | 4 | #include "TimeDateStruct.h" 5 | 6 | // This file must be present for FTimeDateStruct & FLocation 7 | 8 | -------------------------------------------------------------------------------- /Source/Private/TimeFunctionLibrary.h: -------------------------------------------------------------------------------- 1 | // For copyright see LICENSE in EnvironmentProject root dir, or: 2 | //https://github.com/UE4-OceanProject/OceanProject/blob/Master-Environment-Project/LICENSE 3 | 4 | #pragma once 5 | 6 | #include "TimePlugin.h" 7 | #include "Kismet/BlueprintFunctionLibrary.h" 8 | #include "TimeFunctionLibrary.generated.h" 9 | 10 | /* 11 | * Function library class. 12 | * Each function in it is expected to be static and represents blueprint node that can be called in any blueprint. 13 | * 14 | * When declaring function you can define metadata for the node. Key function specifiers will be BlueprintPure and BlueprintCallable. 15 | * BlueprintPure - means the function does not affect the owning object in any way and thus creates a node without Exec pins. 16 | * BlueprintCallable - makes a function which can be executed in Blueprints - Thus it has Exec pins. 17 | * DisplayName - full name of the node, shown when you mouse over the node and in the blueprint drop down menu. 18 | * Its lets you name the node using characters not allowed in C++ function names. 19 | * CompactNodeTitle - the word(s) that appear on the node. 20 | * Keywords - the list of keywords that helps you to find node when you search for it using Blueprint drop-down menu. 21 | * Good example is "Print String" node which you can find also by using keyword "log". 22 | * Category - the category your node will be under in the Blueprint drop-down menu. 23 | * 24 | * For more info on custom blueprint nodes visit documentation: 25 | * https://wiki.unrealengine.com/Custom_Blueprint_Node_Creation 26 | */ 27 | 28 | UCLASS() 29 | class TIMEPLUGIN_API UTimeManagerFunctionLibrary : public UBlueprintFunctionLibrary 30 | { 31 | GENERATED_BODY() 32 | 33 | public: 34 | UFUNCTION(BlueprintPure, meta = (DisplayName = "Get Time Instance", Keywords = ""), meta = (WorldContext = "WorldContextObject"), Category = "TimeManager") 35 | static ATimeManager* GetTimeManager(UObject* WorldContextObject) 36 | { 37 | return FTimePlugin::Get().GetSingletonActor(WorldContextObject); 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /Source/Private/TimeManager.cpp: -------------------------------------------------------------------------------- 1 | #include "TimeManager.h" 2 | #include "TimePlugin.h" 3 | 4 | ATimeManager::ATimeManager(const class FObjectInitializer& PCIP) : Super(PCIP) 5 | { 6 | PrimaryActorTick.bCanEverTick = true; 7 | } 8 | 9 | void ATimeManager::OnConstruction(const FTransform& Transform) 10 | { 11 | ValidateTimeDate(CurrentLocalTime); 12 | OnTimeChanged.Broadcast(CurrentLocalTime); 13 | } 14 | 15 | void ATimeManager::BeginPlay() 16 | { 17 | Super::BeginPlay(); 18 | if (bUseSystemTime) 19 | { 20 | int32 Year, Month, Day, DayOfWeek; 21 | int32 Hour, Minute, Second, Millisecond; 22 | 23 | FPlatformTime::SystemTime(Year, Month, DayOfWeek, Day, Hour, Minute, Second, Millisecond); 24 | FTimeDate SystemTime = FTimeDate(Year, Month, Day, Hour, Minute, Second, Millisecond); 25 | 26 | InitializeTime(SystemTime); 27 | } 28 | else 29 | { 30 | InitializeTime(CurrentLocalTime); 31 | } 32 | } 33 | 34 | void ATimeManager::Tick(float DeltaTime) 35 | { 36 | Super::Tick(DeltaTime); 37 | if (bAutoTick) 38 | { 39 | IncrementTime(DeltaTime); 40 | } 41 | } 42 | 43 | 44 | void ATimeManager::InitializeTime(FTimeDate time) 45 | { 46 | time = ValidateTimeDate(time); 47 | 48 | InternalTime = ConvertToDateTime(time); 49 | OffsetUTC = FMath::Clamp(OffsetUTC, -12, 12); 50 | 51 | DayOfYear = InternalTime.GetDayOfYear(); 52 | int32 leapDays = IsLeapYear(time.Year); 53 | 54 | if (DayOfYear >= (79 + leapDays) && DayOfYear < (265 + leapDays)) 55 | { 56 | bDaylightSavingsActive = true; 57 | } 58 | 59 | OffsetDST = bAllowDaylightSavings && bDaylightSavingsActive ? 1 : 0; 60 | 61 | // Local Standard Time Meridian (degrees) = 15 * Hour Offset from UTC 62 | // The value of the local Standard Time Meridian (15deg intervals) 63 | //NOT USED 64 | LSTM = 15 * OffsetUTC; 65 | 66 | SpanUTC = FTimespan((FMath::Abs(OffsetUTC) + OffsetDST), 0, 0); 67 | 68 | Latitude = FMath::Clamp(Latitude, -90.0f, 90.0f); 69 | Longitude = FMath::Clamp(Longitude, -180.0f, 180.0f); 70 | 71 | CurrentLocalTime = time; 72 | bIsCalendarInitialized = true; 73 | OnTimeChanged.Broadcast(time); // Added delegate call 74 | BP_TimeChanged(); 75 | } 76 | 77 | FTimeDate ATimeManager::ValidateTimeDate(FTimeDate time) 78 | { 79 | time.Year = FMath::Clamp(time.Year, 1, 9999); 80 | time.Month = FMath::Clamp(time.Month, 1, 12); 81 | time.Day = FMath::Clamp(time.Day, 1, GetDaysInMonth(time.Year, time.Month)); 82 | time.Hour = FMath::Clamp(time.Hour, 0, 23); 83 | time.Minute = FMath::Clamp(time.Minute, 0, 59); 84 | time.Second = FMath::Clamp(time.Second, 0, 59); 85 | time.Millisecond = FMath::Clamp(time.Millisecond, 0, 999); 86 | 87 | return time; 88 | } 89 | 90 | FTimeDate ATimeManager::ConvertToTimeDate(FDateTime dt) 91 | { 92 | return FTimeDate(dt.GetYear(), dt.GetMonth(), dt.GetDay(), dt.GetHour(), dt.GetMinute(), dt.GetSecond(), dt.GetMillisecond()); 93 | } 94 | 95 | FDateTime ATimeManager::ConvertToDateTime(FTimeDate td) 96 | { 97 | if (FDateTime::Validate(td.Year, td.Month, td.Day, td.Hour, td.Minute, td.Second, td.Millisecond)) { 98 | return FDateTime(td.Year, td.Month, td.Day, td.Hour, td.Minute, td.Second, td.Millisecond); 99 | } 100 | else 101 | { 102 | UE_LOG(LogTimePlugin, Warning, TEXT("TimePlugin ConvertToDateTime: Invalid TimeData, quietly failing to (1,1,1,0,0,0,0)")); 103 | return FDateTime(1, 1, 1, 0, 0, 0, 0); 104 | } 105 | } 106 | 107 | 108 | /* --- Time of Day --- */ 109 | 110 | float ATimeManager::GetElapsedDayInMinutes() 111 | { 112 | if (!bIsCalendarInitialized) 113 | { 114 | return 0.0f; 115 | } 116 | 117 | return (float)InternalTime.GetTimeOfDay().GetTotalMinutes(); 118 | } 119 | 120 | 121 | void ATimeManager::IncrementTime(float deltaTime) 122 | { 123 | if (!bIsCalendarInitialized) 124 | { 125 | return; 126 | } 127 | 128 | InternalTime += FTimespan::FromSeconds(deltaTime * TimeScaleMultiplier); 129 | 130 | if (CurrentLocalTime.Day != InternalTime.GetDay()) 131 | { 132 | int32 leapDays = IsLeapYear(InternalTime.GetYear()); 133 | DayOfYear = InternalTime.GetDayOfYear(); 134 | 135 | if (DayOfYear >= (79 + leapDays) && DayOfYear < (265 + leapDays)) 136 | { 137 | bDaylightSavingsActive = true; 138 | } 139 | } 140 | CurrentLocalTime = ConvertToTimeDate(InternalTime); 141 | 142 | OnTimeChanged.Broadcast(CurrentLocalTime); 143 | BP_TimeChanged(); 144 | } 145 | 146 | 147 | void ATimeManager::SetCurrentLocalTime(float time) 148 | { 149 | float minute = FMath::Frac(time / 60) * 60; 150 | float second = FMath::Frac(minute) * 60; 151 | float millisec = FMath::Frac(second) * 1000; 152 | FTimeDate newTD = FTimeDate(InternalTime.GetYear(), InternalTime.GetMonth(), InternalTime.GetDay(), 153 | FPlatformMath::FloorToInt(time / 60), minute, second, millisec); 154 | 155 | InitializeTime(newTD); 156 | } 157 | 158 | 159 | int32 ATimeManager::GetDaysInYear(int32 year) 160 | { 161 | return FDateTime::DaysInYear(year); 162 | } 163 | 164 | 165 | int32 ATimeManager::GetDaysInMonth(int32 year, int32 month) 166 | { 167 | return FDateTime::DaysInMonth(year, month); 168 | } 169 | 170 | 171 | int32 ATimeManager::GetDayOfYear(FTimeDate time) 172 | { 173 | return ConvertToDateTime(time).GetDayOfYear(); 174 | } 175 | 176 | 177 | float ATimeManager::GetDayPhase() 178 | { 179 | if (!bIsCalendarInitialized) 180 | { 181 | return 0.0f; 182 | } 183 | 184 | return GetElapsedDayInMinutes() / 1440.0; 185 | } 186 | 187 | 188 | float ATimeManager::GetYearPhase() 189 | { 190 | if (!bIsCalendarInitialized) 191 | { 192 | return 0.0f; 193 | } 194 | 195 | return InternalTime.DaysInYear(InternalTime.GetYear()) / (InternalTime.GetDayOfYear() + (GetElapsedDayInMinutes() / 1440)); 196 | } 197 | 198 | 199 | bool ATimeManager::IsLeapYear(int32 year) 200 | { 201 | bool isLeap = false; 202 | 203 | if ((year % 4) == 0) 204 | { 205 | isLeap = (year % 100) == 0 ? (year % 400) == 0 : true; 206 | } 207 | return isLeap; 208 | } 209 | 210 | //double ATimeManager::toJulianDay(int year, int month, int day, int h, int m, int s) { 211 | // // The conversion formulas are from Meeus, chapter 7. 212 | // bool julian = false; // Use Gregorian calendar 213 | // if (year < 1582 || (year == 1582 && month <= 10) || (year == 1582 && month == 10 && day < 15)) julian = true; 214 | // int D = day; 215 | // int M = month; 216 | // int Y = year; 217 | // if (M < 3) { 218 | // Y--; 219 | // M += 12; 220 | // } 221 | // int A = Y / 100; 222 | // int B = julian ? 0 : 2 - A + A / 4; 223 | // 224 | // double dayFraction = (h + (m + (s / 60.0)) / 60.0) / 24.0; 225 | // double jd = dayFraction + (int)(365.25 * (Y + 4716)) + (int)(30.6001 * (M + 1)) + D + B - 1524.5; 226 | // 227 | // if (jd < 2299160.0 && jd >= 2299150.0) 228 | // //need to make this better somehow 229 | // return 0.0; 230 | // 231 | // return jd; 232 | //} 233 | 234 | 235 | 236 | 237 | /** 238 | * Transforms a Julian day (rise/set/transit fields) to a common date. 239 | * @param jd The Julian day. 240 | * @return A set of integers: year, month, day, hour, minute, second. 241 | * @throws Exception If the input date does not exists. 242 | */ 243 | TArray ATimeManager::getDate(double jd) { 244 | if (jd < 2299160.0 && jd >= 2299150.0) 245 | //throw new Exception("invalid julian day " + jd + ". This date does not exist."); 246 | return TArray{0}; 247 | // The conversion formulas are from Meeus, 248 | // Chapter 7. 249 | double Z = FMath::FloorToFloat(jd + 0.5); 250 | double F = jd + 0.5 - Z; 251 | double A = Z; 252 | if (Z >= 2299161.0) { 253 | int a = (int)((Z - 1867216.25) / 36524.25); 254 | A += 1 + a - a / 4; 255 | } 256 | double B = A + 1524; 257 | int C = (int)((B - 122.1) / 365.25); 258 | int D = (int)(C * 365.25); 259 | int E = (int)((B - D) / 30.6001); 260 | 261 | double exactDay = F + B - D - (int)(30.6001 * E); 262 | int day = (int)exactDay; 263 | int month = (E < 14) ? E - 1 : E - 13; 264 | int year = C - 4715; 265 | if (month > 2) year--; 266 | double h = ((exactDay - day) * SECONDS_PER_DAY) / 3600.0; 267 | 268 | int hour = (int)h; 269 | double m = (h - hour) * 60.0; 270 | int minute = (int)m; 271 | int second = (int)((m - minute) * 60.0); 272 | 273 | return TArray {year, month, day, hour, minute, second}; 274 | } 275 | -------------------------------------------------------------------------------- /Source/Private/TimePlugin.cpp: -------------------------------------------------------------------------------- 1 | // For copyright see LICENSE in EnvironmentProject root dir, or: 2 | //https://github.com/UE4-OceanProject/OceanProject/blob/Master-Environment-Project/LICENSE 3 | 4 | #include "TimePlugin.h" 5 | #include "EngineUtils.h" 6 | 7 | DEFINE_LOG_CATEGORY(LogTimePlugin); 8 | 9 | void FTimePlugin::StartupModule() 10 | { 11 | UE_LOG(LogTimePlugin, Display, TEXT("%s:: StartupModle() Register OnWorldCreated delegate"), *PLUGIN_FUNC_LINE); 12 | 13 | // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module 14 | 15 | //Auto create our TimeManager 16 | //This is called everytime UWorld is created, which is a lot in the editor (every opened BP gets a UWorld) 17 | FWorldDelegates::OnPostWorldInitialization.AddRaw(this, &FTimePlugin::InitSingletonActor); 18 | UE_LOG(LogTimePlugin, Display, TEXT("%s:: Module started"), *PLUGIN_FUNC_LINE); 19 | } 20 | 21 | void FTimePlugin::ShutdownModule() 22 | { 23 | // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, 24 | // we call this function before unloading the module. 25 | FWorldDelegates::OnPostWorldInitialization.RemoveAll(this); 26 | } 27 | 28 | void FTimePlugin::EnforceSingletonActor(UWorld* World) 29 | { 30 | //Make sure there is only one instance of this actor! 31 | //Actor is not blueprintable, but users will find other ways!! 32 | bool bFoundFirstInstance = false; 33 | for (TActorIterator ActorItr(World); ActorItr; ++ActorItr) 34 | { 35 | if (bFoundFirstInstance == false) 36 | { 37 | bFoundFirstInstance = true; 38 | } 39 | else 40 | { 41 | UE_LOG(LogTimePlugin, Display, TEXT("%s:: found more than one TimePlugin destroying..."), *PLUGIN_FUNC_LINE); 42 | ActorItr->Destroy(); 43 | } 44 | } 45 | } 46 | 47 | ATimeManager * FTimePlugin::SpawnSingletonActor(UWorld* World) 48 | { 49 | FActorSpawnParameters SpawnInfo; 50 | ATimeManager* TimeManager = World->SpawnActor(ATimeManager::StaticClass(), FTransform::Identity, FActorSpawnParameters()); 51 | if (!TimeManager) 52 | UE_LOG(LogTimePlugin, Display, TEXT("%s:: Failed to spawn Singleton!"), *PLUGIN_FUNC_LINE); 53 | return TimeManager; 54 | } 55 | 56 | void FTimePlugin::InitSingletonActor(UWorld* World, const UWorld::InitializationValues IVS) 57 | { 58 | //Make sure we are in the correct UWorld! 59 | if ((World->WorldType == EWorldType::Game) || (World->WorldType == EWorldType::PIE) || (World->WorldType == EWorldType::Editor)) 60 | { 61 | //If we already have a TimeManagerEditorActor in the editor level, do not spawn another one 62 | //This also auto spawns a TimeManagerActor in the game world, if the user somehow sneaks a map in 63 | //that has not been opened while the plugin was active! 64 | 65 | EnforceSingletonActor(World); 66 | 67 | for (TActorIterator ActorItr(World); ActorItr; ++ActorItr) 68 | { 69 | //If TimeManager already exists 70 | return; 71 | } 72 | 73 | //Spawn TimeManager since there isn't one already 74 | UE_LOG(LogTimePlugin, Display, TEXT("%s:: No TimePlugin found... spawning..."), *PLUGIN_FUNC_LINE); 75 | SpawnSingletonActor(World); 76 | } 77 | } 78 | 79 | ATimeManager * FTimePlugin::GetSingletonActor(UObject* WorldContextObject) 80 | { 81 | UWorld* World = WorldContextObject->GetWorld(); 82 | if ((World->WorldType == EWorldType::EditorPreview) || (World->WorldType == EWorldType::GamePreview)) 83 | return NULL; 84 | if (World->bIsRunningConstructionScript) 85 | return NULL; 86 | 87 | EnforceSingletonActor(World); 88 | 89 | for (TActorIterator ActorItr(World); ActorItr; ++ActorItr) 90 | { 91 | return *ActorItr; 92 | } 93 | 94 | //In the impossible case that we don't have an actor, spawn one! 95 | UE_LOG(LogTimePlugin, Display, TEXT("%s:: Somehow we don't have a TimePlugin even after all the safeguards... spawning..."), *PLUGIN_FUNC_LINE); 96 | return SpawnSingletonActor(World); 97 | } 98 | 99 | IMPLEMENT_MODULE(FTimePlugin, TimePlugin) 100 | 101 | -------------------------------------------------------------------------------- /Source/Public/TimeDateStruct.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //#include "CoreMinimal.h" 4 | #include "TimeDateStruct.generated.h" 5 | 6 | 7 | USTRUCT(BlueprintType) 8 | struct FTimeDate 9 | { 10 | GENERATED_USTRUCT_BODY() 11 | 12 | // The year value for this time and date. 13 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Time") 14 | int32 Year; 15 | 16 | // The month value for this time and date. 17 | 18 | UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (ClampMin = 0, ClampMax = 12), Category = "Time") 19 | int32 Month; 20 | 21 | // The day value for this time and date. 22 | UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (ClampMin = 0, ClampMax = 31), Category = "Time") 23 | int32 Day; 24 | 25 | // The hour value for this time and date. 26 | UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (ClampMin = 0, ClampMax = 23), Category = "Time") 27 | int32 Hour; 28 | 29 | // The minute value for this time and date. 30 | UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (ClampMin = 0, ClampMax = 59), Category = "Time") 31 | int32 Minute; 32 | 33 | // The second value for this time and date. 34 | UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (ClampMin = 0, ClampMax = 59), Category = "Time") 35 | int32 Second; 36 | 37 | // The millisecond value for this time and date. 38 | UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (ClampMin = 0, ClampMax = 999), Category = "Time") 39 | int32 Millisecond; 40 | 41 | // Fully initialized constructor 42 | FTimeDate(int32 InYear = 2020, int32 InMonth = 1, int32 InDay = 1, int32 InHour = 10, int32 InMinute = 0, int32 InSecond = 0, int32 InMillisecond = 0) 43 | { 44 | Year = InYear; 45 | Month = InMonth; 46 | Day = InDay; 47 | Hour = InHour; 48 | Minute = InMinute; 49 | Second = InSecond; 50 | Millisecond = InMillisecond; 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /Source/Public/TimeManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | //#include "CoreMinimal.h" 4 | #include "GameFramework/Actor.h" 5 | #include "TimeDateStruct.h" 6 | #include "TimeManager.generated.h" 7 | 8 | 9 | DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnTimeChanged, FTimeDate, NewTime); 10 | 11 | 12 | //An actor based calendar system for tracking date + time. 13 | //Transient will prevent this from being saved since we autospawn this anyways 14 | //Removed the Transient property, plugin will spawn this if its missing, and wont if its already there 15 | UCLASS(Blueprintable) 16 | class ATimeManager : public AActor 17 | { 18 | GENERATED_BODY() 19 | 20 | public: 21 | ATimeManager(const class FObjectInitializer& ObjectInitializer); 22 | 23 | virtual void OnConstruction(const FTransform& Transform) override; 24 | virtual void BeginPlay() override; 25 | virtual void Tick(float DeltaSeconds) override; 26 | 27 | // Use System Time instead of CurrentLocalTime struct 28 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "TimeManager") 29 | bool bUseSystemTime = false; 30 | 31 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "TimeManager") 32 | bool bAutoTick = true; 33 | 34 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "TimeManager") 35 | bool bFreezeTime = false; 36 | 37 | // Current Local Clock Time (LCT) 38 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "TimeManager") 39 | FTimeDate CurrentLocalTime; 40 | 41 | // The Latitude of the local location (-90 to +90 in degrees) 42 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "TimeManager") 43 | float Latitude = 30.0f; 44 | 45 | // The Longitude of the local location (-180 to +180 in degrees) 46 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "TimeManager") 47 | float Longitude = 101.0f; 48 | 49 | // The number of hours offset from UTC for the local location (value in the range of -12 to +12 hours from UTC) 50 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "TimeManager") 51 | int32 OffsetUTC = 0; 52 | 53 | // Determines whether Daylight Savings time should be enabled for the local location 54 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "TimeManager") 55 | bool bAllowDaylightSavings = false; 56 | 57 | // The value to multiply the base game time by (1 second real time is multiplied to equal X seconds in game) 58 | UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "TimeManager") 59 | float TimeScaleMultiplier = 1.0f; 60 | 61 | // Shows the number of hours (0 or 1) being subtracted for the current TimeDate for Daylight Savings Time (if enabled) 62 | UPROPERTY(BlueprintReadOnly, Category = "TimeManager") 63 | int32 OffsetDST = 0; 64 | 65 | //Shows the current day of year 66 | UPROPERTY(BlueprintReadOnly, Category = "TimeManager") 67 | int32 DayOfYear = 0; 68 | 69 | // Shows whether Daylight Savings is active for the current date 70 | UPROPERTY(BlueprintReadOnly, Category = "TimeManager") 71 | bool bDaylightSavingsActive = false; 72 | 73 | 74 | 75 | 76 | /* called when the time changes, internal blueprint only, use delegate OnTimeChanged , for external use */ 77 | UFUNCTION(BlueprintImplementableEvent, Category = "TimeManager") 78 | void BP_TimeChanged(); 79 | 80 | 81 | /* ======== DELEGATES ====== */ 82 | /* Called when the time changes */ 83 | UPROPERTY(BlueprintAssignable, Category = "TimeManager") 84 | FOnTimeChanged OnTimeChanged; 85 | 86 | 87 | 88 | 89 | 90 | const double JULIAN_DAYS_PER_CENTURY = 36525.0; 91 | /** Julian century conversion constant = 100 * days per year. */ 92 | UPROPERTY(BlueprintReadOnly, Category = "TimeManager") 93 | float F_JULIAN_DAYS_PER_CENTRY = JULIAN_DAYS_PER_CENTURY; 94 | 95 | const double SECONDS_PER_DAY = 86400.0; 96 | /** Seconds in one day. */ 97 | UPROPERTY(BlueprintReadOnly, Category = "TimeManager") 98 | float F_SECONDS_PER_DAY = SECONDS_PER_DAY; 99 | 100 | const double J2000 = 2451545.0; 101 | /** Our default epoch. The Julian Day which represents noon on 2000-01-01. */ 102 | UPROPERTY(BlueprintReadOnly, Category = "TimeManager") 103 | float F_J2000 = J2000; 104 | 105 | 106 | // The value of the local Standard Time Meridian (15deg intervals) 107 | UPROPERTY(BlueprintReadOnly, Category = "TimeManager") 108 | int32 LSTM = 0; 109 | 110 | 111 | // ------------------- 112 | // PUBLIC FUNCTIONS 113 | // ------------------- 114 | 115 | /** 116 | * Name: InitializeCalendar 117 | * Description: Initializes the calendar with the provided TimeDate, and validates the range of all input values. 118 | * 119 | * @param: time (TimeDate) - The TimeDate value to calculate from. 120 | */ 121 | UFUNCTION(BlueprintCallable, Category = "TimeManager") 122 | void InitializeTime(FTimeDate in_Time); 123 | 124 | /** 125 | * Name: SetCurrentLocalTime 126 | * Description: Sets the local time from minutes, and runs InitializeCalendar to validate and set variables. 127 | * 128 | * @param: time (float) - The number of minutes (+ frac minutes) to calculate from. 129 | */ 130 | UFUNCTION(BlueprintCallable, Category = "TimeManager") 131 | void SetCurrentLocalTime(float in_Time); 132 | 133 | /** 134 | * Name: IncrementTime 135 | * Description: Increments time based on the deltaSeconds * TimeScaleMultiplier 136 | * 137 | * @param: deltaSeconds (float) - The Tick (or accumulated ticks) delta time since the last update 138 | */ 139 | UFUNCTION(BlueprintCallable, Category = "TimeManager") 140 | void IncrementTime(float in_deltaSeconds); 141 | 142 | 143 | 144 | /* --- Utility Functions --- */ 145 | 146 | /** 147 | * Name: GetDayOfYear 148 | * Description: Gets the number of full days elapsed in the current year for the provided date. 149 | * 150 | * @param: time (TimeDate) - The TimeDate value to calculate from. 151 | * @return: int32 - The number of days elapsed in the current year. 152 | */ 153 | UFUNCTION(BlueprintCallable, Category = "TimeManager") 154 | int32 GetDayOfYear(FTimeDate time); 155 | 156 | /** 157 | * Name: DaysInYear 158 | * Description: Gets the total number of days in a given year (takes leap years into account). 159 | * 160 | * @param: year (int32) - The year value. 161 | * @return: int32 - The total number of days in the given year. 162 | */ 163 | UFUNCTION(BlueprintCallable, Category = "TimeManager") 164 | int32 GetDaysInYear(int32 year = 1900); 165 | 166 | /** 167 | * Name: DaysInMonth 168 | * Description: The number of days in the specified month (leap years are taken into account). 169 | * 170 | * @param: month (int32) - The month value. 171 | * @param: year (int32) - The year value. 172 | * @return: int32 - The number of days in the given month for the given year. 173 | */ 174 | UFUNCTION(BlueprintCallable, Category = "TimeManager") 175 | int32 GetDaysInMonth(int32 year = 1900, int32 month = 1); 176 | 177 | /** 178 | * Name: GetElapsedDayInMinutes 179 | * Description: Gets the accumulated number of minutes (plus fractional) for the current day. 180 | * 181 | * @return: float - The number of minutes (plus fractional minute - NOT seconds) elapsed in the given day. 182 | */ 183 | UFUNCTION(BlueprintCallable, Category = "TimeManager") 184 | float GetElapsedDayInMinutes(); 185 | 186 | /** 187 | * Name: GetDayPhase 188 | * Description: Gets the current day phase in a 0 to 1 range (fractional). 189 | * 190 | * @return: float - The day phase in a 0.0 to 1.0 range. 191 | */ 192 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "TimeManager") 193 | float GetDayPhase(); 194 | 195 | 196 | /** 197 | * Name: GetYearPhase 198 | * Description: Gets the current year phase in a 0 to 1 range (fractional). 199 | * 200 | * @return: float - The year phase in a 0.0 to 1.0 range. 201 | */ 202 | UFUNCTION(BlueprintCallable, BlueprintPure, Category = "TimeManager") 203 | float GetYearPhase(); 204 | 205 | /** 206 | * Name: IsLeapYear 207 | * Description: Determines whether the specified year is a leap year. 208 | * 209 | * @param: year (int32) - The year value to check 210 | * @return: bool - Will return true if it is a leap year, otherwise false. 211 | */ 212 | UFUNCTION(BlueprintCallable, Category = "TimeManager") 213 | bool IsLeapYear(int32 year = 1900); 214 | 215 | 216 | //These would be normally be private, but plugins will need this stuff 217 | //These are still private blueprint wise 218 | 219 | FDateTime InternalTime; 220 | 221 | // The UTC + DST TimeSpan difference vs current time 222 | FTimespan SpanUTC; 223 | 224 | // The Julian Day number for Jan 1, 2000 @ 12:00 UTC 225 | double JD2000 = 2451545.0; 226 | 227 | // The Julian Day number for Jan 1, 1900 @ 12:00 UTC 228 | double JD1900 = 2415020.0; 229 | 230 | double ElapsedJD1900 = 0.0; 231 | 232 | UFUNCTION(BlueprintCallable, Category = "TimeManager") 233 | FTimeDate ConvertToTimeDate(FDateTime dt); 234 | 235 | UFUNCTION(BlueprintCallable, Category = "TimeManager") 236 | FDateTime ConvertToDateTime(FTimeDate td); 237 | 238 | UFUNCTION(BlueprintCallable, Category = "TimeManager") 239 | FTimeDate ValidateTimeDate(FTimeDate time); 240 | 241 | //static TArray getDate(double jd); 242 | TArray getDate(double jd); 243 | 244 | UPROPERTY(BlueprintReadOnly, Category = "TimeManager") 245 | bool bIsCalendarInitialized = false; 246 | 247 | 248 | 249 | }; -------------------------------------------------------------------------------- /Source/Public/TimePlugin.h: -------------------------------------------------------------------------------- 1 | // For copyright see LICENSE in EnvironmentProject root dir, or: 2 | //https://github.com/UE4-OceanProject/OceanProject/blob/Master-Environment-Project/LICENSE 3 | 4 | #pragma once 5 | 6 | #include "TimeManager.h" 7 | 8 | DECLARE_LOG_CATEGORY_EXTERN(LogTimePlugin, Display, All); 9 | 10 | #define PLUGIN_FUNC (FString(__FUNCTION__)) // Current Class Name + Function Name where this is called 11 | #define PLUGIN_LINE (FString::FromInt(__LINE__)) // Current Line Number in the code where this is called 12 | #define PLUGIN_FUNC_LINE (PLUGIN_FUNC + "(Line: " + PLUGIN_LINE + ")") // Current Class and Line Number where this is called! 13 | 14 | 15 | class TIMEPLUGIN_API FTimePlugin : public IModuleInterface 16 | { 17 | public: 18 | /** IModuleInterface implementation */ 19 | virtual void StartupModule() override; 20 | virtual void ShutdownModule() override; 21 | 22 | void EnforceSingletonActor(UWorld* World); 23 | ATimeManager * SpawnSingletonActor(UWorld* World); 24 | void InitSingletonActor(UWorld* World, const UWorld::InitializationValues IVS); 25 | 26 | ATimeManager * GetSingletonActor(UObject* WorldContextObject); 27 | 28 | /** 29 | * Singleton-like access to this module's interface. This is just for convenience! 30 | * Beware of calling this during the shutdown phase, though. Your module might have been unloaded already. 31 | * 32 | * @return Returns singleton instance, loading the module on demand if needed 33 | */ 34 | static inline FTimePlugin& Get() 35 | { 36 | return FModuleManager::LoadModuleChecked< FTimePlugin >("TimePlugin"); 37 | } 38 | 39 | /** 40 | * Checks to see if this module is loaded and ready. It is only valid to call Get() if IsAvailable() returns true. 41 | * 42 | * @return True if the module is loaded and ready to use 43 | */ 44 | static inline bool IsAvailable() 45 | { 46 | return FModuleManager::Get().IsModuleLoaded("TimePlugin"); 47 | } 48 | }; 49 | 50 | -------------------------------------------------------------------------------- /Source/TimePlugin.Build.cs: -------------------------------------------------------------------------------- 1 | // For copyright see LICENSE in EnvironmentProject root dir, or: 2 | //https://github.com/UE4-OceanProject/OceanProject/blob/Master-Environment-Project/LICENSE 3 | 4 | using UnrealBuildTool; 5 | using System.IO; 6 | 7 | public class TimePlugin : ModuleRules 8 | { 9 | public TimePlugin(ReadOnlyTargetRules Target) : base(Target) 10 | { 11 | PublicIncludePaths.AddRange(new string[] { }); 12 | 13 | PrivateIncludePaths.AddRange(new string[] { }); 14 | 15 | PublicDependencyModuleNames.AddRange(new string[] { 16 | "Core" 17 | }); 18 | 19 | PrivateDependencyModuleNames.AddRange(new string[] { 20 | "CoreUObject", 21 | "Engine" 22 | }); 23 | 24 | DynamicallyLoadedModuleNames.AddRange(new string[] { }); 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /TimePlugin.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "1.0", 5 | "FriendlyName": "TimePlugin", 6 | "Description": "Adjustable Latitude, Longitude, and Time Zones with a complete calendar and time component that can provide a 1:1 simulation of real world data in the past, present, or future.", 7 | "Category": "Time", 8 | "CreatedBy": "EvoPulse", 9 | "CreatedByURL": "", 10 | "DocsURL": "", 11 | "SupportURL": "", 12 | "EnabledByDefault": true, 13 | "CanContainContent": true, 14 | "Modules": [ 15 | { 16 | "Name": "TimePlugin", 17 | "Type": "Runtime", 18 | "LoadingPhase": "PreDefault" 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /index-1.html: -------------------------------------------------------------------------------- 1 | Unknown 2 |

TimePlugin

3 |

Adjustable Latitude, Longitude, and Time Zones with a complete calendar and time component that can provide a 1:1 simulation of real world data in the past, present, or future.

4 | --------------------------------------------------------------------------------