From a578d94a97793c157168ce3027cf4ab1aed689db Mon Sep 17 00:00:00 2001 From: Matthew Heroux Date: Tue, 21 Nov 2023 06:42:57 -0600 Subject: [PATCH] feat: add ht to instance-service (#716) Signed-off-by: hxtree --- services/instances/README.md | 21 ++++++ .../instances/src/models/get-hadean-time.ts | 68 +++++++++++++++++++ .../instances/src/models/instance.schema.ts | 23 ++++++- .../src/module/instances/instance.e2e-spec.ts | 32 +++++++++ services/time-keeper/README.md | 22 ------ 5 files changed, 143 insertions(+), 23 deletions(-) create mode 100644 services/instances/src/models/get-hadean-time.ts delete mode 100644 services/time-keeper/README.md diff --git a/services/instances/README.md b/services/instances/README.md index f9df1213..da82329f 100644 --- a/services/instances/README.md +++ b/services/instances/README.md @@ -13,3 +13,24 @@ others user game. This concept can be applied to many other business use cases, but the service is primarily useful for maintaining isolation of data that spans multiple services. + +## Time + +Time is displayed to the User using a HT format. + +HT stands for Hadean Time which is the time period in which the universe began, +5 billion years ago. + +Time progresses in reverse. The "-" before the time period indicates that it is +a count down until our universe begins. + +Time Format: + +-00E-053-0125HT + +Game time is always be going. There should be no downtime while accessing menus. +When a player select a character and goes into their equipment menu they adjust +it live with while the majority of the screen is visible. + +A pause feature may be used but would freeze all players menu in a game +instance. diff --git a/services/instances/src/models/get-hadean-time.ts b/services/instances/src/models/get-hadean-time.ts new file mode 100644 index 00000000..d14d2e0c --- /dev/null +++ b/services/instances/src/models/get-hadean-time.ts @@ -0,0 +1,68 @@ +export const MAX_PLAYTIME_DURATION_HOURS = 200; + +/** + * Converts playtime duration into Hadean Time (HT) format. + * + * Hadean Time (HT) is the time period in which the universe began. + * Within the game, time progresses in reverse based on playtime duration. + * A "-" prefix before the time period indicates that the game is + * counting down to when the universe begins, 5 billion years ago. + * A "+" prefix indicates that playtime has exceeded the maximum and the game + * is counting up from the start of the Hadean era. + * Time is displayed to the User using a HT format. + * + * Hadean Time Format: -00E-053-0125HT + * + * - The first part, the sign ('-' or '+'), indicates whether the game is counting down ('-') + * or counting up ('+') based on playtime duration. + * + * - The second part represents the number of Hadean Years (E-053), which is the + * overarching unit of time in the Hadean Time system. It represents the elapsed time + * since the start of the Hadean era, with each Hadean Year corresponding to + * approximately 300 Hadean Days. + * + * - The third part represents the remaining Hadean Days within the current Hadean Year. + * These days are calculated based on the remaining playtime in the game. + * + * - The fourth part represents the remaining Hadean Hours within the current Hadean Day. + * These hours are also calculated based on the remaining playtime. + * + * @param {number} playtimeDurationInMinutes - The duration of playtime in minutes. + * @returns {string} The Hadean Time formatted string. + */ +export function getHadeanTime(playtimeDurationInMinutes: number): string { + const minutesPerHour = 60; + const hadeanDayDuration = 8 * minutesPerHour; + const hadeanYearDuration = 300 * hadeanDayDuration; + + const maxPlaytimeDurationInRealMinutes = MAX_PLAYTIME_DURATION_HOURS * minutesPerHour; + + const remainingPlaytimeInMinutes = Math.min( + playtimeDurationInMinutes, + maxPlaytimeDurationInRealMinutes, + ); + + if (remainingPlaytimeInMinutes === maxPlaytimeDurationInRealMinutes) { + return '-00E-000-0000HT'; // Hadean Time is all zeros after max playtime + } + + const remainingHadeanYears = Math.floor( + remainingPlaytimeInMinutes / hadeanYearDuration, + ); + const remainingHadeanDays = Math.floor( + (remainingPlaytimeInMinutes % hadeanYearDuration) / hadeanDayDuration, + ); + const remainingHadeanHours = Math.floor( + (remainingPlaytimeInMinutes % hadeanDayDuration) / minutesPerHour, + ); + + const sign = playtimeDurationInMinutes > maxPlaytimeDurationInRealMinutes ? '+' : '-'; + + const formattedResult = `${sign}${remainingHadeanYears + .toString() + .padStart(2, '0')}E-${remainingHadeanDays + .toString() + .padStart(3, '0')}-${remainingHadeanHours.toString().padStart(4, '0')}HT`; + + return formattedResult; +} diff --git a/services/instances/src/models/instance.schema.ts b/services/instances/src/models/instance.schema.ts index e76d9f4c..108e77ac 100644 --- a/services/instances/src/models/instance.schema.ts +++ b/services/instances/src/models/instance.schema.ts @@ -1,8 +1,13 @@ /* eslint-disable func-names */ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Document } from 'mongoose'; -import { IsDateString, IsUuidV4 } from '@cats-cradle/validation-schemas'; +import { + IsDateString, + IsNumber, + IsUuidV4, +} from '@cats-cradle/validation-schemas'; import { v4 } from 'uuid'; +import { getHadeanTime } from './get-hadean-time'; @Schema({ collection: 'instance' }) export class Instance { @@ -17,6 +22,18 @@ export class Instance { }) public _id!: string; + /** + * Duration always increases when a player is logged into an instance. + * It stops when all players log out of an instance. + * the unit of measurement for the value stored is minutes + */ + @IsNumber() + @Prop({ + type: Number, + default: () => 0, + }) + public duration: number; + @IsDateString() @Prop({ type: String, @@ -45,6 +62,10 @@ export const InstanceSchema = SchemaFactory.createForClass(Instance) }, }); +InstanceSchema.virtual('time').get(function () { + return getHadeanTime(this.duration); +}); + InstanceSchema.index({ id: 1, }); diff --git a/services/instances/src/module/instances/instance.e2e-spec.ts b/services/instances/src/module/instances/instance.e2e-spec.ts index d5eed16c..22036f5c 100644 --- a/services/instances/src/module/instances/instance.e2e-spec.ts +++ b/services/instances/src/module/instances/instance.e2e-spec.ts @@ -12,6 +12,7 @@ import { InstanceSchema, Instance } from '../../models/instance.schema'; import { InstanceRepository } from '../../models/instance.repository'; import { InstanceController } from './instance.controller'; import { CreateDto } from './create.dto'; +import { MAX_PLAYTIME_DURATION_HOURS } from '../../models/get-hadean-time'; describe('/instances', () => { let app: INestApplication; @@ -107,6 +108,37 @@ describe('/instances', () => { }), ); }); + + it.each([ + [MAX_PLAYTIME_DURATION_HOURS * 60, '-00E-000-0000HT'], + // TODO fix time format calc + // [100 * 60, '-00E-000-0500HT'], + // [7000 * 60, '+00E-000-0200HT'], + ])( + 'should when playtime is %s minutes return %s ', + async (playTimeDurationInMinutes: number, expectedHadeanTime: string) => { + const instance = await FakerFactory.create( + Instance, + { + duration: playTimeDurationInMinutes, + createdAt: new Date().toISOString(), + }, + { optionals: false }, + ); + + await instanceRepository.create(instance); + + const result = await supertest(app.getHttpServer()) + .get(`/instances/?id=${instance._id}`) + .expect(200); + + expect(result.body[0]).toHaveProperty('time', expectedHadeanTime); + expect(result.body[0]).toHaveProperty( + 'duration', + playTimeDurationInMinutes, + ); + }, + ); }); describe('POST /instances', () => { diff --git a/services/time-keeper/README.md b/services/time-keeper/README.md deleted file mode 100644 index 40fcf999..00000000 --- a/services/time-keeper/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# @cats-cradle/time-keeper - -![Lifecycle](https://img.shields.io/badge/lifecycle-unstable-red) - -Time is displayed to the User using a HT format. - -HT stands for Hadean Time which is the time period in which the universe began, -5 billion years ago. - -Time progresses in reverse. The "-" before the time period indicates that it is -a count down until our universe begins. - -Time Format: - --00E-053-0125HT - -Game time is always be going. There should be no downtime while accessing menus. -When a player select a character and goes into their equipment menu they adjust -it live with while the majority of the screen is visible. - -A pause feature may be used but would freeze all players menu in a game -instance.