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(webui): add "add missing warframes" & "add missing weapons" (#775)

215b8397
Sainan <sainan@calamity.inc>
提交于

代码差异

6 个文件 +116 -106
Deleted src/controllers/custom/addItemController.ts +0 -33
@@ -1,33 +0,0 @@
1 import { getAccountIdForRequest } from "@/src/services/loginService";
2 import { ItemType, toAddItemRequest } from "@/src/helpers/customHelpers/addItemHelpers";
3 import { getWeaponType } from "@/src/services/itemDataService";
4 import { addPowerSuit, addEquipment, getInventory } from "@/src/services/inventoryService";
5 import { RequestHandler } from "express";
6
7 const addItemController: RequestHandler = async (req, res) => {
8 const accountId = await getAccountIdForRequest(req);
9 const request = toAddItemRequest(req.body);
10
11 switch (request.type) {
12 case ItemType.Powersuit: {
13 const inventory = await getInventory(accountId);
14 const inventoryChanges = addPowerSuit(inventory, request.InternalName);
15 await inventory.save();
16 res.json(inventoryChanges);
17 return;
18 }
19 case ItemType.Weapon: {
20 const inventory = await getInventory(accountId);
21 const weaponType = getWeaponType(request.InternalName);
22 const inventoryChanges = addEquipment(inventory, weaponType, request.InternalName);
23 await inventory.save();
24 res.json(inventoryChanges);
25 break;
26 }
27 default:
28 res.status(400).json({ error: "something went wrong" });
29 break;
30 }
31 };
32
33 export { addItemController };
Added src/controllers/custom/addItemsController.ts +33 -0
@@ -0,0 +1,33 @@
1 import { getAccountIdForRequest } from "@/src/services/loginService";
2 import { getWeaponType } from "@/src/services/itemDataService";
3 import { addPowerSuit, addEquipment, getInventory } from "@/src/services/inventoryService";
4 import { RequestHandler } from "express";
5
6 export const addItemsController: RequestHandler = async (req, res) => {
7 const accountId = await getAccountIdForRequest(req);
8 const requests = req.body as IAddItemRequest[];
9 const inventory = await getInventory(accountId);
10 for (const request of requests) {
11 switch (request.type) {
12 case ItemType.Powersuit:
13 addPowerSuit(inventory, request.internalName);
14 break;
15
16 case ItemType.Weapon:
17 addEquipment(inventory, getWeaponType(request.internalName), request.internalName);
18 break;
19 }
20 }
21 await inventory.save();
22 res.end();
23 };
24
25 enum ItemType {
26 Powersuit = "Powersuit",
27 Weapon = "Weapon"
28 }
29
30 interface IAddItemRequest {
31 type: ItemType;
32 internalName: string;
33 }
Deleted src/helpers/customHelpers/addItemHelpers.ts +0 -46
@@ -1,46 +0,0 @@
1 import { isString } from "@/src/helpers/general";
2
3 export enum ItemType {
4 Powersuit = "Powersuit",
5 Weapon = "Weapon"
6 }
7
8 export const isItemType = (itemType: string): itemType is ItemType => {
9 return Object.keys(ItemType).includes(itemType);
10 };
11
12 const parseItemType = (itemType: unknown): ItemType => {
13 if (!itemType || !isString(itemType) || !isItemType(itemType)) {
14 throw new Error("incorrect item type");
15 }
16
17 return itemType;
18 };
19
20 interface IAddItemRequest {
21 type: ItemType;
22 InternalName: string;
23 }
24
25 const parseInternalItemName = (internalName: unknown): string => {
26 if (!isString(internalName)) {
27 throw new Error("incorrect internal name");
28 }
29
30 return internalName;
31 };
32
33 export const toAddItemRequest = (body: unknown): IAddItemRequest => {
34 if (!body || typeof body !== "object") {
35 throw new Error("incorrect or missing add item request data");
36 }
37
38 if ("type" in body && "internalName" in body) {
39 return {
40 type: parseItemType(body.type),
41 InternalName: parseInternalItemName(body.internalName)
42 };
43 }
44
45 throw new Error("malformed add item request");
46 };
Modified src/routes/custom.ts +2 -2
@@ -8,7 +8,7 @@ import { deleteAccountController } from "@/src/controllers/custom/deleteAccountC
8 8 import { renameAccountController } from "@/src/controllers/custom/renameAccountController";
9 9
10 10 import { createAccountController } from "@/src/controllers/custom/createAccountController";
11 import { addItemController } from "@/src/controllers/custom/addItemController";
11 import { addItemsController } from "@/src/controllers/custom/addItemsController";
12 12
13 13 import { getConfigDataController } from "@/src/controllers/custom/getConfigDataController";
14 14 import { updateConfigDataController } from "@/src/controllers/custom/updateConfigDataController";
@@ -23,7 +23,7 @@ customRouter.get("/deleteAccount", deleteAccountController);
23 23 customRouter.get("/renameAccount", renameAccountController);
24 24
25 25 customRouter.post("/createAccount", createAccountController);
26 customRouter.post("/addItem", addItemController);
26 customRouter.post("/addItems", addItemsController);
27 27
28 28 customRouter.get("/config", getConfigDataController);
29 29 customRouter.post("/config", updateConfigDataController);
Modified static/webui/index.html +22 -15
@@ -82,11 +82,11 @@
82 82 </form>
83 83 </div>
84 84 <div data-route="/webui/inventory" data-title="Inventory | OpenWF WebUI">
85 <p class="mb-4">
85 <p class="mb-3">
86 86 Note: Changes made here will only be reflected in-game when the game re-downloads your
87 87 inventory. Visiting the navigation should be the easiest way to trigger that.
88 88 </p>
89 <div class="card mb-4">
89 <div class="card mb-3">
90 90 <h5 class="card-header">Add Items</h5>
91 91 <form class="card-body input-group" onsubmit="doAcquireMiscItems();return false;">
92 92 <input class="form-control" id="miscitem-count" type="number" min="1" value="1" />
@@ -94,9 +94,9 @@
94 94 <button class="btn btn-primary" type="submit">Add</button>
95 95 </form>
96 96 </div>
97 <div class="row">
97 <div class="row g-3">
98 98 <div class="col-lg-6">
99 <div class="card mb-4">
99 <div class="card mb-3">
100 100 <h5 class="card-header">Warframes</h5>
101 101 <div class="card-body">
102 102 <form class="input-group mb-3" onsubmit="doAcquireWarframe();return false;">
@@ -108,9 +108,16 @@
108 108 </table>
109 109 </div>
110 110 </div>
111 <div class="card mb-3">
112 <h5 class="card-header">Bulk Actions</h5>
113 <div class="card-body">
114 <button class="btn btn-primary" onclick="addMissingWarframes();">Add Missing Warframes</button>
115 <button class="btn btn-primary" onclick="addMissingWeapons();">Add Missing Weapons</button>
116 </div>
117 </div>
111 118 </div>
112 119 <div class="col-lg-6">
113 <div class="card mb-4">
120 <div class="card mb-3">
114 121 <h5 class="card-header">Weapons</h5>
115 122 <div class="card-body">
116 123 <form class="input-group mb-3" onsubmit="doAcquireWeapon();return false;">
@@ -128,7 +135,7 @@
128 135 <div id="powersuit-route" data-route="~ /webui/powersuit/(.+)" data-title="Inventory | OpenWF WebUI">
129 136 <h3 class="mb-0"></h3>
130 137 <p class="text-body-secondary"></p>
131 <div class="card mb-4">
138 <div class="card mb-3">
132 139 <h5 class="card-header">Archon Shard Slots</h5>
133 140 <div class="card-body">
134 141 <p>You can use these unlimited slots to apply a wide range of upgrades.</p>
@@ -145,13 +152,13 @@
145 152 </div>
146 153 </div>
147 154 <div data-route="/webui/mods" data-title="Mods | OpenWF WebUI">
148 <p class="mb-4">
155 <p class="mb-3">
149 156 Note: Changes made here will only be reflected in-game when the game re-downloads your
150 157 inventory. Visiting the navigation should be the easiest way to trigger that.
151 158 </p>
152 <div class="row">
159 <div class="row g-3">
153 160 <div class="col-xxl-6">
154 <div class="card mb-4">
161 <div class="card mb-3">
155 162 <h5 class="card-header">Add Riven</h5>
156 163 <form class="card-body" onsubmit="doAcquireRiven();return false;">
157 164 <select class="form-control mb-3" id="addriven-type">
@@ -168,7 +175,7 @@
168 175 <a href="riven-tool/" target="_blank">Need help with the fingerprint?</a>
169 176 </form>
170 177 </div>
171 <div class="card mb-4">
178 <div class="card mb-3">
172 179 <h5 class="card-header">Rivens</h5>
173 180 <div class="card-body">
174 181 <table class="table table-hover w-100">
@@ -178,7 +185,7 @@
178 185 </div>
179 186 </div>
180 187 <div class="col-xxl-6">
181 <div class="card mb-4">
188 <div class="card mb-3">
182 189 <h5 class="card-header">Mods</h5>
183 190 <div class="card-body">
184 191 <form class="input-group mb-3" onsubmit="doAcquireMod();return false;">
@@ -194,9 +201,9 @@
194 201 </div>
195 202 </div>
196 203 <div data-route="/webui/cheats, /webui/settings" data-title="Cheats | OpenWF WebUI">
197 <div class="row">
204 <div class="row g-3">
198 205 <div class="col-lg-4">
199 <div class="card mb-4">
206 <div class="card mb-3">
200 207 <h5 class="card-header">Server</h5>
201 208 <div class="card-body">
202 209 <div id="server-settings-no-perms" class="d-none">
@@ -283,7 +290,7 @@
283 290 </div>
284 291 </div>
285 292 <div class="col-lg-4">
286 <div class="card mb-4">
293 <div class="card mb-3">
287 294 <h5 class="card-header">Account</h5>
288 295 <div class="card-body">
289 296 <p><button class="btn btn-primary" onclick="doUnlockAllFocusSchools();">Unlock All Focus Schools</button></p>
@@ -292,7 +299,7 @@
292 299 </div>
293 300 </div>
294 301 <div class="col-lg-4">
295 <div class="card mb-4">
302 <div class="card mb-3">
296 303 <h5 class="card-header">Client</h5>
297 304 <div id="client-cheats-nok" class="card-body">
298 305 Client cheats are currently unavailable. This could be because your client is not running or using a DLL without an HTTP interface.
Modified static/webui/script.js +59 -10
@@ -190,6 +190,7 @@ function updateInventory() {
190 190 document.getElementById("warframe-list").innerHTML = "";
191 191 data.Suits.forEach(item => {
192 192 const tr = document.createElement("tr");
193 tr.setAttribute("data-item-type", item.ItemType);
193 194 {
194 195 const td = document.createElement("td");
195 196 td.textContent = itemMap[item.ItemType]?.name ?? item.ItemType;
@@ -267,6 +268,7 @@ function updateInventory() {
267 268 ["LongGuns", "Pistols", "Melee"].forEach(category => {
268 269 data[category].forEach(item => {
269 270 const tr = document.createElement("tr");
271 tr.setAttribute("data-item-type", item.ItemType);
270 272 {
271 273 const td = document.createElement("td");
272 274 td.textContent = itemMap[item.ItemType]?.name ?? item.ItemType;
@@ -527,12 +529,14 @@ function doAcquireWarframe() {
527 529 }
528 530 revalidateAuthz(() => {
529 531 const req = $.post({
530 url: "/custom/addItem?" + window.authz,
532 url: "/custom/addItems?" + window.authz,
531 533 contentType: "application/json",
532 data: JSON.stringify({
533 type: "Powersuit",
534 internalName: uniqueName
535 })
534 data: JSON.stringify([
535 {
536 type: "Powersuit",
537 internalName: uniqueName
538 }
539 ])
536 540 });
537 541 req.done(() => {
538 542 document.getElementById("warframe-to-acquire").value = "";
@@ -553,12 +557,14 @@ function doAcquireWeapon() {
553 557 }
554 558 revalidateAuthz(() => {
555 559 const req = $.post({
556 url: "/custom/addItem?" + window.authz,
560 url: "/custom/addItems?" + window.authz,
557 561 contentType: "application/json",
558 data: JSON.stringify({
559 type: "Weapon",
560 internalName: uniqueName
561 })
562 data: JSON.stringify([
563 {
564 type: "Weapon",
565 internalName: uniqueName
566 }
567 ])
562 568 });
563 569 req.done(() => {
564 570 document.getElementById("weapon-to-acquire").value = "";
@@ -571,6 +577,49 @@ $("#weapon-to-acquire").on("input", () => {
571 577 $("#weapon-to-acquire").removeClass("is-invalid");
572 578 });
573 579
580 function dispatchAddItemsRequestsBatch(requests) {
581 revalidateAuthz(() => {
582 const req = $.post({
583 url: "/custom/addItems?" + window.authz,
584 contentType: "application/json",
585 data: JSON.stringify(requests)
586 });
587 req.done(() => {
588 updateInventory();
589 });
590 });
591 }
592
593 function addMissingWarframes() {
594 const requests = [];
595 document.querySelectorAll("#datalist-warframes option").forEach(elm => {
596 if (!document.querySelector("#warframe-list [data-item-type='" + elm.getAttribute("data-key") + "']")) {
597 requests.push({ type: "Powersuit", internalName: elm.getAttribute("data-key") });
598 }
599 });
600 if (
601 requests.length != 0 &&
602 window.confirm("Are you sure you want to add " + requests.length + " items to your account?")
603 ) {
604 dispatchAddItemsRequestsBatch(requests);
605 }
606 }
607
608 function addMissingWeapons() {
609 const requests = [];
610 document.querySelectorAll("#datalist-weapons option").forEach(elm => {
611 if (!document.querySelector("#weapon-list [data-item-type='" + elm.getAttribute("data-key") + "']")) {
612 requests.push({ type: "Weapon", internalName: elm.getAttribute("data-key") });
613 }
614 });
615 if (
616 requests.length != 0 &&
617 window.confirm("Are you sure you want to add " + requests.length + " items to your account?")
618 ) {
619 dispatchAddItemsRequestsBatch(requests);
620 }
621 }
622
574 623 function addGearExp(category, oid, xp) {
575 624 const data = {};
576 625 data[category] = [