XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

SpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 1 Star 0
返回提交历史

XFEstudio/SpaceNinjaServer

feat: personal quarters loadout, stencil, vignette, & fish customisation (#1619)

Closes #1618 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1619 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>

827ea474
Sainan <63328889+Sainan@users.noreply.github.com>
提交于

代码差异

7 个文件 +122 -38
Modified src/controllers/api/getShipController.ts +4 -1
@@ -26,7 +26,10 @@ export const getShipController: RequestHandler = async (req, res) => {
26 26 Colors: personalRooms.ShipInteriorColors,
27 27 ShipAttachments: ship.ShipAttachments,
28 28 SkinFlavourItem: ship.SkinFlavourItem
29 }
29 },
30 FavouriteLoadoutId: personalRooms.Ship.FavouriteLoadoutId
31 ? toOid(personalRooms.Ship.FavouriteLoadoutId)
32 : undefined
30 33 },
31 34 Apartment: personalRooms.Apartment,
32 35 TailorShop: personalRooms.TailorShop
Modified src/controllers/api/setShipFavouriteLoadoutController.ts +23 -12
@@ -3,29 +3,40 @@ import { RequestHandler } from "express";
3 3 import { getPersonalRooms } from "@/src/services/personalRoomsService";
4 4 import { IOid } from "@/src/types/commonTypes";
5 5 import { Types } from "mongoose";
6 import { IFavouriteLoadoutDatabase, TBootLocation } from "@/src/types/shipTypes";
6 7
7 8 export const setShipFavouriteLoadoutController: RequestHandler = async (req, res) => {
8 9 const accountId = await getAccountIdForRequest(req);
9 10 const personalRooms = await getPersonalRooms(accountId);
10 11 const body = JSON.parse(String(req.body)) as ISetShipFavouriteLoadoutRequest;
11 if (body.BootLocation != "SHOP") {
12 throw new Error(`unexpected BootLocation: ${body.BootLocation}`);
13 }
14 const display = personalRooms.TailorShop.FavouriteLoadouts.find(x => x.Tag == body.TagName);
15 if (display) {
16 display.LoadoutId = new Types.ObjectId(body.FavouriteLoadoutId.$oid);
12 if (body.BootLocation == "LISET") {
13 personalRooms.Ship.FavouriteLoadoutId = new Types.ObjectId(body.FavouriteLoadoutId.$oid);
14 } else if (body.BootLocation == "APARTMENT") {
15 updateTaggedDisplay(personalRooms.Apartment.FavouriteLoadouts, body);
16 } else if (body.BootLocation == "SHOP") {
17 updateTaggedDisplay(personalRooms.TailorShop.FavouriteLoadouts, body);
17 18 } else {
18 personalRooms.TailorShop.FavouriteLoadouts.push({
19 Tag: body.TagName,
20 LoadoutId: new Types.ObjectId(body.FavouriteLoadoutId.$oid)
21 });
19 console.log(body);
20 throw new Error(`unexpected BootLocation: ${body.BootLocation}`);
22 21 }
23 22 await personalRooms.save();
24 23 res.json({});
25 24 };
26 25
27 26 interface ISetShipFavouriteLoadoutRequest {
28 BootLocation: string;
27 BootLocation: TBootLocation;
29 28 FavouriteLoadoutId: IOid;
30 TagName: string;
29 TagName?: string;
31 30 }
31
32 const updateTaggedDisplay = (arr: IFavouriteLoadoutDatabase[], body: ISetShipFavouriteLoadoutRequest): void => {
33 const display = arr.find(x => x.Tag == body.TagName!);
34 if (display) {
35 display.LoadoutId = new Types.ObjectId(body.FavouriteLoadoutId.$oid);
36 } else {
37 arr.push({
38 Tag: body.TagName!,
39 LoadoutId: new Types.ObjectId(body.FavouriteLoadoutId.$oid)
40 });
41 }
42 };
Added src/controllers/api/setShipVignetteController.ts +48 -0
@@ -0,0 +1,48 @@
1 import { addMiscItems, combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
2 import { getAccountIdForRequest } from "@/src/services/loginService";
3 import { getPersonalRooms } from "@/src/services/personalRoomsService";
4 import { IInventoryChanges } from "@/src/types/purchaseTypes";
5 import { logger } from "@/src/utils/logger";
6 import { RequestHandler } from "express";
7
8 export const setShipVignetteController: RequestHandler = async (req, res) => {
9 const accountId = await getAccountIdForRequest(req);
10 const inventory = await getInventory(accountId, "MiscItems");
11 const personalRooms = await getPersonalRooms(accountId);
12 const body = JSON.parse(String(req.body)) as ISetShipVignetteRequest;
13 personalRooms.Ship.Wallpaper = body.Wallpaper;
14 personalRooms.Ship.Vignette = body.Vignette;
15 personalRooms.Ship.VignetteFish ??= [];
16 const inventoryChanges: IInventoryChanges = {};
17 for (let i = 0; i != body.Fish.length; ++i) {
18 if (body.Fish[i] && !personalRooms.Ship.VignetteFish[i]) {
19 logger.debug(`moving ${body.Fish[i]} from inventory to vignette slot ${i}`);
20 const miscItemsDelta = [{ ItemType: body.Fish[i], ItemCount: -1 }];
21 addMiscItems(inventory, miscItemsDelta);
22 combineInventoryChanges(inventoryChanges, { MiscItems: miscItemsDelta });
23 } else if (personalRooms.Ship.VignetteFish[i] && !body.Fish[i]) {
24 logger.debug(`moving ${personalRooms.Ship.VignetteFish[i]} from vignette slot ${i} to inventory`);
25 const miscItemsDelta = [{ ItemType: personalRooms.Ship.VignetteFish[i], ItemCount: +1 }];
26 addMiscItems(inventory, miscItemsDelta);
27 combineInventoryChanges(inventoryChanges, { MiscItems: miscItemsDelta });
28 }
29 }
30 personalRooms.Ship.VignetteFish = body.Fish;
31 if (body.VignetteDecos.length) {
32 logger.error(`setShipVignette request not fully handled:`, body);
33 }
34 await Promise.all([inventory.save(), personalRooms.save()]);
35 res.json({
36 Wallpaper: body.Wallpaper,
37 Vignette: body.Vignette,
38 VignetteFish: body.Fish,
39 InventoryChanges: inventoryChanges
40 });
41 };
42
43 interface ISetShipVignetteRequest {
44 Wallpaper: string;
45 Vignette: string;
46 Fish: string[];
47 VignetteDecos: unknown[];
48 }
Modified src/models/personalRoomsModel.ts +24 -20
@@ -2,13 +2,13 @@ import { toOid } from "@/src/helpers/inventoryHelpers";
2 2 import { colorSchema } from "@/src/models/inventoryModels/inventoryModel";
3 3 import { IOrbiter, IPersonalRoomsDatabase, PersonalRoomsModelType } from "@/src/types/personalRoomsTypes";
4 4 import {
5 IApartment,
6 5 IFavouriteLoadoutDatabase,
7 6 IGardening,
8 7 IPlacedDecosDatabase,
9 8 IPictureFrameInfo,
10 9 IRoom,
11 ITailorShopDatabase
10 ITailorShopDatabase,
11 IApartmentDatabase
12 12 } from "@/src/types/shipTypes";
13 13 import { Schema, model } from "mongoose";
14 14
@@ -62,19 +62,34 @@ const roomSchema = new Schema<IRoom>(
62 62 { _id: false }
63 63 );
64 64
65 const favouriteLoadoutSchema = new Schema<IFavouriteLoadoutDatabase>(
66 {
67 Tag: String,
68 LoadoutId: Schema.Types.ObjectId
69 },
70 { _id: false }
71 );
72 favouriteLoadoutSchema.set("toJSON", {
73 virtuals: true,
74 transform(_document, returnedObject) {
75 // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
76 returnedObject.LoadoutId = toOid(returnedObject.LoadoutId);
77 }
78 });
79
65 80 const gardeningSchema = new Schema<IGardening>({
66 81 Planters: [Schema.Types.Mixed] //TODO: add when implementing gardening
67 82 });
68 83
69 const apartmentSchema = new Schema<IApartment>(
84 const apartmentSchema = new Schema<IApartmentDatabase>(
70 85 {
71 86 Rooms: [roomSchema],
72 FavouriteLoadouts: [Schema.Types.Mixed],
87 FavouriteLoadouts: [favouriteLoadoutSchema],
73 88 Gardening: gardeningSchema // TODO: ensure this is correct
74 89 },
75 90 { _id: false }
76 91 );
77 const apartmentDefault: IApartment = {
92 const apartmentDefault: IApartmentDatabase = {
78 93 Rooms: [
79 94 { Name: "ElevatorLanding", MaxCapacity: 1600 },
80 95 { Name: "ApartmentRoomA", MaxCapacity: 1000 },
@@ -90,6 +105,10 @@ const orbiterSchema = new Schema<IOrbiter>(
90 105 {
91 106 Features: [String],
92 107 Rooms: [roomSchema],
108 VignetteFish: { type: [String], default: undefined },
109 FavouriteLoadoutId: Schema.Types.ObjectId,
110 Wallpaper: String,
111 Vignette: String,
93 112 ContentUrlSignature: { type: String, required: false },
94 113 BootLocation: String
95 114 },
@@ -107,21 +126,6 @@ const orbiterDefault: IOrbiter = {
107 126 ]
108 127 };
109 128
110 const favouriteLoadoutSchema = new Schema<IFavouriteLoadoutDatabase>(
111 {
112 Tag: String,
113 LoadoutId: Schema.Types.ObjectId
114 },
115 { _id: false }
116 );
117 favouriteLoadoutSchema.set("toJSON", {
118 virtuals: true,
119 transform(_document, returnedObject) {
120 // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
121 returnedObject.LoadoutId = toOid(returnedObject.LoadoutId);
122 }
123 });
124
125 129 const tailorShopSchema = new Schema<ITailorShopDatabase>(
126 130 {
127 131 FavouriteLoadouts: [favouriteLoadoutSchema],
Modified src/routes/api.ts +2 -0
@@ -115,6 +115,7 @@ import { setGuildMotdController } from "@/src/controllers/api/setGuildMotdContro
115 115 import { setPlacedDecoInfoController } from "@/src/controllers/api/setPlacedDecoInfoController";
116 116 import { setShipCustomizationsController } from "@/src/controllers/api/setShipCustomizationsController";
117 117 import { setShipFavouriteLoadoutController } from "@/src/controllers/api/setShipFavouriteLoadoutController";
118 import { setShipVignetteController } from "@/src/controllers/api/setShipVignetteController";
118 119 import { setSupportedSyndicateController } from "@/src/controllers/api/setSupportedSyndicateController";
119 120 import { setWeaponSkillTreeController } from "@/src/controllers/api/setWeaponSkillTreeController";
120 121 import { shipDecorationsController } from "@/src/controllers/api/shipDecorationsController";
@@ -277,6 +278,7 @@ apiRouter.post("/setGuildMotd.php", setGuildMotdController);
277 278 apiRouter.post("/setPlacedDecoInfo.php", setPlacedDecoInfoController);
278 279 apiRouter.post("/setShipCustomizations.php", setShipCustomizationsController);
279 280 apiRouter.post("/setShipFavouriteLoadout.php", setShipFavouriteLoadoutController);
281 apiRouter.post("/setShipVignette.php", setShipVignetteController);
280 282 apiRouter.post("/setWeaponSkillTree.php", setWeaponSkillTreeController);
281 283 apiRouter.post("/shipDecorations.php", shipDecorationsController);
282 284 apiRouter.post("/startCollectibleEntry.php", startCollectibleEntryController);
Modified src/types/personalRoomsTypes.ts +8 -3
@@ -5,13 +5,18 @@ import {
5 5 IPlacedDecosDatabase,
6 6 ITailorShop,
7 7 ITailorShopDatabase,
8 TBootLocation
8 TBootLocation,
9 IApartmentDatabase
9 10 } from "@/src/types/shipTypes";
10 11 import { Document, Model, Types } from "mongoose";
11 12
12 13 export interface IOrbiter {
13 14 Features: string[];
14 15 Rooms: IRoom[];
16 VignetteFish?: string[];
17 FavouriteLoadoutId?: Types.ObjectId;
18 Wallpaper?: string;
19 Vignette?: string;
15 20 ContentUrlSignature?: string;
16 21 BootLocation?: TBootLocation;
17 22 }
@@ -28,7 +33,7 @@ export interface IPersonalRoomsDatabase {
28 33 personalRoomsOwnerId: Types.ObjectId;
29 34 activeShipId: Types.ObjectId;
30 35 Ship: IOrbiter;
31 Apartment: IApartment;
36 Apartment: IApartmentDatabase;
32 37 TailorShop: ITailorShopDatabase;
33 38 }
34 39
@@ -38,7 +43,7 @@ export type PersonalRoomsDocumentProps = {
38 43 Ship: Omit<IOrbiter, "Rooms"> & {
39 44 Rooms: RoomsType[];
40 45 };
41 Apartment: Omit<IApartment, "Rooms"> & {
46 Apartment: Omit<IApartmentDatabase, "Rooms"> & {
42 47 Rooms: RoomsType[];
43 48 };
44 49 TailorShop: Omit<ITailorShopDatabase, "Rooms"> & {
Modified src/types/shipTypes.ts +13 -2
@@ -28,8 +28,12 @@ export interface IShip {
28 28 ShipId: IOid;
29 29 ShipInterior: IShipInterior;
30 30 Rooms: IRoom[];
31 ContentUrlSignature?: string;
31 VignetteFish?: string[];
32 FavouriteLoadoutId?: IOid;
33 Wallpaper?: string;
34 Vignette?: string;
32 35 BootLocation?: TBootLocation;
36 ContentUrlSignature?: string;
33 37 }
34 38
35 39 export interface IShipDatabase {
@@ -60,10 +64,17 @@ export interface IPlanters {
60 64 export interface IGardening {
61 65 Planters?: IPlanters[];
62 66 }
67
63 68 export interface IApartment {
64 69 Gardening: IGardening;
65 70 Rooms: IRoom[];
66 FavouriteLoadouts: string[];
71 FavouriteLoadouts: IFavouriteLoadout[];
72 }
73
74 export interface IApartmentDatabase {
75 Gardening: IGardening;
76 Rooms: IRoom[];
77 FavouriteLoadouts: IFavouriteLoadoutDatabase[];
67 78 }
68 79
69 80 export interface IPlacedDecosDatabase {