You've already forked Arcturus-Morningstar-Extended
mirror of
https://github.com/duckietm/Arcturus-Morningstar-Extended.git
synced 2026-06-19 15:06:19 +00:00
Merge pull request #234 from simoleo89/fix/items-data-lookups
fix(items): harden item data lookups
This commit is contained in:
@@ -45,7 +45,7 @@ public class Item implements ISerialize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isPet(Item item) {
|
public static boolean isPet(Item item) {
|
||||||
return item.getName().toLowerCase().startsWith("a0 pet");
|
return item != null && item.getName() != null && item.getName().toLowerCase().startsWith("a0 pet");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isBot(Item item) {
|
public static boolean isBot(Item item) {
|
||||||
@@ -121,26 +121,19 @@ public class Item implements ISerialize {
|
|||||||
this.customParams = set.getString("customparams");
|
this.customParams = set.getString("customparams");
|
||||||
this.clothingOnWalk = set.getString("clothing_on_walk");
|
this.clothingOnWalk = set.getString("clothing_on_walk");
|
||||||
|
|
||||||
if (!set.getString("vending_ids").isEmpty()) {
|
int[] vendingIds = ItemDataGuard.parsePositiveIntList(set.getString("vending_ids"));
|
||||||
|
if (vendingIds.length > 0) {
|
||||||
this.vendingItems = new TIntArrayList();
|
this.vendingItems = new TIntArrayList();
|
||||||
String[] vendingIds = set.getString("vending_ids").replace(";", ",").replace(".", ",").split(",");
|
for (int vendingId : vendingIds) {
|
||||||
for (String s : vendingIds) {
|
this.vendingItems.add(vendingId);
|
||||||
this.vendingItems.add(Integer.parseInt(s.replace(" ", "")));
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
this.vendingItems = new TIntArrayList();
|
||||||
}
|
}
|
||||||
|
|
||||||
//if(this.interactionType.getType() == InteractionMultiHeight.class || this.interactionType.getType().isAssignableFrom(InteractionMultiHeight.class))
|
//if(this.interactionType.getType() == InteractionMultiHeight.class || this.interactionType.getType().isAssignableFrom(InteractionMultiHeight.class))
|
||||||
{
|
{
|
||||||
if (set.getString("multiheight").contains(";")) {
|
this.multiHeights = ItemDataGuard.parseHeights(set.getString("multiheight"));
|
||||||
String[] s = set.getString("multiheight").split(";");
|
|
||||||
this.multiHeights = new double[s.length];
|
|
||||||
|
|
||||||
for (int i = 0; i < s.length; i++) {
|
|
||||||
this.multiHeights[i] = Double.parseDouble(s[i]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.multiHeights = new double[0];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.rotations = 4;
|
this.rotations = 4;
|
||||||
@@ -254,6 +247,10 @@ public class Item implements ISerialize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getRandomVendingItem() {
|
public int getRandomVendingItem() {
|
||||||
|
if (this.vendingItems == null || this.vendingItems.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return this.vendingItems.get(Emulator.getRandom().nextInt(this.vendingItems.size()));
|
return this.vendingItems.get(Emulator.getRandom().nextInt(this.vendingItems.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,21 +270,23 @@ public class Item implements ISerialize {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serialize(ServerMessage message) {
|
public void serialize(ServerMessage message) {
|
||||||
message.appendString(this.type.code.toLowerCase());
|
message.appendString(this.type == null ? "" : this.type.code.toLowerCase());
|
||||||
|
|
||||||
if (type == FurnitureType.BADGE) {
|
if (type == FurnitureType.BADGE) {
|
||||||
message.appendString(this.customParams);
|
message.appendString(ItemDataGuard.safeString(this.customParams));
|
||||||
} else {
|
} else {
|
||||||
message.appendInt(this.spriteId);
|
message.appendInt(this.spriteId);
|
||||||
|
|
||||||
if (this.getName().contains("wallpaper_single") || this.getName().contains("floor_single") || this.getName().contains("landscape_single")) {
|
String itemName = ItemDataGuard.safeString(this.getName());
|
||||||
message.appendString(this.name.split("_")[2]);
|
if (itemName.contains("wallpaper_single") || itemName.contains("floor_single") || itemName.contains("landscape_single")) {
|
||||||
|
String[] nameParts = itemName.split("_");
|
||||||
|
message.appendString(nameParts.length > 2 ? nameParts[2] : "");
|
||||||
} else if (type == FurnitureType.ROBOT) {
|
} else if (type == FurnitureType.ROBOT) {
|
||||||
message.appendString(this.customParams);
|
message.appendString(ItemDataGuard.safeString(this.customParams));
|
||||||
} else if (name.equalsIgnoreCase("poster")) {
|
} else if (itemName.equalsIgnoreCase("poster")) {
|
||||||
message.appendString(this.customParams);
|
message.appendString(ItemDataGuard.safeString(this.customParams));
|
||||||
} else if (name.startsWith("SONG ")) {
|
} else if (itemName.startsWith("SONG ")) {
|
||||||
message.appendString(this.customParams);
|
message.appendString(ItemDataGuard.safeString(this.customParams));
|
||||||
} else {
|
} else {
|
||||||
message.appendString("");
|
message.appendString("");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package com.eu.habbo.habbohotel.items;
|
||||||
|
|
||||||
|
final class ItemDataGuard {
|
||||||
|
static final int MAX_EXTRA_DATA_LENGTH = 1000;
|
||||||
|
|
||||||
|
private ItemDataGuard() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static String safeString(String value) {
|
||||||
|
return value == null ? "" : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String normalizeExtraData(String value) {
|
||||||
|
String safe = safeString(value);
|
||||||
|
return safe.length() > MAX_EXTRA_DATA_LENGTH ? safe.substring(0, MAX_EXTRA_DATA_LENGTH) : safe;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parsePositiveInt(String value) {
|
||||||
|
try {
|
||||||
|
int parsed = Integer.parseInt(safeString(value).trim());
|
||||||
|
return parsed > 0 ? parsed : 0;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int[] parsePositiveIntList(String value) {
|
||||||
|
String safe = safeString(value).replace(";", ",").replace(".", ",");
|
||||||
|
if (safe.isBlank()) {
|
||||||
|
return new int[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] parts = safe.split(",");
|
||||||
|
int[] parsed = new int[parts.length];
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (String part : parts) {
|
||||||
|
int id = parsePositiveInt(part);
|
||||||
|
if (id > 0) {
|
||||||
|
parsed[count++] = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == parsed.length) {
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] compact = new int[count];
|
||||||
|
System.arraycopy(parsed, 0, compact, 0, count);
|
||||||
|
return compact;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double[] parseHeights(String value) {
|
||||||
|
String safe = safeString(value);
|
||||||
|
if (safe.isBlank() || !safe.contains(";")) {
|
||||||
|
return new double[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] parts = safe.split(";");
|
||||||
|
double[] parsed = new double[parts.length];
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (String part : parts) {
|
||||||
|
try {
|
||||||
|
double height = Double.parseDouble(part.trim());
|
||||||
|
if (Double.isFinite(height)) {
|
||||||
|
parsed[count++] = height;
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// Ignore malformed DB values and keep the remaining heights usable.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == parsed.length) {
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
double[] compact = new double[count];
|
||||||
|
System.arraycopy(parsed, 0, compact, 0, count);
|
||||||
|
return compact;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -566,6 +566,10 @@ public class ItemManager {
|
|||||||
|
|
||||||
|
|
||||||
public int calculateCrackState(int count, int max, Item baseItem) {
|
public int calculateCrackState(int count, int max, Item baseItem) {
|
||||||
|
if (count <= 0 || max <= 0 || baseItem == null || baseItem.getStateCount() <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return (int) Math.floor((1.0D / ((double) max / (double) count) * baseItem.getStateCount()));
|
return (int) Math.floor((1.0D / ((double) max / (double) count) * baseItem.getStateCount()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,7 +578,8 @@ public class ItemManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Item getCrackableReward(int itemId) {
|
public Item getCrackableReward(int itemId) {
|
||||||
return this.getItem(this.crackableRewards.get(itemId).getRandomReward());
|
CrackableReward reward = this.crackableRewards.get(itemId);
|
||||||
|
return reward == null ? null : this.getItem(reward.getRandomReward());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -604,6 +609,12 @@ public class ItemManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public HabboItem createItem(int habboId, Item item, int limitedStack, int limitedSells, String extraData) {
|
public HabboItem createItem(int habboId, Item item, int limitedStack, int limitedSells, String extraData) {
|
||||||
|
if (habboId <= 0 || item == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
extraData = ItemDataGuard.normalizeExtraData(extraData);
|
||||||
|
|
||||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("INSERT INTO items (user_id, item_id, extra_data, limited_data) VALUES (?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS)) {
|
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("INSERT INTO items (user_id, item_id, extra_data, limited_data) VALUES (?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS)) {
|
||||||
statement.setInt(1, habboId);
|
statement.setInt(1, habboId);
|
||||||
statement.setInt(2, item.getId());
|
statement.setInt(2, item.getId());
|
||||||
@@ -673,6 +684,12 @@ public class ItemManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public HabboItem handleRecycle(Habbo habbo, String itemId) {
|
public HabboItem handleRecycle(Habbo habbo, String itemId) {
|
||||||
|
int rewardItemId = ItemDataGuard.parsePositiveInt(itemId);
|
||||||
|
if (habbo == null || habbo.getHabboInfo() == null || rewardItemId <= 0
|
||||||
|
|| Emulator.getGameEnvironment().getCatalogManager().ecotronItem == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
String extradata = Calendar.getInstance().get(Calendar.DAY_OF_MONTH) + "-" + (Calendar.getInstance().get(Calendar.MONTH) + 1) + "-" + Calendar.getInstance().get(Calendar.YEAR);
|
String extradata = Calendar.getInstance().get(Calendar.DAY_OF_MONTH) + "-" + (Calendar.getInstance().get(Calendar.MONTH) + 1) + "-" + Calendar.getInstance().get(Calendar.YEAR);
|
||||||
|
|
||||||
HabboItem item = null;
|
HabboItem item = null;
|
||||||
@@ -686,7 +703,7 @@ public class ItemManager {
|
|||||||
try (PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO items_presents (item_id, base_item_reward) VALUES (?, ?)")) {
|
try (PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO items_presents (item_id, base_item_reward) VALUES (?, ?)")) {
|
||||||
while (set.next() && item == null) {
|
while (set.next() && item == null) {
|
||||||
preparedStatement.setInt(1, set.getInt(1));
|
preparedStatement.setInt(1, set.getInt(1));
|
||||||
preparedStatement.setInt(2, Integer.parseInt(itemId));
|
preparedStatement.setInt(2, rewardItemId);
|
||||||
preparedStatement.addBatch();
|
preparedStatement.addBatch();
|
||||||
item = new InteractionDefault(set.getInt(1), habbo.getHabboInfo().getId(), Emulator.getGameEnvironment().getCatalogManager().ecotronItem, extradata, 0, 0);
|
item = new InteractionDefault(set.getInt(1), habbo.getHabboInfo().getId(), Emulator.getGameEnvironment().getCatalogManager().ecotronItem, extradata, 0, 0);
|
||||||
}
|
}
|
||||||
@@ -829,6 +846,10 @@ public class ItemManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public HabboItem createGift(String username, Item item, String extraData, int limitedStack, int limitedSells) {
|
public HabboItem createGift(String username, Item item, String extraData, int limitedStack, int limitedSells) {
|
||||||
|
if (username == null || username.isBlank() || item == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(username);
|
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(username);
|
||||||
|
|
||||||
int userId = 0;
|
int userId = 0;
|
||||||
@@ -857,13 +878,13 @@ public class ItemManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public HabboItem createGift(int userId, Item item, String extraData, int limitedStack, int limitedSells) {
|
public HabboItem createGift(int userId, Item item, String extraData, int limitedStack, int limitedSells) {
|
||||||
if (userId == 0)
|
if (userId <= 0 || item == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (extraData.length() > 1000) {
|
if (extraData != null && extraData.length() > ItemDataGuard.MAX_EXTRA_DATA_LENGTH) {
|
||||||
LOGGER.error("Extradata exceeds maximum length of 1000 characters: {}", extraData);
|
LOGGER.error("Extradata exceeds maximum length of 1000 characters: {}", extraData);
|
||||||
extraData = extraData.substring(0, 1000);
|
|
||||||
}
|
}
|
||||||
|
extraData = ItemDataGuard.normalizeExtraData(extraData);
|
||||||
|
|
||||||
HabboItem gift = this.createItem(userId, item, limitedStack, limitedSells, extraData);
|
HabboItem gift = this.createItem(userId, item, limitedStack, limitedSells, extraData);
|
||||||
|
|
||||||
@@ -879,7 +900,7 @@ public class ItemManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Item getItem(int itemId) {
|
public Item getItem(int itemId) {
|
||||||
if (itemId < 0)
|
if (itemId <= 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return this.items.get(itemId);
|
return this.items.get(itemId);
|
||||||
@@ -890,12 +911,16 @@ public class ItemManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Item getItem(String itemName) {
|
public Item getItem(String itemName) {
|
||||||
|
if (itemName == null || itemName.isBlank()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
TIntObjectIterator<Item> item = this.items.iterator();
|
TIntObjectIterator<Item> item = this.items.iterator();
|
||||||
|
|
||||||
for (int i = this.items.size(); i-- > 0; ) {
|
for (int i = this.items.size(); i-- > 0; ) {
|
||||||
try {
|
try {
|
||||||
item.advance();
|
item.advance();
|
||||||
if (item.value().getName().equalsIgnoreCase(itemName)) {
|
if (item.value() != null && item.value().getName() != null && item.value().getName().equalsIgnoreCase(itemName)) {
|
||||||
return item.value();
|
return item.value();
|
||||||
}
|
}
|
||||||
} catch (NoSuchElementException e) {
|
} catch (NoSuchElementException e) {
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.eu.habbo.habbohotel.items;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
class ItemDataGuardTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void normalizesExtraDataToDatabaseBound() {
|
||||||
|
assertEquals("", ItemDataGuard.normalizeExtraData(null));
|
||||||
|
assertEquals(ItemDataGuard.MAX_EXTRA_DATA_LENGTH,
|
||||||
|
ItemDataGuard.normalizeExtraData("x".repeat(ItemDataGuard.MAX_EXTRA_DATA_LENGTH + 1)).length());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void parsesOnlyPositiveVendingIds() {
|
||||||
|
assertArrayEquals(new int[]{1, 2, 3}, ItemDataGuard.parsePositiveIntList("1; 2.bad,3,-4,0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void ignoresMalformedMultiHeights() {
|
||||||
|
assertArrayEquals(new double[]{0.5, 1.25}, ItemDataGuard.parseHeights("0.5;nope;Infinity;1.25"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user