From 4546fd44ffb52724449a646342fb341ce59f3ff4 Mon Sep 17 00:00:00 2001 From: Matthew Hinds Date: Fri, 12 May 2023 18:02:08 +1200 Subject: [PATCH 1/3] To prevent abuse, GMs should be permission restricted (via GM level) to trade with other non GM players, use their storage (prevent transferring to their other characters), send via Duey and to drop items. GM level is configurable. --- config.yaml | 6 ++++++ .../manipulator/InventoryManipulator.java | 6 ++++++ .../java/client/processor/npc/DueyProcessor.java | 7 +++++++ .../client/processor/npc/StorageProcessor.java | 7 +++++++ src/main/java/config/ServerConfig.java | 6 ++++++ src/main/java/server/Trade.java | 14 ++++++++++++++ 6 files changed, 46 insertions(+) diff --git a/config.yaml b/config.yaml index 835fe88b93..3fae109d3c 100644 --- a/config.yaml +++ b/config.yaml @@ -461,6 +461,12 @@ server: #Event End Timestamp EVENT_END_TIMESTAMP: 1428897600000 + # GM Security Configuration + MINIMUM_GM_LEVEL_TO_TRADE: 4 + MINIMUM_GM_LEVEL_TO_USE_STORAGE: 4 + MINIMUM_GM_LEVEL_TO_USE_DUEY: 4 + MINIMUM_GM_LEVEL_TO_DROP: 4 + #Any NPC ids that should search for a js override script (useful if they already have wz entries since otherwise they're ignored). NPCS_SCRIPTABLE: #9200000: Talk to Cody # Cody diff --git a/src/main/java/client/inventory/manipulator/InventoryManipulator.java b/src/main/java/client/inventory/manipulator/InventoryManipulator.java index 98f6fc3f19..331a7061b0 100644 --- a/src/main/java/client/inventory/manipulator/InventoryManipulator.java +++ b/src/main/java/client/inventory/manipulator/InventoryManipulator.java @@ -706,6 +706,12 @@ public class InventoryManipulator { Inventory inv = chr.getInventory(type); Item source = inv.getItem(src); + if (chr.isGM() && chr.gmLevel() < YamlConfig.config.server.MINIMUM_GM_LEVEL_TO_DROP) { + chr.message("You cannot drop items at your GM level."); + log.info("GM %s tried to drop item id %d", chr.getName(), source.getItemId()); + return; + } + if (chr.getTrade() != null || chr.getMiniGame() != null || source == null) { //Only check needed would prob be merchants (to see if the player is in one) return; } diff --git a/src/main/java/client/processor/npc/DueyProcessor.java b/src/main/java/client/processor/npc/DueyProcessor.java index 1633e99b71..345c135c7a 100644 --- a/src/main/java/client/processor/npc/DueyProcessor.java +++ b/src/main/java/client/processor/npc/DueyProcessor.java @@ -284,6 +284,13 @@ public class DueyProcessor { public static void dueySendItem(Client c, byte invTypeId, short itemPos, short amount, int sendMesos, String sendMessage, String recipient, boolean quick) { if (c.tryacquireClient()) { try { + if (c.getPlayer().isGM() && c.getPlayer().gmLevel() < YamlConfig.config.server.MINIMUM_GM_LEVEL_TO_USE_DUEY) { + c.getPlayer().message("You cannot use Duey to send items at your GM level."); + log.info(String.format("GM %s tried to send a package to %s", c.getPlayer().getName(), recipient)); + c.sendPacket(PacketCreator.sendDueyMSG(DueyProcessor.Actions.TOCLIENT_SEND_INCORRECT_REQUEST.getCode())); + return; + } + int fee = Trade.getFee(sendMesos); if (sendMessage != null && sendMessage.length() > 100) { AutobanFactory.PACKET_EDIT.alert(c.getPlayer(), c.getPlayer().getName() + " tried to packet edit with Quick Delivery on duey."); diff --git a/src/main/java/client/processor/npc/StorageProcessor.java b/src/main/java/client/processor/npc/StorageProcessor.java index bd7f4333a0..6bfc55f001 100644 --- a/src/main/java/client/processor/npc/StorageProcessor.java +++ b/src/main/java/client/processor/npc/StorageProcessor.java @@ -52,6 +52,13 @@ public class StorageProcessor { Storage storage = chr.getStorage(); byte mode = p.readByte(); + if (chr.isGM() && chr.gmLevel() < YamlConfig.config.server.MINIMUM_GM_LEVEL_TO_USE_STORAGE) { + chr.dropMessage(1, "You cannot use the storage as a GM of this level."); + log.info(String.format("GM %s blocked from placing items in storage", chr.getName())); + c.sendPacket(PacketCreator.enableActions()); + return; + } + if (chr.getLevel() < 15) { chr.dropMessage(1, "You may only use the storage once you have reached level 15."); c.sendPacket(PacketCreator.enableActions()); diff --git a/src/main/java/config/ServerConfig.java b/src/main/java/config/ServerConfig.java index 064599729a..499ac738ef 100644 --- a/src/main/java/config/ServerConfig.java +++ b/src/main/java/config/ServerConfig.java @@ -309,6 +309,12 @@ public class ServerConfig { //Event End Timestamp public long EVENT_END_TIMESTAMP; + //GM Security Configuration + public int MINIMUM_GM_LEVEL_TO_TRADE; + public int MINIMUM_GM_LEVEL_TO_USE_STORAGE; + public int MINIMUM_GM_LEVEL_TO_USE_DUEY; + public int MINIMUM_GM_LEVEL_TO_DROP; + //Custom NPC overrides. List of NPC IDs. public Map NPCS_SCRIPTABLE = new HashMap<>(); } diff --git a/src/main/java/server/Trade.java b/src/main/java/server/Trade.java index 2f95cb9219..9233d57426 100644 --- a/src/main/java/server/Trade.java +++ b/src/main/java/server/Trade.java @@ -448,6 +448,20 @@ public class Trade { } public static void inviteTrade(Character c1, Character c2) { + + if ((c1.isGM() && !c2.isGM()) && c1.gmLevel() < YamlConfig.config.server.MINIMUM_GM_LEVEL_TO_TRADE) { + c1.message("You cannot trade with non-GM characters."); + log.info(String.format("GM %s blocked from trading with %s due to GM level.", c1.getName(), c2.getName())); + cancelTrade(c1, TradeResult.NO_RESPONSE); + return; + } + + if ((!c1.isGM() && c2.isGM()) && c2.gmLevel() < YamlConfig.config.server.MINIMUM_GM_LEVEL_TO_TRADE) { + c1.message("You cannot trade with this GM character."); + cancelTrade(c1, TradeResult.NO_RESPONSE); + return; + } + if (InviteCoordinator.hasInvite(InviteType.TRADE, c1.getId())) { if (hasTradeInviteBack(c1, c2)) { c1.message("You are already managing this player's trade invitation."); From a9d92b78a271436872408241b22bf04d135642f2 Mon Sep 17 00:00:00 2001 From: Matthew Hinds Date: Mon, 29 May 2023 12:57:01 +1200 Subject: [PATCH 2/3] Meso drop restricted by GM level --- .../java/net/server/channel/handlers/MesoDropHandler.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/net/server/channel/handlers/MesoDropHandler.java b/src/main/java/net/server/channel/handlers/MesoDropHandler.java index 2c8254aed7..f99c7edbee 100644 --- a/src/main/java/net/server/channel/handlers/MesoDropHandler.java +++ b/src/main/java/net/server/channel/handlers/MesoDropHandler.java @@ -23,6 +23,7 @@ package net.server.channel.handlers; import client.Character; import client.Client; +import config.YamlConfig; import net.AbstractPacketHandler; import net.packet.InPacket; import tools.PacketCreator; @@ -42,6 +43,11 @@ public final class MesoDropHandler extends AbstractPacketHandler { p.skip(4); int meso = p.readInt(); + if (player.isGM() && player.gmLevel() < YamlConfig.config.server.MINIMUM_GM_LEVEL_TO_DROP) { + player.message("You cannot drop mesos at your GM level."); + return; + } + if (c.tryacquireClient()) { // thanks imbee for noticing players not being able to throw mesos too fast try { if (meso <= player.getMeso() && meso > 9 && meso < 50001) { From 95bf0473f3f2fafcb8c26fb7c242ea552b437247 Mon Sep 17 00:00:00 2001 From: Matthew Hinds Date: Mon, 29 May 2023 14:32:01 +1200 Subject: [PATCH 3/3] Adjusted based on feedback --- .../processor/npc/StorageProcessor.java | 48 ++++++++++++++----- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/src/main/java/client/processor/npc/StorageProcessor.java b/src/main/java/client/processor/npc/StorageProcessor.java index 6bfc55f001..6fa24a7399 100644 --- a/src/main/java/client/processor/npc/StorageProcessor.java +++ b/src/main/java/client/processor/npc/StorageProcessor.java @@ -50,14 +50,9 @@ public class StorageProcessor { ItemInformationProvider ii = ItemInformationProvider.getInstance(); Character chr = c.getPlayer(); Storage storage = chr.getStorage(); - byte mode = p.readByte(); + String gmBlockedStorageMessage = "You cannot use the storage as a GM of this level."; - if (chr.isGM() && chr.gmLevel() < YamlConfig.config.server.MINIMUM_GM_LEVEL_TO_USE_STORAGE) { - chr.dropMessage(1, "You cannot use the storage as a GM of this level."); - log.info(String.format("GM %s blocked from placing items in storage", chr.getName())); - c.sendPacket(PacketCreator.enableActions()); - return; - } + byte mode = p.readByte(); if (chr.getLevel() < 15) { chr.dropMessage(1, "You may only use the storage once you have reached level 15."); @@ -68,7 +63,7 @@ public class StorageProcessor { if (c.tryacquireClient()) { try { switch (mode) { - case 4: { // take out + case 4: { // Take out byte type = p.readByte(); byte slot = p.readByte(); if (slot < 0 || slot > storage.getSlots()) { // removal starts at zero @@ -77,8 +72,17 @@ public class StorageProcessor { c.disconnect(true, false); return; } + slot = storage.getSlot(InventoryType.getByType(type), slot); Item item = storage.getItem(slot); + + if (hasGMRestrictions(chr)) { + chr.dropMessage(1, gmBlockedStorageMessage); + log.info(String.format("GM %s blocked from using storage", chr.getName())); + chr.sendPacket(PacketCreator.enableActions()); + return; + } + if (item != null) { if (ii.isPickupRestricted(item.getItemId()) && chr.haveItemWithId(item.getItemId(), true)) { c.sendPacket(PacketCreator.getStorageError((byte) 0x0C)); @@ -114,7 +118,7 @@ public class StorageProcessor { } break; } - case 5: { // store + case 5: { // Store short slot = p.readShort(); int itemId = p.readInt(); short quantity = p.readShort(); @@ -127,6 +131,14 @@ public class StorageProcessor { c.disconnect(true, false); return; } + + if (hasGMRestrictions(chr)) { + chr.dropMessage(1, gmBlockedStorageMessage); + log.info(String.format("GM %s blocked from using storage", chr.getName())); + chr.sendPacket(PacketCreator.enableActions()); + return; + } + if (quantity < 1) { c.sendPacket(PacketCreator.enableActions()); return; @@ -180,16 +192,24 @@ public class StorageProcessor { } break; } - case 6: // arrange items + case 6: // Arrange items if (YamlConfig.config.server.USE_STORAGE_ITEM_SORT) { storage.arrangeItems(c); } c.sendPacket(PacketCreator.enableActions()); break; - case 7: { // meso + case 7: { // Mesos int meso = p.readInt(); int storageMesos = storage.getMeso(); int playerMesos = chr.getMeso(); + + if (hasGMRestrictions(chr)) { + chr.dropMessage(1, gmBlockedStorageMessage); + log.info(String.format("GM %s blocked from using storage", chr.getName())); + chr.sendPacket(PacketCreator.enableActions()); + return; + } + if ((meso > 0 && storageMesos >= meso) || (meso < 0 && playerMesos >= -meso)) { if (meso < 0 && (storageMesos - meso) < 0) { meso = Integer.MIN_VALUE + storageMesos; @@ -215,7 +235,7 @@ public class StorageProcessor { } break; } - case 8: // close... unless the player decides to enter cash shop! + case 8: // Close (unless the player decides to enter cash shop) storage.close(); break; } @@ -224,4 +244,8 @@ public class StorageProcessor { } } } + + private static boolean hasGMRestrictions(Character character) { + return character.isGM() && character.gmLevel() < YamlConfig.config.server.MINIMUM_GM_LEVEL_TO_USE_STORAGE; + } }