Skip to content

UE4 – Day and Night Cycle for Multiplayer C++ (Part 2)

Hello, i’m not going to go preview this so i’ll just throw this whole thing here. This is fast build of Blueprint version.

You need to create two float curves. Leave them in game root folder. There is a list of assets in DayNightMPSky.cpp file so make sure you have those assets in right place or just change them in the code.

I didn’t test this much so there’s probably some bugs, but all features should work the same way as in Blueprint version.

This is an Actor Class so select Actor when you create a new class.

Tested in

4.25
4.26
4.27
5.00 Early Access 1
5.00 Early Access 2
5.00 Preview 2 (Nightsky doesn't fade away during day)

DayNightMPSky.h

// Level Paradox @levelparadox.com - Day and Night Multiplayer Tutorial

#pragma once

#include "CoreMinimal.h"
#include "Components/SceneComponent.h"
#include "Components/LightComponent.h"
#include "Components/SkyLightComponent.h"
#include "Components/DirectionalLightComponent.h"
#include "Components/StaticMeshComponent.h"
#include "Components/ExponentialHeightFogComponent.h"
#include "Components/SkyAtmosphereComponent.h"
#include "Components/TimelineComponent.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "Materials/MaterialInstanceConstant.h"
#include "UObject/ConstructorHelpers.h"
#include "Net/UnrealNetwork.h"
#include "Kismet/KismetSystemLibrary.h"
#include "SunPosition.h"
#include "TimerManager.h"
#include "DayNightCycle_ST_Rules.h"
#include "GameFramework/Actor.h"
class UStaticMeshComponent;
class UExponentialHeightFogComponent;
class UDirectionalLightComponent;
class USkyAtmosphereComponent;
class USkyLightComponent;
class USceneComponent;
class UTimelineComponent;
class UMaterialInstanceDynamic;
class UMaterialInstanceConstant;
#include "DayNightMPSky.generated.h"

//todo: add parameter when day or night ends
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FIsNight);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FIsDay);

UCLASS()
class ADayNightMPSky : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ADayNightMPSky();

	//For timeline
	float class_DeltaTime;

	/**
	 Components
	*/

	UPROPERTY(BlueprintReadWrite, NonTransactional, meta = (Category = "Default", OverrideNativeName = "Scene"))
	USceneComponent* Scene;

	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta = (Category = "Default", OverrideNativeName = "SkyLight"))
	USkyLightComponent* SkyLight;

	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta = (Category = "Default", OverrideNativeName = "DirectionalLight"))
	UDirectionalLightComponent* DirectionalLight;

	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta = (Category = "Default", OverrideNativeName = "SkyAtmosphere"))
	USkyAtmosphereComponent* SkyAtmosphere;

	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta = (Category = "Default", OverrideNativeName = "MoonLight"))
	UDirectionalLightComponent* MoonLight;

	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, meta = (Category = "Default", OverrideNativeName = "ExponentialHeightFog"))
	UExponentialHeightFogComponent* ExponentialHeightFog;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (AllowPrivateAccess = "true", Category = "Default", OverrideNativeName = "CompassMesh"))
	UStaticMeshComponent* CompassMesh;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (AllowPrivateAccess = "true", Category = "Default", OverrideNativeName = "SkySphereMesh"))
	UStaticMeshComponent* SkySphereMesh;

	/**
	 Functions
	*/
	UFUNCTION(BlueprintCallable)
	void UpdateSky();

	UFUNCTION(BlueprintCallable)
	void UpdateSun();

	UFUNCTION(BlueprintCallable)
	void GetHMSFromSolarTime(float SolarTime_loc, int32& Hour, int32& Minute, int32& Second);

	UFUNCTION(BlueprintCallable)
	void FromDateTime(FDateTime DateTime);

	UFUNCTION(BlueprintPure)
	void IsDST(bool DSTEnable, int32 DSTStartMonth_loc, int32 DSTStartDay_loc, int32 DSTEndMonth_loc, int32 DSTEndDa_loc, int32 DSTSwitchHour_loc, bool& isDST);
	
	UFUNCTION(BlueprintCallable)
	void MoveMoon();

	//timeline
	UFUNCTION(BlueprintCallable)
	void StarsOnHelper(float Value);

	//timeline
	UFUNCTION(BlueprintCallable)
	void StarsOffHelper(float Value);

	UFUNCTION(BlueprintCallable)
	void StarsOnTickTimeline();

	UFUNCTION(BlueprintCallable)
	void StarsOffTickTimeline();

	UFUNCTION(BlueprintCallable)
	void enableskyspam();
	/**
	 Event functions
	*/

	void UpdateRealTime();
	void SetLocationRealTime();
	void SetMoon();
	void SunIsDown();
	void StarsOn();
	void StarsOff();


	/**
	 Variables
	*/

	//Location
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Location"))
	float Latitude;
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Location"))
	float Longitude;
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Location"))
	float TimeZone;
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Location"))
	float NorthOffset;
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Location"))
	float Elevation;
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Location"))
	float CorrectedElevation;
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Location"))
	float Azimuth;

	//Date
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Date"))
	int32 Year;
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Date"))
	int32 Month;
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Date"))
	int32 Day;
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Date"))
	bool UseDaylightSavingsTime;
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Date"))
	int32 DSTStartMonth;
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Date"))
	int32 DSTSTartDay;
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Date"))
	int32 DSTEndMonth;
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Date"))
	int32 DSTEndDay;
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Date"))
	int32 DSTSwitchHours;

	//Time
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Time"))
	float SolarTime;

	//Event Tick
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Event Tick"))
	float HashVal;

	//Default
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Default"))
	UMaterialInstanceDynamic* SkyMaterial;
	
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Default"))
	bool StarsAreOn;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Default"))
	float MaxStarsBrightness;

	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Default"))
	int32 BeginDay;
	
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Default"))
	bool IsNight_B;
	
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Default"))
	bool UpdateSkySpamPrevention;
	
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Default"))
	FTimespan Sunset;
	
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Default"))
	FTimespan Sunrise;
	
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Default"))
	FDateTime GameTimeNow;
	
	UPROPERTY(Replicated, BlueprintReadWrite)
	FDayNightCyclerRules_cpp DN_Rules;
	
	UPROPERTY(BlueprintReadWrite, EditAnywhere, meta = (Category = "Default"))
	FUTCTimeDifference_cpp UTCTimeDifference;

	//Other

	UPROPERTY(BlueprintAssignable, Category = "Event Dispatchers")
	FIsNight IsNight;

	UPROPERTY(BlueprintAssignable, Category = "Event Dispatchers")
	FIsDay IsDay;

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

	//Replication
	void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const;

private:
	UMaterialInterface* SkyMatFound;

	bool tickfirst_timer_on;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	virtual void OnConstruction(const FTransform& Transform);

	FTimerHandle tickfirst_timer;

	FTimeline StarsOnTimeline;
	FTimeline StarsOffTimeline;

	FTimerHandle StarsOnTimerHandle;
	FTimerHandle StarsOffTimerHandle;
};

DayNightMPSky.cpp

// Level Paradox @levelparadox.com - Day and Night Multiplayer Tutorial

/*

debug:
UKismetSystemLibrary::PrintString(GetWorld(), GameTimeNow.ToString());

List of assets:

CurveFloat'/Game/StarsOnCurve.StarsOnCurve'
CurveFloat'/Game/StarsOffCurve.StarsOffCurve'
StaticMesh'/SunPosition/Editor/SM_Compass.SM_Compass'
StaticMesh'/Engine/EngineSky/SM_SkySphere.SM_SkySphere'
MaterialInstanceConstant'/Game/M_SkyMaterial_Inst.M_SkyMaterial_Inst'
/Game/M_SkyMaterial.M_SkyMaterial

*/

#include "DayNightMPSky.h"

// Sets default values
ADayNightMPSky::ADayNightMPSky()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	UseDaylightSavingsTime = true;
	UpdateSkySpamPrevention = true;

	Latitude = 45.0f;
	Longitude = -73.0f;
	TimeZone = -5.0f;
	NorthOffset = 0.0f;
	Elevation = 0.0f;
	CorrectedElevation = 0.0f;
	Azimuth = 0.0f;
	SolarTime = 22.0f;

	Year = 2019;
	Month = 9;
	Day = 21;
	DSTStartMonth = 3;
	DSTSTartDay = 10;
	DSTEndMonth = 11;
	DSTEndDay = 3;
	DSTSwitchHours = 2;

	MaxStarsBrightness = 1.5f;
	BeginDay = 0;

	tickfirst_timer_on = false;

	//Enable replication for this class
	bReplicates = true;


	//Timelines
	const ConstructorHelpers::FObjectFinder<UCurveFloat> Curve_StarsOn(TEXT("CurveFloat'/Game/StarsOnCurve.StarsOnCurve'"));
	StarsOnTimeline = FTimeline{};

	FOnTimelineFloat progressFunction_one{};
	progressFunction_one.BindUFunction(this, "StarsOnHelper");
	StarsOnTimeline.AddInterpFloat(Curve_StarsOn.Object, progressFunction_one, FName{ TEXT("EFFECTFADE") });


	const ConstructorHelpers::FObjectFinder<UCurveFloat> Curve_StarsOff(TEXT("CurveFloat'/Game/StarsOffCurve.StarsOffCurve'"));
	StarsOffTimeline = FTimeline{};

	FOnTimelineFloat progressFunction_two{};
	progressFunction_two.BindUFunction(this, "StarsOffHelper");
	StarsOffTimeline.AddInterpFloat(Curve_StarsOff.Object, progressFunction_two, FName{ TEXT("EFFECTFADE") });


	Scene = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
	CompassMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("CompassMesh"));
	SkyLight = CreateDefaultSubobject<USkyLightComponent>(TEXT("SkyLight"));
	DirectionalLight = CreateDefaultSubobject<UDirectionalLightComponent>(TEXT("DirectionalLight"));
	SkyAtmosphere = CreateDefaultSubobject<USkyAtmosphereComponent>(TEXT("SkyAtmosphere"));
	MoonLight = CreateDefaultSubobject<UDirectionalLightComponent>(TEXT("MoonLight"));
	ExponentialHeightFog = CreateDefaultSubobject<UExponentialHeightFogComponent>(TEXT("ExponentialHeightFog"));
	SkySphereMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("SkySphereMesh"));

	RootComponent = Scene;
	Scene->CreationMethod = EComponentCreationMethod::Native;
	Scene->Mobility = EComponentMobility::Type::Static;

	//Height fog
	FLinearColor albedofogcolor = FLinearColor(0.603827, 0.603827, 0.603827, 1.0f);

	ExponentialHeightFog->FogDensity = 0.05f;
	ExponentialHeightFog->SetVolumetricFog(true);
	ExponentialHeightFog->VolumetricFogScatteringDistribution = 0.9f;
	ExponentialHeightFog->VolumetricFogAlbedo = albedofogcolor.ToFColor(false);
	ExponentialHeightFog->VolumetricFogExtinctionScale = 15.0f;
	ExponentialHeightFog->SetHiddenInGame(true);

	//Skylight
	SkyLight->SetMobility(EComponentMobility::Movable);
	SkyLight->AttachToComponent(Scene, FAttachmentTransformRules::KeepRelativeTransform);

	SkyLight->SourceType = ESkyLightSourceType::SLS_CapturedScene;
	SkyLight->SamplesPerPixel = 2;

	//DirectionalLight
	DirectionalLight->SetMobility(EComponentMobility::Movable);
	DirectionalLight->AttachToComponent(Scene, FAttachmentTransformRules::KeepRelativeTransform);

	//DirectionalLight->Intensity = 10;
	DirectionalLight->ULightComponent::SetIntensity(10.000000);
	//Comment this one in UE5 Preview2
	DirectionalLight->bUsedAsAtmosphereSunLight = true;
	//Uncomment this one in UE5 Preview2
	//DirectionalLight->bAtmosphereSunLight = true;
	DirectionalLight->LightSourceAngle = 0.500000f;
	DirectionalLight->DynamicShadowCascades = 5;
	DirectionalLight->CascadeDistributionExponent = 1.400000f;

	//SkyAtmosphere
	SkyAtmosphere->SetMobility(EComponentMobility::Movable);
	SkyAtmosphere->AttachToComponent(Scene, FAttachmentTransformRules::KeepRelativeTransform);

	//MoonLight
	MoonLight->SetMobility(EComponentMobility::Movable);
	MoonLight->AttachToComponent(Scene, FAttachmentTransformRules::KeepRelativeTransform);

	MoonLight->DynamicShadowCascades = 5;
	MoonLight->CascadeDistributionExponent = 1.400000f;
	MoonLight->LightSourceAngle = 0.500000f;
	//Comment this one in UE5 Preview2
	MoonLight->bUsedAsAtmosphereSunLight = true;
	//Uncomment this one in UE5 Preview2
	//MoonLight->bAtmosphereSunLight = true;
	MoonLight->Temperature = 4000.000000f;
	MoonLight->bUseTemperature = true;
	MoonLight->Intensity = 0.000000f;


	//CompassMesh
	CompassMesh->SetMobility(EComponentMobility::Movable);
	CompassMesh->AttachToComponent(Scene, FAttachmentTransformRules::KeepRelativeTransform);

	CompassMesh->OverrideMaterials = TArray<UMaterialInterface*>();
	CompassMesh->OverrideMaterials.Reserve(1);
	CompassMesh->OverrideMaterials.Add(nullptr);
	CompassMesh->bVisibleInReflectionCaptures = false;
	CompassMesh->bVisibleInRayTracing = false;
	CompassMesh->CastShadow = false;
	CompassMesh->SetCollisionProfileName(FName(TEXT("NoCollision")));

	FRotator CompassMeshRotation = FRotator(0.000000, 90.000000, 0.000000);

	CompassMesh->SetRelativeRotation(CompassMeshRotation.Quaternion());
	CompassMesh->SetHiddenInGame(true);
	CompassMesh->bIsEditorOnly = true;

	static ConstructorHelpers::FObjectFinder<UStaticMesh> CMPMesh(TEXT("StaticMesh'/SunPosition/Editor/SM_Compass.SM_Compass'"));

	if (CMPMesh.Succeeded())
	{
		CompassMesh->SetStaticMesh(CMPMesh.Object);
	}

	//SkySphereMesh
	SkySphereMesh->CreationMethod = EComponentCreationMethod::Native;
	SkySphereMesh->AttachToComponent(Scene, FAttachmentTransformRules::KeepRelativeTransform);
	SkySphereMesh->SetMobility(EComponentMobility::Static);
	SkySphereMesh->OverrideMaterials = TArray<UMaterialInterface*>();
	SkySphereMesh->OverrideMaterials.Add(nullptr);

	SkySphereMesh->SetCollisionProfileName(FName(TEXT("NoCollision")));
	SkySphereMesh->SetRelativeScale3D(FVector(400.000000, 400.000000, 400.000000));
	SkySphereMesh->bVisibleInRayTracing = false;
	SkySphereMesh->bReceivesDecals = false;
	SkySphereMesh->CastShadow = false;
	SkySphereMesh->bAffectDynamicIndirectLighting = false;
	SkySphereMesh->bCastDynamicShadow = false;
	SkySphereMesh->bCastStaticShadow = false;
	SkySphereMesh->BodyInstance.bAutoWeld = false;
	SkySphereMesh->SetGenerateOverlapEvents(false);

	static ConstructorHelpers::FObjectFinder<UStaticMesh> MSHSkySphere(TEXT("StaticMesh'/Engine/EngineSky/SM_SkySphere.SM_SkySphere'"));

	if (MSHSkySphere.Succeeded())
	{
		SkySphereMesh->SetStaticMesh(MSHSkySphere.Object);
	}

	static ConstructorHelpers::FObjectFinder<UMaterialInstanceConstant> X_SphereMaterialInstance(TEXT("MaterialInstanceConstant'/Game/M_SkyMaterial_Inst.M_SkyMaterial_Inst'"));

	if (X_SphereMaterialInstance.Succeeded())
	{
		SkySphereMesh->SetMaterial(0, X_SphereMaterialInstance.Object);
	}


	//find skymaterial
	SkyMatFound = nullptr;

	static ConstructorHelpers::FObjectFinder<UMaterial> SkyMatFind(TEXT("/Game/M_SkyMaterial.M_SkyMaterial"));

	if (SkyMatFind.Succeeded())
	{
		SkyMatFound = SkyMatFind.Object;
	}
}

//Replication
void ADayNightMPSky::GetLifetimeReplicatedProps(TArray< FLifetimeProperty >& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
	DOREPLIFETIME(ADayNightMPSky, DN_Rules);
}

// Called when the game starts or when spawned
void ADayNightMPSky::BeginPlay()
{
	Super::BeginPlay();

	FDayNightCyclerRules_cpp Make;

	FDateTime gw_sst = FDateTime(2009, 1, 20, 18, 0, 0, 0);
	FTimespan rwtigt = FTimespan(0, 1, 0);

	Make.RealWorld_StaticStartTime = FDateTime::UtcNow();
	Make.GameWorld_StaticStartTime = gw_sst;
	Make.RealWorldTimeInGameTime = rwtigt;

	Make.Latitude = 45.0f;
	Make.Longitude = -73.0f;
	Make.TimeZone = -5.0f;
	Make.NorthOffset = 0.0f;
	Make.Moon = true;
	Make.MoonLightStrength = 0.1f;
	Make.MoonDistance = 0.0f;
	Make.MoonSize = 0.005f;

	DN_Rules = Make;

	FTimerHandle beginplayfirst_timer;

	GetWorld()->GetTimerManager().SetTimer(beginplayfirst_timer, this, &ADayNightMPSky::UpdateSky, 0.2f, false);
}

// Called every frame
void ADayNightMPSky::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	class_DeltaTime = DeltaTime;

	UpdateRealTime();
	
	float something = (float)Month + (float)Day + SolarTime;

	if ( HashVal != something )
	{
		HashVal = something;
	}

	if (DirectionalLight->Mobility.GetValue() == EComponentMobility::Movable)
	{
		UpdateSun();
	}

	if (SkyLight->Mobility.GetValue() == EComponentMobility::Movable)
	{

		if (UpdateSkySpamPrevention && !IsNight_B)
		{
			UpdateSkySpamPrevention = false;

			UpdateSky();

			//timer spam prevention
			if (!tickfirst_timer_on)
			{
				tickfirst_timer_on = true;

				GetWorld()->GetTimerManager().SetTimer(tickfirst_timer, this, &ADayNightMPSky::enableskyspam, 1.0f, false);
			}
		}
	}
}

/*
*
*/
void ADayNightMPSky::UpdateSky()
{
	if (::IsValid(SkyLight))
	{
		SkyLight->USkyLightComponent::RecaptureSky();
	}
}

/*
*
*/
void ADayNightMPSky::UpdateSun()
{
	int32 Hour_x, Minute_x, Second_x;
	bool isDST_b = false;
	FSunPositionData SunPositionDt;
	FRotator MainRotator;

	if (::IsValid(DirectionalLight))
	{
		GetHMSFromSolarTime(SolarTime, Hour_x, Minute_x, Second_x);

		IsDST(UseDaylightSavingsTime, DSTStartMonth, DSTSTartDay, DSTEndMonth, DSTEndDay, DSTSwitchHours, isDST_b);

		USunPositionFunctionLibrary::GetSunPosition(Latitude, Longitude, TimeZone, isDST_b, Year, Month, Day, Hour_x, Minute_x, Second_x, SunPositionDt);

		Elevation = SunPositionDt.Elevation;
		CorrectedElevation = SunPositionDt.CorrectedElevation;
		Azimuth = SunPositionDt.Azimuth;
		Sunrise = SunPositionDt.SunriseTime;
		Sunset = SunPositionDt.SunsetTime;
		//SunPositionDt.SolarNoon;

		MainRotator = FRotator(CorrectedElevation, Azimuth + NorthOffset, 0.0f);

		DirectionalLight->SetWorldRotation(MainRotator);

		MainRotator.Pitch = MainRotator.Pitch - 180;
		MoonLight->SetWorldRotation(MainRotator);

		MoveMoon();

		CompassMesh->SetWorldRotation(FRotator(0, NorthOffset + 90, 0).Quaternion());
	}
}

/*
*
*/
void ADayNightMPSky::GetHMSFromSolarTime(float SolarTime_loc, int32& Hour, int32& Minute, int32& Second)
{
	Hour = FMath::TruncToInt(SolarTime_loc) % 24;
	Minute = FMath::TruncToInt((60 * (SolarTime_loc - (float)Hour))) % 60;
	Second = FMath::TruncToInt((3600 * ((SolarTime_loc - Hour) - (Minute / 60))) + 0.5f) % 60;
}

/*
*
*/
void ADayNightMPSky::IsDST(bool DSTEnable, int32 DSTStartMonth_loc, int32 DSTStartDay_loc, int32 DSTEndMonth_loc, int32 DSTEndDa_loc, int32 DSTSwitchHour_loc, bool& isDST)
{
	int32 Hour_x, Minute_x, Second_x;

	GetHMSFromSolarTime(SolarTime, Hour_x, Minute_x, Second_x);

	FDateTime Time_A = FDateTime(Year, Month, Day, Hour_x, Minute_x, Second_x);
	FDateTime Time_B = FDateTime(Year, DSTStartMonth, DSTStartDay_loc, DSTSwitchHour_loc, 0, 0, 0);
	FDateTime Time_C = FDateTime(Year, DSTEndMonth, DSTEndDa_loc, DSTSwitchHour_loc, 0, 0, 0);

	if (Time_A >= Time_B && Time_A <= Time_C && DSTEnable)
	{
		isDST = true;
	}
	else
	{
		isDST = false;
	}
}

/*
*
*/
void ADayNightMPSky::FromDateTime(FDateTime DateTime)
{
	Year = DateTime.GetYear();
	Month = DateTime.GetMonth();
	Day = DateTime.GetDay();
	float Second_l = (float)DateTime.GetSecond();
	float Minute_l = (float)DateTime.GetMinute();
	float Hour_l = (float)DateTime.GetHour();

	float mid_a = Second_l * 0.01f;

	float mid_b = (Second_l / 3) / 60.0f;

	float mid_c = ((Minute_l) + mid_a + mid_b) / 60.0f;

	float mid_d = (mid_c * 100.0f) * 0.01f;

	SolarTime = Hour_l + mid_d;
}

/*
*
*/
void ADayNightMPSky::MoveMoon()
{
	
	FRotator MoonRot = MoonLight->GetComponentRotation();

	FLinearColor Color = FLinearColor(MoonRot.Vector());

	if (::IsValid(SkyMaterial))
	{
		SkyMaterial->SetVectorParameterValue(FName(TEXT("Moon Sky Rotator")), Color);
		
	}
}

/*
*
*/
void ADayNightMPSky::UpdateRealTime()
{
	SetLocationRealTime();

	FTimespan result = FDateTime::UtcNow() - DN_Rules.RealWorld_StaticStartTime;

	float result_two = result.GetTotalSeconds() * (86400.0f / DN_Rules.RealWorldTimeInGameTime.GetTotalSeconds());

	FTimespan time = FTimespan( 0, 0, 0, FMath::TruncToInt(result_two), FMath::TruncToInt(FMath::Fractional(result_two)) );

	GameTimeNow = (DN_Rules.GameWorld_StaticStartTime + time) + UTCTimeDifference.TimeDifference;

	FromDateTime(GameTimeNow);
	SunIsDown();
	SetMoon();

	if (BeginDay == 0)
	{
		BeginDay = GameTimeNow.GetDay();
	}
}

/*
*
*/
void ADayNightMPSky::SetLocationRealTime()
{
	Latitude = DN_Rules.Latitude;
	Longitude = DN_Rules.Longitude;
	TimeZone = DN_Rules.TimeZone;
	NorthOffset = DN_Rules.NorthOffset;
}

/*
*
*/
void ADayNightMPSky::SetMoon()
{
	FLinearColor color = FLinearColor(DN_Rules.MoonSize, DN_Rules.MoonSize, DN_Rules.MoonSize, DN_Rules.MoonSize);

	SkyMaterial->SetVectorParameterValue(FName(TEXT("Moon Radius")), color);
}

void ADayNightMPSky::SunIsDown()
{

	FDateTime datesunset = FDateTime(GameTimeNow.GetYear(), GameTimeNow.GetMonth(), GameTimeNow.GetDay(), Sunset.GetHours(), Sunset.GetMinutes(), Sunset.GetSeconds(), 0);
	FDateTime datesunrise = FDateTime(GameTimeNow.GetYear(), GameTimeNow.GetMonth(), GameTimeNow.GetDay(), Sunrise.GetHours(), Sunrise.GetMinutes(), Sunrise.GetSeconds(), 0);

	if (GameTimeNow >= datesunset || GameTimeNow <= datesunrise)
	{
		//delegate
		IsNight.Broadcast();

		IsNight_B = true;
		StarsOn();

		ExponentialHeightFog->SetHiddenInGame(false);
		DirectionalLight->SetIntensity(0.0f);

		if (DN_Rules.Moon)
		{
			MoonLight->SetIntensity(DN_Rules.MoonLightStrength);
			SkyMaterial->SetScalarParameterValue(FName(TEXT("Enable Moon")), 1.0f);
		}
	}
	else
	{

		//delegate
		IsDay.Broadcast();

		IsNight_B = false;
		StarsOff();

		MoonLight->SetIntensity(0.0f);
		ExponentialHeightFog->SetHiddenInGame(true);
		DirectionalLight->SetIntensity(10.0f);
		SkyMaterial->SetScalarParameterValue(FName(TEXT("Enable Moon")), 0.0f);
	}

}

void ADayNightMPSky::StarsOn()
{

	if (!StarsAreOn)
	{
		StarsAreOn = true;

		//Timeline
		StarsOnTimeline.PlayFromStart();
		GetWorld()->GetTimerManager().SetTimer(StarsOnTimerHandle, this, &ADayNightMPSky::StarsOnTickTimeline, class_DeltaTime, true, 0.0f);
	}

}

void ADayNightMPSky::StarsOnHelper(float Value)
{
	SkyMaterial->SetScalarParameterValue(FName(TEXT("Stars brightness")), FMath::Clamp(Value, 0.0f, MaxStarsBrightness));
}

void ADayNightMPSky::StarsOff()
{
	if (StarsAreOn)
	{
		StarsAreOn = false;

		StarsOffTimeline.PlayFromStart();
		GetWorld()->GetTimerManager().SetTimer(StarsOffTimerHandle, this, &ADayNightMPSky::StarsOffTickTimeline, class_DeltaTime, true, 0.0f);
	}

}

void ADayNightMPSky::StarsOnTickTimeline()
{
	if (StarsOnTimeline.IsPlaying())
	{
		StarsOnTimeline.TickTimeline(class_DeltaTime);
	} 
	else
	{ 
		GetWorld()->GetTimerManager().ClearTimer(StarsOnTimerHandle);
		SetLifeSpan(0);
	}
}

void ADayNightMPSky::StarsOffTickTimeline()
{
	if (StarsOffTimeline.IsPlaying())
	{
		StarsOffTimeline.TickTimeline(class_DeltaTime);
	}
	else
	{
		GetWorld()->GetTimerManager().ClearTimer(StarsOffTimerHandle);
		SetLifeSpan(0);
	}
}

void ADayNightMPSky::StarsOffHelper(float Value)
{
	SkyMaterial->SetScalarParameterValue(FName(TEXT("Stars brightness")), FMath::Clamp(Value, 0.0f, MaxStarsBrightness));
}

/*
*
*/
void ADayNightMPSky::OnConstruction(const FTransform& Transform)
{

	if (SkyMatFound != nullptr)
	{
		SkyMaterial = SkySphereMesh->CreateDynamicMaterialInstance(0, SkyMatFound);
	}

	//create material before these
	UpdateSun();
	UpdateSky();
}

/*
*
*/
void ADayNightMPSky::enableskyspam()
{
	UpdateSkySpamPrevention = true;
	tickfirst_timer_on = false;
}

Don’t forget the DayNightCycle_ST_Rules.h file which you can get from:

https://levelparadox.com/2020/10/06/ue4-day-and-night-cycle-for-multiplayer/2/

Also add SunPosition to MyProjectUE5.Build.cs file

// Fill out your copyright notice in the Description page of Project Settings.

using UnrealBuildTool;

public class MyProjectUE5 : ModuleRules
{
	public MyProjectUE5(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
	
		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore", "SunPosition" });

		PrivateDependencyModuleNames.AddRange(new string[] {  });

		// Uncomment if you are using Slate UI
		// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
		
		// Uncomment if you are using online features
		// PrivateDependencyModuleNames.Add("OnlineSubsystem");

		// To include OnlineSubsystemSteam, add it to the plugins section in your uproject file with the Enabled attribute set to true
	}
}
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
Level Paradox
0
Would love your thoughts, please comment.x
()
x