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

XFESpaceNinjaServer

A simple server for a small space ninja game

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

XFEstudio/XFESpaceNinjaServer

feat: clan polychrome research (#1177)

Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1177

ab11f67f
Sainan <sainan@calamity.inc>
提交于

代码差异

4 个文件 +76 -28
Modified src/controllers/api/guildTechController.ts +58 -28
@@ -4,6 +4,7 @@ import {
4 4 getGuildVault,
5 5 hasAccessToDojo,
6 6 hasGuildPermission,
7 removePigmentsFromGuildMembers,
7 8 scaleRequiredCount
8 9 } from "@/src/services/guildService";
9 10 import { ExportDojoRecipes, IDojoResearch } from "warframe-public-export-plus";
@@ -28,8 +29,7 @@ export const guildTechController: RequestHandler = async (req, res) => {
28 29 const inventory = await getInventory(accountId);
29 30 const guild = await getGuildForRequestEx(req, inventory);
30 31 const data = JSON.parse(String(req.body)) as TGuildTechRequest;
31 const action = data.Action.split(",")[0];
32 if (action == "Sync") {
32 if (data.Action == "Sync") {
33 33 let needSave = false;
34 34 const techProjects: ITechProjectClient[] = [];
35 35 if (guild.TechProjects) {
@@ -53,18 +53,18 @@ export const guildTechController: RequestHandler = async (req, res) => {
53 53 await guild.save();
54 54 }
55 55 res.json({ TechProjects: techProjects });
56 } else if (action == "Start") {
57 if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Fabricator))) {
56 } else if (data.Action == "Start") {
57 if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Tech))) {
58 58 res.status(400).send("-1").end();
59 59 return;
60 60 }
61 const recipe = ExportDojoRecipes.research[data.RecipeType!];
61 const recipe = ExportDojoRecipes.research[data.RecipeType];
62 62 guild.TechProjects ??= [];
63 63 if (!guild.TechProjects.find(x => x.ItemType == data.RecipeType)) {
64 64 const techProject =
65 65 guild.TechProjects[
66 66 guild.TechProjects.push({
67 ItemType: data.RecipeType!,
67 ItemType: data.RecipeType,
68 68 ReqCredits: config.noDojoResearchCosts ? 0 : scaleRequiredCount(recipe.price),
69 69 ReqItems: recipe.ingredients.map(x => ({
70 70 ItemType: x.ItemType,
@@ -76,16 +76,20 @@ export const guildTechController: RequestHandler = async (req, res) => {
76 76 setTechLogState(guild, techProject.ItemType, 5);
77 77 if (config.noDojoResearchCosts) {
78 78 processFundedProject(guild, techProject, recipe);
79 } else {
80 if (data.RecipeType.substring(0, 39) == "/Lotus/Types/Items/Research/DojoColors/") {
81 guild.ActiveDojoColorResearch = data.RecipeType;
82 }
79 83 }
80 84 }
81 85 await guild.save();
82 86 res.end();
83 } else if (action == "Contribute") {
87 } else if (data.Action == "Contribute") {
84 88 if (!hasAccessToDojo(inventory)) {
85 89 res.status(400).send("-1").end();
86 90 return;
87 91 }
88 const contributions = data as IGuildTechContributeFields;
92 const contributions = data;
89 93 const techProject = guild.TechProjects!.find(x => x.ItemType == contributions.RecipeType)!;
90 94
91 95 if (contributions.VaultCredits) {
@@ -136,8 +140,12 @@ export const guildTechController: RequestHandler = async (req, res) => {
136 140
137 141 if (techProject.ReqCredits == 0 && !techProject.ReqItems.find(x => x.ItemCount > 0)) {
138 142 // This research is now fully funded.
139 const recipe = ExportDojoRecipes.research[data.RecipeType!];
143 const recipe = ExportDojoRecipes.research[data.RecipeType];
140 144 processFundedProject(guild, techProject, recipe);
145 if (data.RecipeType.substring(0, 39) == "/Lotus/Types/Items/Research/DojoColors/") {
146 guild.ActiveDojoColorResearch = "";
147 await removePigmentsFromGuildMembers(guild._id);
148 }
141 149 }
142 150
143 151 await guild.save();
@@ -146,12 +154,12 @@ export const guildTechController: RequestHandler = async (req, res) => {
146 154 InventoryChanges: inventoryChanges,
147 155 Vault: getGuildVault(guild)
148 156 });
149 } else if (action == "Buy") {
157 } else if (data.Action.split(",")[0] == "Buy") {
150 158 if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Fabricator))) {
151 159 res.status(400).send("-1").end();
152 160 return;
153 161 }
154 const purchase = data as IGuildTechBuyFields;
162 const purchase = data as IGuildTechBuyRequest;
155 163 const quantity = parseInt(data.Action.split(",")[1]);
156 164 const recipeChanges = [
157 165 {
@@ -173,13 +181,12 @@ export const guildTechController: RequestHandler = async (req, res) => {
173 181 Recipes: recipeChanges
174 182 }
175 183 });
176 } else if (action == "Fabricate") {
184 } else if (data.Action == "Fabricate") {
177 185 if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Fabricator))) {
178 186 res.status(400).send("-1").end();
179 187 return;
180 188 }
181 const payload = data as IGuildTechFabricateRequest;
182 const recipe = ExportDojoRecipes.fabrications[payload.RecipeType];
189 const recipe = ExportDojoRecipes.fabrications[data.RecipeType];
183 190 const inventoryChanges: IInventoryChanges = updateCurrency(inventory, recipe.price, false);
184 191 inventoryChanges.MiscItems = recipe.ingredients.map(x => ({
185 192 ItemType: x.ItemType,
@@ -190,6 +197,31 @@ export const guildTechController: RequestHandler = async (req, res) => {
190 197 await inventory.save();
191 198 // Not a mistake: This response uses `inventoryChanges` instead of `InventoryChanges`.
192 199 res.json({ inventoryChanges: inventoryChanges });
200 } else if (data.Action == "Pause") {
201 if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Tech))) {
202 res.status(400).send("-1").end();
203 return;
204 }
205 const project = guild.TechProjects!.find(x => x.ItemType == data.RecipeType)!;
206 project.State = -2;
207 guild.ActiveDojoColorResearch = "";
208 await guild.save();
209 await removePigmentsFromGuildMembers(guild._id);
210 res.end();
211 } else if (data.Action == "Unpause") {
212 if (!hasAccessToDojo(inventory) || !(await hasGuildPermission(guild, accountId, GuildPermission.Tech))) {
213 res.status(400).send("-1").end();
214 return;
215 }
216 const project = guild.TechProjects!.find(x => x.ItemType == data.RecipeType)!;
217 project.State = 0;
218 guild.ActiveDojoColorResearch = data.RecipeType;
219 const entry = guild.TechChanges?.find(x => x.details == data.RecipeType);
220 if (entry) {
221 entry.dateTime = new Date();
222 }
223 await guild.save();
224 res.end();
193 225 } else {
194 226 throw new Error(`unknown guildTech action: ${data.Action}`);
195 227 }
@@ -233,20 +265,24 @@ const setTechLogState = (
233 265 };
234 266
235 267 type TGuildTechRequest =
236 | ({
237 Action: string;
238 } & Partial<IGuildTechStartFields> &
239 Partial<IGuildTechContributeFields>)
240 | IGuildTechFabricateRequest;
268 | { Action: "Sync" | "SomethingElseThatWeMightNotKnowAbout" }
269 | IGuildTechBasicRequest
270 | IGuildTechContributeRequest;
241 271
242 interface IGuildTechStartFields {
272 interface IGuildTechBasicRequest {
273 Action: "Start" | "Fabricate" | "Pause" | "Unpause";
243 274 Mode: "Guild";
244 275 RecipeType: string;
245 276 }
246 277
247 type IGuildTechBuyFields = IGuildTechStartFields;
278 interface IGuildTechBuyRequest {
279 Action: string;
280 Mode: "Guild";
281 RecipeType: string;
282 }
248 283
249 interface IGuildTechContributeFields {
284 interface IGuildTechContributeRequest {
285 Action: "Contribute";
250 286 ResearchId: "";
251 287 RecipeType: string;
252 288 RegularCredits: number;
@@ -254,9 +290,3 @@ interface IGuildTechContributeFields {
254 290 VaultCredits: number;
255 291 VaultMiscItems: IMiscItem[];
256 292 }
257
258 interface IGuildTechFabricateRequest {
259 Action: "Fabricate";
260 Mode: "Guild";
261 RecipeType: string;
262 }
Modified src/models/guildModel.ts +1 -0
@@ -152,6 +152,7 @@ const guildSchema = new Schema<IGuildDatabase>(
152 152 VaultShipDecorations: { type: [typeCountSchema], default: undefined },
153 153 VaultFusionTreasures: { type: [fusionTreasuresSchema], default: undefined },
154 154 TechProjects: { type: [techProjectSchema], default: undefined },
155 ActiveDojoColorResearch: { type: String, default: "" },
155 156 Class: { type: Number, default: 0 },
156 157 XP: { type: Number, default: 0 },
157 158 ClaimedXP: { type: [String], default: undefined },
Modified src/services/guildService.ts +15 -0
@@ -93,6 +93,7 @@ export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: s
93 93 TradeTax: guild.TradeTax,
94 94 Tier: 1,
95 95 Vault: getGuildVault(guild),
96 ActiveDojoColorResearch: guild.ActiveDojoColorResearch,
96 97 Class: guild.Class,
97 98 XP: guild.XP,
98 99 IsContributor: !!guild.CeremonyContributors?.find(x => x.equals(accountId)),
@@ -350,3 +351,17 @@ export const hasGuildPermissionEx = (
350 351 const rank = guild.Ranks[member.rank];
351 352 return (rank.Permissions & perm) != 0;
352 353 };
354
355 export const removePigmentsFromGuildMembers = async (guildId: string | Types.ObjectId): Promise<void> => {
356 const members = await GuildMember.find({ guildId, status: 0 }, "accountId");
357 for (const member of members) {
358 const inventory = await getInventory(member.accountId.toString(), "MiscItems");
359 const index = inventory.MiscItems.findIndex(
360 x => x.ItemType == "/Lotus/Types/Items/Research/DojoColors/GenericDojoColorPigment"
361 );
362 if (index != -1) {
363 inventory.MiscItems.splice(index, 1);
364 await inventory.save();
365 }
366 }
367 };
Modified src/types/guildTypes.ts +2 -0
@@ -12,6 +12,7 @@ export interface IGuildClient {
12 12 TradeTax: number;
13 13 Tier: number;
14 14 Vault: IGuildVault;
15 ActiveDojoColorResearch: string;
15 16 Class: number;
16 17 XP: number;
17 18 IsContributor: boolean;
@@ -38,6 +39,7 @@ export interface IGuildDatabase {
38 39 VaultFusionTreasures?: IFusionTreasure[];
39 40
40 41 TechProjects?: ITechProjectDatabase[];
42 ActiveDojoColorResearch: string;
41 43
42 44 Class: number;
43 45 XP: number;