using { /Fortnite.com/Devices } using { /Fortnite.com/Playspaces } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/Diagnostics } # ----------------------------------------------------------------------------- # live_event_manager — Indie Island tutorial 01: Live concert, step 2 # # Counts down to a real date and time and fires a trigger at that exact moment. # # Setup (Details panel): # 1. Add one entry to Events per scheduled show. # 2. EventTime = the date and time you ANNOUNCED, in your local time. # 3. StartTrigger = the trigger that starts the show. Use the same trigger # device as concert_manager.ShowStartTrigger. # 4. Optional: CountdownBoard = a Billboard in the world showing the countdown. # 5. Set TimeZoneOffsetHours below for your timezone (see the warning). # ----------------------------------------------------------------------------- LiveEventText(Value : string) : message = "{Value}" # A wall-clock date and time, in your local timezone. event_date_time := class: @editable Year : int = 2026 @editable Month : int = 1 @editable Day : int = 1 @editable Hour : int = 20 @editable Minute : int = 0 @editable Second : int = 0 # One scheduled show. scheduled_event := class: @editable EventTime : event_date_time = event_date_time{} @editable StartTrigger : trigger_device = trigger_device{} @editable CountdownBoard : billboard_device = billboard_device{} live_event_manager := class(creative_device): @editable Events : []scheduled_event = array{} # Texts on the countdown board. Replace with your own. @editable CountdownPrefix : string = "YOUR ARTIST NAME -- LIVE IN " @editable StartedText : string = "THE SHOW HAS STARTED!" SecondsInAMinute : int = 60 SecondsInAnHour : int = 3600 SecondsInADay : int = 86400 SecondsInAYear : int = 31536000 SecondsInALeapYear : int = 31622400 # !! Verse has no timezone or daylight-saving support. !! # GetSecondsSinceEpoch() is UTC. This offset converts your local time to UTC. # Example, Amsterdam: 1 in winter, 2 during summer time. # Flip it by hand at each clock change -- a wrong value makes the show fire # EXACTLY one hour early or late. TimeZoneOffsetHours : int = 2 var DaysInMonth : []int = array{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31} OnBegin() : void = for (E : Events): spawn { RunCountdown(E) } RunCountdown(E : scheduled_event) : void = loop: if (NowSeconds := Int[GetSecondsSinceEpoch()]): EventEpoch := GetEpochFromDateAndTime(E.EventTime) SecondsDifference := EventEpoch - NowSeconds if (SecondsDifference <= 0): E.StartTrigger.Trigger() E.CountdownBoard.SetText(LiveEventText(StartedText)) Print("[live_event_manager] Event started") break Left := GetDateAndTimeFromSeconds(SecondsDifference) Days := Left.Day - 1 Hours := FormatTwoDigits(Left.Hour) Minutes := FormatTwoDigits(Left.Minute) Seconds := FormatTwoDigits(Left.Second) E.CountdownBoard.SetText(LiveEventText("{CountdownPrefix}{Days}d {Hours}:{Minutes}:{Seconds}")) Sleep(1.0) FormatTwoDigits(Number : int) : string = if (Number < 10): return "0{Number}" return "{Number}" # Local date/time -> seconds since 1970 (UTC). GetEpochFromDateAndTime(InDateAndTime : event_date_time) : int = var CurrentSeconds : int = 0 var CurrentYear : int = 1970 loop: if (CurrentYear >= InDateAndTime.Year): break NewYearlySeconds := if (IsLeapYear(CurrentYear)?) { SecondsInALeapYear } else { SecondsInAYear } set CurrentSeconds += NewYearlySeconds set CurrentYear += 1 if: if (IsLeapYear(InDateAndTime.Year)?): set DaysInMonth[1] = 29 else: set DaysInMonth[1] = 28 var CurrentMonth : int = 1 loop: if (CurrentMonth >= InDateAndTime.Month): break if (MonthDays := DaysInMonth[CurrentMonth - 1]): set CurrentSeconds += MonthDays * SecondsInADay set CurrentMonth += 1 set CurrentSeconds += (InDateAndTime.Day - 1) * SecondsInADay set CurrentSeconds += InDateAndTime.Hour * SecondsInAnHour set CurrentSeconds += InDateAndTime.Minute * SecondsInAMinute set CurrentSeconds += InDateAndTime.Second set CurrentSeconds -= (TimeZoneOffsetHours * SecondsInAnHour) return CurrentSeconds # A number of seconds -> years/months/days/hours/minutes/seconds. # Used here for "time left", so Day starts at 1 (hence Days := Day - 1 above). GetDateAndTimeFromSeconds(InSeconds : int) : event_date_time = var CurrentYears : int = 1970 var CurrentMonth : int = 1 var CurrentDays : int = 1 var CurrentHours : int = 0 var CurrentMinutes : int = 0 var CurrentSeconds : int = InSeconds loop: NewYearlySeconds := if (IsLeapYear(CurrentYears)?) { SecondsInALeapYear } else { SecondsInAYear } if (CurrentSeconds < NewYearlySeconds): break set CurrentSeconds -= NewYearlySeconds set CurrentYears += 1 if: if (IsLeapYear(CurrentYears)?): set DaysInMonth[1] = 29 else: set DaysInMonth[1] = 28 loop: if (CurrentMonthSeconds := DaysInMonth[CurrentMonth - 1] * SecondsInADay): if (CurrentSeconds < CurrentMonthSeconds): break set CurrentSeconds -= CurrentMonthSeconds set CurrentMonth += 1 if (NewDays := Floor(CurrentSeconds / SecondsInADay)): set CurrentDays = NewDays + 1 set CurrentSeconds -= NewDays * SecondsInADay if (NewHours := Floor(CurrentSeconds / SecondsInAnHour)): set CurrentHours = NewHours set CurrentSeconds -= NewHours * SecondsInAnHour if (NewMinutes := Floor(CurrentSeconds / SecondsInAMinute)): set CurrentMinutes = NewMinutes set CurrentSeconds -= NewMinutes * SecondsInAMinute return event_date_time{ Year := CurrentYears, Month := CurrentMonth, Day := CurrentDays, Hour := CurrentHours, Minute := CurrentMinutes, Second := CurrentSeconds} IsLeapYear(Year : int) : logic = if (Mod[Year, 4] = 0 and Mod[Year, 100] <> 0): return true else if (Mod[Year, 400] = 0): return true return false