feat: Kinematic Instant Messaging (#801)

This commit is contained in:
Sainan 2025-01-19 01:57:24 +01:00 committed by GitHub
parent f1c3dcbefc
commit a8fb9095c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 219 additions and 2 deletions

View File

@ -0,0 +1,23 @@
import { getInventory } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { RequestHandler } from "express";
export const clearDialogueHistoryController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId);
const request = JSON.parse(String(req.body)) as IClearDialogueRequest;
if (inventory.DialogueHistory && inventory.DialogueHistory.Dialogues) {
for (const dialogueName of request.Dialogues) {
const index = inventory.DialogueHistory.Dialogues.findIndex(x => x.DialogueName == dialogueName);
if (index != -1) {
inventory.DialogueHistory.Dialogues.splice(index, 1);
}
}
}
await inventory.save();
res.end();
};
interface IClearDialogueRequest {
Dialogues: string[];
}

View File

@ -0,0 +1,85 @@
import { getInventory } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { ICompletedDialogue } from "@/src/types/inventoryTypes/inventoryTypes";
import { logger } from "@/src/utils/logger";
import { RequestHandler } from "express";
export const saveDialogueController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const request = JSON.parse(String(req.body)) as SaveDialogueRequest;
if ("YearIteration" in request) {
const inventory = await getInventory(accountId);
if (inventory.DialogueHistory) {
inventory.DialogueHistory.YearIteration = request.YearIteration;
} else {
inventory.DialogueHistory = { YearIteration: request.YearIteration };
}
await inventory.save();
res.end();
} else {
const inventory = await getInventory(accountId);
if (!inventory.DialogueHistory) {
throw new Error("bad inventory state");
}
if (request.QueuedDialogues.length != 0 || request.OtherDialogueInfos.length != 0) {
logger.error(`saveDialogue request not fully handled: ${String(req.body)}`);
}
inventory.DialogueHistory.Dialogues ??= [];
let dialogue = inventory.DialogueHistory.Dialogues.find(x => x.DialogueName == request.DialogueName);
if (!dialogue) {
dialogue =
inventory.DialogueHistory.Dialogues[
inventory.DialogueHistory.Dialogues.push({
Rank: 0,
Chemistry: 0,
AvailableDate: new Date(0),
AvailableGiftDate: new Date(0),
RankUpExpiry: new Date(0),
BountyChemExpiry: new Date(0),
Gifts: [],
Booleans: [],
Completed: [],
DialogueName: request.DialogueName
}) - 1
];
}
dialogue.Rank = request.Rank;
dialogue.Chemistry = request.Chemistry;
//dialogue.QueuedDialogues = request.QueuedDialogues;
for (const bool of request.Booleans) {
dialogue.Booleans.push(bool);
}
for (const bool of request.ResetBooleans) {
const index = dialogue.Booleans.findIndex(x => x == bool);
if (index != -1) {
dialogue.Booleans.splice(index, 1);
}
}
dialogue.Completed.push(request.Data);
const tomorrowAt0Utc = (Math.trunc(Date.now() / (86400 * 1000)) + 1) * 86400 * 1000;
dialogue.AvailableDate = new Date(tomorrowAt0Utc);
await inventory.save();
res.json({
InventoryChanges: [],
AvailableDate: { $date: { $numberLong: tomorrowAt0Utc.toString() } }
});
}
};
type SaveDialogueRequest = SaveYearIterationRequest | SaveCompletedDialogueRequest;
interface SaveYearIterationRequest {
YearIteration: number;
}
interface SaveCompletedDialogueRequest {
DialogueName: string;
Rank: number;
Chemistry: number;
CompletionType: number;
QueuedDialogues: string[]; // unsure
Booleans: string[];
ResetBooleans: string[];
Data: ICompletedDialogue;
OtherDialogueInfos: string[]; // unsure
}

View File

@ -47,7 +47,12 @@ import {
ICrewShipPilotWeapon,
IShipExterior,
IHelminthFoodRecord,
ICrewShipMembersDatabase
ICrewShipMembersDatabase,
IDialogueHistoryDatabase,
IDialogueDatabase,
IDialogueGift,
ICompletedDialogue,
IDialogueClient
} from "../../types/inventoryTypes/inventoryTypes";
import { IOid } from "../../types/commonTypes";
import {
@ -710,6 +715,60 @@ crewShipSchema.set("toJSON", {
}
});
const dialogueGiftSchema = new Schema<IDialogueGift>(
{
Item: String,
GiftedQuantity: Number
},
{ _id: false }
);
const completedDialogueSchema = new Schema<ICompletedDialogue>(
{
Id: { type: String, required: true },
Booleans: { type: [String], required: true },
Choices: { type: [Number], required: true }
},
{ _id: false }
);
const dialogueSchema = new Schema<IDialogueDatabase>(
{
Rank: Number,
Chemistry: Number,
AvailableDate: Date,
AvailableGiftDate: Date,
RankUpExpiry: Date,
BountyChemExpiry: Date,
//QueuedDialogues: ???
Gifts: { type: [dialogueGiftSchema], default: [] },
Booleans: { type: [String], default: [] },
Completed: { type: [completedDialogueSchema], default: [] },
DialogueName: String
},
{ _id: false }
);
dialogueSchema.set("toJSON", {
virtuals: true,
transform(_doc, ret) {
const db = ret as IDialogueDatabase;
const client = ret as IDialogueClient;
client.AvailableDate = toMongoDate(db.AvailableDate);
client.AvailableGiftDate = toMongoDate(db.AvailableGiftDate);
client.RankUpExpiry = toMongoDate(db.RankUpExpiry);
client.BountyChemExpiry = toMongoDate(db.BountyChemExpiry);
}
});
const dialogueHistorySchema = new Schema<IDialogueHistoryDatabase>(
{
YearIteration: { type: Number, required: true },
Dialogues: { type: [dialogueSchema], required: false }
},
{ _id: false }
);
const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
{
accountOwnerId: Schema.Types.ObjectId,
@ -1069,7 +1128,9 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
//Grustag three
DeathSquadable: Boolean,
EndlessXP: { type: [endlessXpProgressSchema], default: undefined }
EndlessXP: { type: [endlessXpProgressSchema], default: undefined },
DialogueHistory: dialogueHistorySchema
},
{ timestamps: { createdAt: "Created" } }
);

View File

@ -6,6 +6,7 @@ import { archonFusionController } from "@/src/controllers/api/archonFusionContro
import { artifactsController } from "../controllers/api/artifactsController";
import { checkDailyMissionBonusController } from "@/src/controllers/api/checkDailyMissionBonusController";
import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController";
import { clearDialogueHistoryController } from "@/src/controllers/api/clearDialogueHistoryController";
import { createGuildController } from "@/src/controllers/api/createGuildController";
import { creditsController } from "@/src/controllers/api/creditsController";
import { deleteSessionController } from "@/src/controllers/api/deleteSessionController";
@ -52,6 +53,7 @@ import { projectionManagerController } from "../controllers/api/projectionManage
import { purchaseController } from "@/src/controllers/api/purchaseController";
import { queueDojoComponentDestructionController } from "@/src/controllers/api/queueDojoComponentDestructionController";
import { rerollRandomModController } from "@/src/controllers/api/rerollRandomModController";
import { saveDialogueController } from "@/src/controllers/api/saveDialogueController";
import { saveLoadoutController } from "@/src/controllers/api/saveLoadout";
import { sellController } from "@/src/controllers/api/sellController";
import { setActiveQuestController } from "@/src/controllers/api/setActiveQuestController";
@ -118,6 +120,7 @@ apiRouter.post("/arcaneCommon.php", arcaneCommonController);
apiRouter.post("/archonFusion.php", archonFusionController);
apiRouter.post("/artifacts.php", artifactsController);
apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);
apiRouter.post("/createGuild.php", createGuildController);
apiRouter.post("/endlessXp.php", endlessXpController);
apiRouter.post("/evolveWeapon.php", evolveWeaponController);
@ -142,6 +145,7 @@ apiRouter.post("/playerSkills.php", playerSkillsController);
apiRouter.post("/projectionManager.php", projectionManagerController);
apiRouter.post("/purchase.php", purchaseController);
apiRouter.post("/rerollRandomMod.php", rerollRandomModController);
apiRouter.post("/saveDialogue.php", saveDialogueController);
apiRouter.post("/saveLoadout.php", saveLoadoutController);
apiRouter.post("/sell.php", sellController);
apiRouter.post("/setEquippedInstrument.php", setEquippedInstrumentController);

View File

@ -306,6 +306,7 @@ export interface IInventoryResponse extends IDailyAffiliations {
Harvestable: boolean;
DeathSquadable: boolean;
EndlessXP?: IEndlessXpProgress[];
DialogueHistory?: IDialogueHistoryDatabase;
}
export interface IAffiliation {
@ -948,3 +949,46 @@ export interface IEndlessXpProgress {
Category: TEndlessXpCategory;
Choices: string[];
}
export interface IDialogueHistoryClient {
YearIteration: number;
Dialogues?: IDialogueClient[];
}
export interface IDialogueHistoryDatabase {
YearIteration: number;
Dialogues?: IDialogueDatabase[];
}
export interface IDialogueClient {
Rank: number;
Chemistry: number;
AvailableDate: IMongoDate;
AvailableGiftDate: IMongoDate;
RankUpExpiry: IMongoDate;
BountyChemExpiry: IMongoDate;
//QueuedDialogues: any[];
Gifts: IDialogueGift[];
Booleans: string[];
Completed: ICompletedDialogue[];
DialogueName: string;
}
export interface IDialogueDatabase
extends Omit<IDialogueClient, "AvailableDate" | "AvailableGiftDate" | "RankUpExpiry" | "BountyChemExpiry"> {
AvailableDate: Date;
AvailableGiftDate: Date;
RankUpExpiry: Date;
BountyChemExpiry: Date;
}
export interface IDialogueGift {
Item: string;
GiftedQuantity: number;
}
export interface ICompletedDialogue {
Id: string;
Booleans: string[];
Choices: number[];
}