[refactor/perf] Deduplicate HasHackedItemStacks slot checks#3215
[refactor/perf] Deduplicate HasHackedItemStacks slot checks#3215Xekep wants to merge 2 commits intoPryaxis:general-develfrom
Conversation
TShockAPI/TSPlayer.cs
Outdated
| item.netDefaults(loadout3Dye[index].type); | ||
| item.Prefix(loadout3Dye[index].prefix); | ||
| item.AffixName(); | ||
| CheckSlotStack(trash, "Stack cheat detected. Remove trash item {0} ({1}) and then rejoin.", checkNegative: false); |
There was a problem hiding this comment.
Why skip the negative stack check for the trash item?
TShockAPI/TSPlayer.cs
Outdated
| Item trash = TPlayer.trashItem; | ||
| for (int i = 0; i < NetItem.MaxInventory; i++) | ||
|
|
||
| bool CheckSlotStack(Item item, string warningMessage, bool checkNegative = true) |
There was a problem hiding this comment.
The return value doesn't seem to be used
TShockAPI/TSPlayer.cs
Outdated
| SendErrorMessage(GetString("Stack cheat detected. Remove dye {0} ({1}) and then rejoin.", item.Name, dye[index].stack)); | ||
| } | ||
| } | ||
| SendErrorMessage(GetString(warningMessage, item.Name, item.stack)); |
There was a problem hiding this comment.
GetString should be used on the raw strings directly for strings extraction, not inside the helper method.
There was a problem hiding this comment.
Thanks, fair points.
-
About
checkNegative: falsefor trash:
I left it this way on purpose to keep old behavior. Before refactor, trash only checkedstack > maxStack(no negative check). I added a comment to make that explicit. If you want, I can change this too, but I’d prefer a separate PR since that’s behavior-changing. -
About
CheckSlotStackreturn value:
Yep, agreed - leftover from the first refactor. I changed it tovoidin85e1f323. -
About
GetString:
Also agreed. I moved messages to directGetString("...")calls on raw literals, then pass the localized format into the helper. No nestedGetStringnow. Included in85e1f323.
|
i try your all pr and i get bug when use this pr player stuck in requesting tile data |
|
no plugin installed (need someone to test it too) to validate my issue |
|
@greptile review |
Greptile SummaryThis PR refactors Critical Issue:
What needs to be fixed:
Confidence Score: 1/5
Important Files Changed
Last reviewed commit: 85e1f32 |
| if (item == null || item.type == 0) | ||
| return; | ||
|
|
||
| if (item.stack > item.maxStack || (checkNegative && item.stack < 0)) |
There was a problem hiding this comment.
Critical security issue: directly using item.maxStack breaks the established validation pattern used throughout TShock
The old code created a fresh Item and called netDefaults() to get server-authoritative maxStack:
Item item = new Item();
item.netDefaults(inventory[i].type);
if (inventory[i].stack > item.maxStack || inventory[i].stack < 0)This same pattern is used in:
Bouncer.cs:1232-1234(OnItemDrop validation)GetDataHandlers.cs:3346-3352(HandleChestItem validation)
The refactored code uses item.maxStack from the player's item directly. If a hacked client modifies both stack AND maxStack on their items, this check will fail to detect the cheat.
Fix: Restore the netDefaults pattern:
void CheckSlotStack(Item playerItem, string warningMessage, bool checkNegative = true)
{
if (playerItem == null || playerItem.type == 0)
return;
Item referenceItem = new Item();
referenceItem.netDefaults(playerItem.type);
if (playerItem.stack > referenceItem.maxStack || (checkNegative && playerItem.stack < 0))
{
check = true;
if (shouldWarnPlayer)
{
SendErrorMessage(warningMessage, referenceItem.Name, playerItem.stack);
}
}
}
Summary
Scope