feat: leveling up intrinsics #725
@ -10,7 +10,7 @@ export const playerSkillsController: RequestHandler = async (req, res) => {
|
|||||||
|
|||||||
const request = getJSONfromString(String(req.body)) as IPlayerSkillsRequest;
|
const request = getJSONfromString(String(req.body)) as IPlayerSkillsRequest;
|
||||||
|
|
||||||
![]() ⚠️ Potential issue Gracefully handle malformed JSON requests. Calling
📝 Committable suggestion
_:warning: Potential issue_
**Gracefully handle malformed JSON requests.**
Calling `getJSONfromString` directly on `req.body` might throw runtime errors if the request body is malformed or non-JSON. Consider guarding against `null` or invalid input, returning an error response if parsing fails or if required fields are missing.
```diff
- const request = getJSONfromString(String(req.body)) as IPlayerSkillsRequest;
+ let request: IPlayerSkillsRequest;
+ try {
+ request = getJSONfromString(String(req.body)) as IPlayerSkillsRequest;
+ } catch (err) {
+ return res.status(400).json({ error: "Invalid JSON format." });
+ }
```
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
`````suggestion
let request: IPlayerSkillsRequest;
try {
request = getJSONfromString(String(req.body)) as IPlayerSkillsRequest;
} catch (err) {
return res.status(400).json({ error: "Invalid JSON format." });
}
`````
</details>
<!-- suggestion_end -->
<!-- This is an auto-generated comment by CodeRabbit -->
|
|||||||
const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills];
|
const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills];
|
||||||
const cost = (1 << oldRank) * 1000;
|
const cost = (request.Pool == "LPP_DRIFTER" ? drifterCosts[oldRank] : 1 << oldRank) * 1000;
|
||||||
![]() ⚠️ Potential issue Check sufficient pool balance and skill validity.
_:warning: Potential issue_
**Check sufficient pool balance and skill validity.**
1) There's no validation to confirm the chosen pool (e.g., `RegularCredits` vs. `FusionPoints`) has enough funds to cover the `cost`. If `cost` exceeds the balance, this logic would set the pool to a negative value.
2) Also ensure that `request.Skill` is valid and actually exists in `inventory.PlayerSkills`, to avoid writing to an undefined key or misusing the cast `as keyof IPlayerSkills`.
```diff
const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills];
const cost = (1 << oldRank) * 1000;
- inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost;
- inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++;
+ // 1) Validate pool balance
+ const poolKey = request.Pool as keyof IPlayerSkills;
+ if (inventory.PlayerSkills[poolKey] < cost) {
+ return res.status(400).json({ error: "Insufficient balance in pool" });
+ }
+ // 2) Validate skill
+ const skillKey = request.Skill as keyof IPlayerSkills;
+ if (typeof inventory.PlayerSkills[skillKey] !== "number") {
+ return res.status(400).json({ error: "Invalid skill name" });
+ }
+
+ // Safe to update
+ inventory.PlayerSkills[poolKey] -= cost;
+ inventory.PlayerSkills[skillKey]++;
```
> Committable suggestion skipped: line range outside the PR's diff.
<!-- This is an auto-generated comment by CodeRabbit -->
![]() ⚠️ Potential issue Check sufficient pool balance and skill validity.
_:warning: Potential issue_
**Check sufficient pool balance and skill validity.**
1) There's no validation to confirm the chosen pool (e.g., `RegularCredits` vs. `FusionPoints`) has enough funds to cover the `cost`. If `cost` exceeds the balance, this logic would set the pool to a negative value.
2) Also ensure that `request.Skill` is valid and actually exists in `inventory.PlayerSkills`, to avoid writing to an undefined key or misusing the cast `as keyof IPlayerSkills`.
```diff
const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills];
const cost = (1 << oldRank) * 1000;
- inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost;
- inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++;
+ // 1) Validate pool balance
+ const poolKey = request.Pool as keyof IPlayerSkills;
+ if (inventory.PlayerSkills[poolKey] < cost) {
+ return res.status(400).json({ error: "Insufficient balance in pool" });
+ }
+ // 2) Validate skill
+ const skillKey = request.Skill as keyof IPlayerSkills;
+ if (typeof inventory.PlayerSkills[skillKey] !== "number") {
+ return res.status(400).json({ error: "Invalid skill name" });
+ }
+
+ // Safe to update
+ inventory.PlayerSkills[poolKey] -= cost;
+ inventory.PlayerSkills[skillKey]++;
```
> Committable suggestion skipped: line range outside the PR's diff.
<!-- This is an auto-generated comment by CodeRabbit -->
![]() ⚠️ Potential issue Add bounds checking for drifterCosts array access. When accessing
📝 Committable suggestion
_:warning: Potential issue_
**Add bounds checking for drifterCosts array access.**
When accessing `drifterCosts[oldRank]`, there's no validation to ensure `oldRank` is within array bounds (0-9). This could lead to undefined behavior if the rank exceeds the maximum level.
```diff
- const cost = (request.Pool == "LPP_DRIFTER" ? drifterCosts[oldRank] : 1 << oldRank) * 1000;
+ if (request.Pool === "LPP_DRIFTER" && (oldRank < 0 || oldRank >= drifterCosts.length)) {
+ return res.status(400).json({ error: `Invalid rank ${oldRank}. Maximum rank is ${drifterCosts.length - 1}` });
+ }
+ const cost = (request.Pool === "LPP_DRIFTER" ? drifterCosts[oldRank] : 1 << oldRank) * 1000;
```
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
`````suggestion
if (request.Pool === "LPP_DRIFTER" && (oldRank < 0 || oldRank >= drifterCosts.length)) {
return res.status(400).json({ error: `Invalid rank ${oldRank}. Maximum rank is ${drifterCosts.length - 1}` });
}
const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills];
const cost = (request.Pool === "LPP_DRIFTER" ? drifterCosts[oldRank] : 1 << oldRank) * 1000;
`````
</details>
<!-- suggestion_end -->
<!-- This is an auto-generated comment by CodeRabbit -->
|
|||||||
inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost;
|
inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost;
|
||||||
inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++;
|
inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++;
|
||||||
![]() ⚠️ Potential issue Prevent negative costs and add maximum rank validation. The current implementation lacks validation for:
📝 Committable suggestion
_:warning: Potential issue_
**Prevent negative costs and add maximum rank validation.**
The current implementation lacks validation for:
1. Maximum rank for non-Drifter skills (Railjack goes up to rank 9)
2. Negative costs that could occur from integer overflow
```diff
- const cost = (request.Pool === "LPP_DRIFTER" ? drifterCosts[oldRank] : 1 << oldRank) * 1000;
- inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost;
- inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++;
+ // Maximum rank for non-Drifter skills
+ if (request.Pool !== "LPP_DRIFTER" && oldRank >= 9) {
+ return res.status(400).json({ error: "Maximum rank reached" });
+ }
+
+ const baseCost = request.Pool === "LPP_DRIFTER" ? drifterCosts[oldRank] : 1 << oldRank;
+ const cost = baseCost * 1000;
+
+ // Prevent integer overflow leading to negative costs
+ if (cost <= 0) {
+ return res.status(400).json({ error: "Invalid cost calculation" });
+ }
+
+ const poolKey = request.Pool as keyof IPlayerSkills;
+ const skillKey = request.Skill as keyof IPlayerSkills;
+
+ inventory.PlayerSkills[poolKey] -= cost;
+ inventory.PlayerSkills[skillKey]++;
```
<!-- suggestion_start -->
<details>
<summary>📝 Committable suggestion</summary>
> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
`````suggestion
// Maximum rank for non-Drifter skills
if (request.Pool !== "LPP_DRIFTER" && oldRank >= 9) {
return res.status(400).json({ error: "Maximum rank reached" });
}
const baseCost = request.Pool === "LPP_DRIFTER" ? drifterCosts[oldRank] : 1 << oldRank;
const cost = baseCost * 1000;
// Prevent integer overflow leading to negative costs
if (cost <= 0) {
return res.status(400).json({ error: "Invalid cost calculation" });
}
const poolKey = request.Pool as keyof IPlayerSkills;
const skillKey = request.Skill as keyof IPlayerSkills;
inventory.PlayerSkills[poolKey] -= cost;
inventory.PlayerSkills[skillKey]++;
`````
</details>
<!-- suggestion_end -->
<!-- This is an auto-generated comment by CodeRabbit -->
|
|||||||
await inventory.save();
|
await inventory.save();
|
||||||
@ -27,3 +27,5 @@ interface IPlayerSkillsRequest {
|
|||||||
![]() ⚠️ Potential issue Check sufficient pool balance and skill validity.
_:warning: Potential issue_
**Check sufficient pool balance and skill validity.**
1) There's no validation to confirm the chosen pool (e.g., `RegularCredits` vs. `FusionPoints`) has enough funds to cover the `cost`. If `cost` exceeds the balance, this logic would set the pool to a negative value.
2) Also ensure that `request.Skill` is valid and actually exists in `inventory.PlayerSkills`, to avoid writing to an undefined key or misusing the cast `as keyof IPlayerSkills`.
```diff
const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills];
const cost = (1 << oldRank) * 1000;
- inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost;
- inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++;
+ // 1) Validate pool balance
+ const poolKey = request.Pool as keyof IPlayerSkills;
+ if (inventory.PlayerSkills[poolKey] < cost) {
+ return res.status(400).json({ error: "Insufficient balance in pool" });
+ }
+ // 2) Validate skill
+ const skillKey = request.Skill as keyof IPlayerSkills;
+ if (typeof inventory.PlayerSkills[skillKey] !== "number") {
+ return res.status(400).json({ error: "Invalid skill name" });
+ }
+
+ // Safe to update
+ inventory.PlayerSkills[poolKey] -= cost;
+ inventory.PlayerSkills[skillKey]++;
```
> Committable suggestion skipped: line range outside the PR's diff.
<!-- This is an auto-generated comment by CodeRabbit -->
![]() ⚠️ Potential issue Check sufficient pool balance and skill validity.
_:warning: Potential issue_
**Check sufficient pool balance and skill validity.**
1) There's no validation to confirm the chosen pool (e.g., `RegularCredits` vs. `FusionPoints`) has enough funds to cover the `cost`. If `cost` exceeds the balance, this logic would set the pool to a negative value.
2) Also ensure that `request.Skill` is valid and actually exists in `inventory.PlayerSkills`, to avoid writing to an undefined key or misusing the cast `as keyof IPlayerSkills`.
```diff
const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills];
const cost = (1 << oldRank) * 1000;
- inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost;
- inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++;
+ // 1) Validate pool balance
+ const poolKey = request.Pool as keyof IPlayerSkills;
+ if (inventory.PlayerSkills[poolKey] < cost) {
+ return res.status(400).json({ error: "Insufficient balance in pool" });
+ }
+ // 2) Validate skill
+ const skillKey = request.Skill as keyof IPlayerSkills;
+ if (typeof inventory.PlayerSkills[skillKey] !== "number") {
+ return res.status(400).json({ error: "Invalid skill name" });
+ }
+
+ // Safe to update
+ inventory.PlayerSkills[poolKey] -= cost;
+ inventory.PlayerSkills[skillKey]++;
```
> Committable suggestion skipped: line range outside the PR's diff.
<!-- This is an auto-generated comment by CodeRabbit -->
|
|||||||
Pool: string;
|
Pool: string;
|
||||||
Skill: string;
|
Skill: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
![]() ⚠️ Potential issue Check sufficient pool balance and skill validity.
_:warning: Potential issue_
**Check sufficient pool balance and skill validity.**
1) There's no validation to confirm the chosen pool (e.g., `RegularCredits` vs. `FusionPoints`) has enough funds to cover the `cost`. If `cost` exceeds the balance, this logic would set the pool to a negative value.
2) Also ensure that `request.Skill` is valid and actually exists in `inventory.PlayerSkills`, to avoid writing to an undefined key or misusing the cast `as keyof IPlayerSkills`.
```diff
const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills];
const cost = (1 << oldRank) * 1000;
- inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost;
- inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++;
+ // 1) Validate pool balance
+ const poolKey = request.Pool as keyof IPlayerSkills;
+ if (inventory.PlayerSkills[poolKey] < cost) {
+ return res.status(400).json({ error: "Insufficient balance in pool" });
+ }
+ // 2) Validate skill
+ const skillKey = request.Skill as keyof IPlayerSkills;
+ if (typeof inventory.PlayerSkills[skillKey] !== "number") {
+ return res.status(400).json({ error: "Invalid skill name" });
+ }
+
+ // Safe to update
+ inventory.PlayerSkills[poolKey] -= cost;
+ inventory.PlayerSkills[skillKey]++;
```
> Committable suggestion skipped: line range outside the PR's diff.
<!-- This is an auto-generated comment by CodeRabbit -->
|
|||||||
|
const drifterCosts = [20, 25, 30, 45, 65, 90, 125, 160, 205, 255];
|
||||||
![]() ⚠️ Potential issue Check sufficient pool balance and skill validity.
_:warning: Potential issue_
**Check sufficient pool balance and skill validity.**
1) There's no validation to confirm the chosen pool (e.g., `RegularCredits` vs. `FusionPoints`) has enough funds to cover the `cost`. If `cost` exceeds the balance, this logic would set the pool to a negative value.
2) Also ensure that `request.Skill` is valid and actually exists in `inventory.PlayerSkills`, to avoid writing to an undefined key or misusing the cast `as keyof IPlayerSkills`.
```diff
const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills];
const cost = (1 << oldRank) * 1000;
- inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost;
- inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++;
+ // 1) Validate pool balance
+ const poolKey = request.Pool as keyof IPlayerSkills;
+ if (inventory.PlayerSkills[poolKey] < cost) {
+ return res.status(400).json({ error: "Insufficient balance in pool" });
+ }
+ // 2) Validate skill
+ const skillKey = request.Skill as keyof IPlayerSkills;
+ if (typeof inventory.PlayerSkills[skillKey] !== "number") {
+ return res.status(400).json({ error: "Invalid skill name" });
+ }
+
+ // Safe to update
+ inventory.PlayerSkills[poolKey] -= cost;
+ inventory.PlayerSkills[skillKey]++;
```
> Committable suggestion skipped: line range outside the PR's diff.
<!-- This is an auto-generated comment by CodeRabbit -->
|
|||||||
|
|||||||
![]() ⚠️ Potential issue Check sufficient pool balance and skill validity.
_:warning: Potential issue_
**Check sufficient pool balance and skill validity.**
1) There's no validation to confirm the chosen pool (e.g., `RegularCredits` vs. `FusionPoints`) has enough funds to cover the `cost`. If `cost` exceeds the balance, this logic would set the pool to a negative value.
2) Also ensure that `request.Skill` is valid and actually exists in `inventory.PlayerSkills`, to avoid writing to an undefined key or misusing the cast `as keyof IPlayerSkills`.
```diff
const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills];
const cost = (1 << oldRank) * 1000;
- inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost;
- inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++;
+ // 1) Validate pool balance
+ const poolKey = request.Pool as keyof IPlayerSkills;
+ if (inventory.PlayerSkills[poolKey] < cost) {
+ return res.status(400).json({ error: "Insufficient balance in pool" });
+ }
+ // 2) Validate skill
+ const skillKey = request.Skill as keyof IPlayerSkills;
+ if (typeof inventory.PlayerSkills[skillKey] !== "number") {
+ return res.status(400).json({ error: "Invalid skill name" });
+ }
+
+ // Safe to update
+ inventory.PlayerSkills[poolKey] -= cost;
+ inventory.PlayerSkills[skillKey]++;
```
> Committable suggestion skipped: line range outside the PR's diff.
<!-- This is an auto-generated comment by CodeRabbit -->
![]() ⚠️ Potential issue Check sufficient pool balance and skill validity.
_:warning: Potential issue_
**Check sufficient pool balance and skill validity.**
1) There's no validation to confirm the chosen pool (e.g., `RegularCredits` vs. `FusionPoints`) has enough funds to cover the `cost`. If `cost` exceeds the balance, this logic would set the pool to a negative value.
2) Also ensure that `request.Skill` is valid and actually exists in `inventory.PlayerSkills`, to avoid writing to an undefined key or misusing the cast `as keyof IPlayerSkills`.
```diff
const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills];
const cost = (1 << oldRank) * 1000;
- inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost;
- inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++;
+ // 1) Validate pool balance
+ const poolKey = request.Pool as keyof IPlayerSkills;
+ if (inventory.PlayerSkills[poolKey] < cost) {
+ return res.status(400).json({ error: "Insufficient balance in pool" });
+ }
+ // 2) Validate skill
+ const skillKey = request.Skill as keyof IPlayerSkills;
+ if (typeof inventory.PlayerSkills[skillKey] !== "number") {
+ return res.status(400).json({ error: "Invalid skill name" });
+ }
+
+ // Safe to update
+ inventory.PlayerSkills[poolKey] -= cost;
+ inventory.PlayerSkills[skillKey]++;
```
> Committable suggestion skipped: line range outside the PR's diff.
<!-- This is an auto-generated comment by CodeRabbit -->
|
⚠️ Potential issue
Check sufficient pool balance and skill validity.
RegularCredits
vs.FusionPoints
) has enough funds to cover thecost
. Ifcost
exceeds the balance, this logic would set the pool to a negative value.request.Skill
is valid and actually exists ininventory.PlayerSkills
, to avoid writing to an undefined key or misusing the castas keyof IPlayerSkills
.⚠️ Potential issue
Check sufficient pool balance and skill validity.
RegularCredits
vs.FusionPoints
) has enough funds to cover thecost
. Ifcost
exceeds the balance, this logic would set the pool to a negative value.request.Skill
is valid and actually exists ininventory.PlayerSkills
, to avoid writing to an undefined key or misusing the castas keyof IPlayerSkills
.