diff --git a/Dockerfile b/Dockerfile index d65c5576e8..261ce9e499 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ # # Cosmic JAR creation stage # -FROM maven:3.8.4-openjdk-17 AS jar +FROM maven:3.9.1-eclipse-temurin-17 AS jar # Build in a separated location which won't have permissions issues. WORKDIR /opt/cosmic @@ -21,7 +21,7 @@ RUN mvn -f ./pom.xml clean package -Dmaven.test.skip -T 1C # # Server creation stage # -FROM openjdk:17.0.2 +FROM eclipse-temurin:17.0.6_10-jre # Host the server in a location that won't have permissions issues. WORKDIR /opt/server diff --git a/config.yaml b/config.yaml index a67f67f4ce..d76ff5ebb5 100644 --- a/config.yaml +++ b/config.yaml @@ -468,6 +468,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/scripts/portal/MCRevive1.js b/scripts/portal/MCrevive1.js similarity index 100% rename from scripts/portal/MCRevive1.js rename to scripts/portal/MCrevive1.js diff --git a/scripts/portal/MCRevive2.js b/scripts/portal/MCrevive2.js similarity index 100% rename from scripts/portal/MCRevive2.js rename to scripts/portal/MCrevive2.js diff --git a/scripts/portal/MCRevive3.js b/scripts/portal/MCrevive3.js similarity index 100% rename from scripts/portal/MCRevive3.js rename to scripts/portal/MCrevive3.js diff --git a/scripts/portal/MCRevive4.js b/scripts/portal/MCrevive4.js similarity index 100% rename from scripts/portal/MCRevive4.js rename to scripts/portal/MCrevive4.js diff --git a/scripts/portal/MCRevive5.js b/scripts/portal/MCrevive5.js similarity index 100% rename from scripts/portal/MCRevive5.js rename to scripts/portal/MCrevive5.js diff --git a/scripts/portal/MCRevive6.js b/scripts/portal/MCrevive6.js similarity index 100% rename from scripts/portal/MCRevive6.js rename to scripts/portal/MCrevive6.js diff --git a/src/main/java/client/Character.java b/src/main/java/client/Character.java index 11b9ada175..f5323a6152 100644 --- a/src/main/java/client/Character.java +++ b/src/main/java/client/Character.java @@ -6483,7 +6483,6 @@ public class Character extends AbstractCharacterObject { ThreadManager.getInstance().newTask(r); } - levelUpMessages(); guildUpdate(); FamilyEntry familyEntry = getFamilyEntry(); @@ -6522,94 +6521,6 @@ public class Character extends AbstractCharacterObject { return false; } } - - private void levelUpMessages() { - if (level % 5 != 0) { //Performance FTW? - return; - } - if (level == 5) { - yellowMessage("Aww, you're level 5, how cute!"); - } else if (level == 10) { - yellowMessage("Henesys Party Quest is now open to you! Head over to Henesys, find some friends, and try it out!"); - } else if (level == 15) { - yellowMessage("Half-way to your 2nd job advancement, nice work!"); - } else if (level == 20) { - yellowMessage("You can almost Kerning Party Quest!"); - } else if (level == 25) { - yellowMessage("You seem to be improving, but you are still not ready to move on to the next step."); - } else if (level == 30) { - yellowMessage("You have finally reached level 30! Try job advancing, after that try the Mushroom Castle!"); - } else if (level == 35) { - yellowMessage("Hey did you hear about this mall that opened in Kerning? Try visiting the Kerning Mall."); - } else if (level == 40) { - yellowMessage("Do @rates to see what all your rates are!"); - } else if (level == 45) { - yellowMessage("I heard that a rock and roll artist died during the grand opening of the Kerning Mall. People are naming him the Spirit of Rock."); - } else if (level == 50) { - yellowMessage("You seem to be growing very fast, would you like to test your new found strength with the mighty Zakum?"); - } else if (level == 55) { - yellowMessage("You can now try out the Ludibrium Maze Party Quest!"); - } else if (level == 60) { - yellowMessage("Feels good to be near the end of 2nd job, doesn't it?"); - } else if (level == 65) { - yellowMessage("You're only 5 more levels away from 3rd job, not bad!"); - } else if (level == 70) { - yellowMessage("I see many people wearing a teddy bear helmet. I should ask someone where they got it from."); - } else if (level == 75) { - yellowMessage("You have reached level 3 quarters!"); - } else if (level == 80) { - yellowMessage("You think you are powerful enough? Try facing horntail!"); - } else if (level == 85) { - yellowMessage("Did you know? The majority of people who hit level 85 in Cosmic don't live to be 85 years old?"); - } else if (level == 90) { - yellowMessage("Hey do you like the amusement park? I heard Spooky World is the best theme park around. I heard they sell cute teddy-bears."); - } else if (level == 95) { - yellowMessage("100% of people who hit level 95 in Cosmic don't live to be 95 years old."); - } else if (level == 100) { - yellowMessage("Mid-journey so far... You just reached level 100! Now THAT's such a feat, however to manage the 200 you will need even more passion and determination than ever! Good hunting!"); - } else if (level == 105) { - yellowMessage("Have you ever been to leafre? I heard they have dragons!"); - } else if (level == 110) { - yellowMessage("I see many people wearing a teddy bear helmet. I should ask someone where they got it from."); - } else if (level == 115) { - yellowMessage("I bet all you can think of is level 120, huh? Level 115 gets no love."); - } else if (level == 120) { - yellowMessage("Are you ready to learn from the masters? Head over to your job instructor!"); - } else if (level == 125) { - yellowMessage("The struggle for mastery books has begun, huh?"); - } else if (level == 130) { - yellowMessage("You should try Temple of Time. It should be pretty decent EXP."); - } else if (level == 135) { - yellowMessage("I hope you're still not struggling for mastery books!"); - } else if (level == 140) { - yellowMessage("You're well into 4th job at this point, great work!"); - } else if (level == 145) { - yellowMessage("Level 145 is serious business!"); - } else if (level == 150) { - yellowMessage("You have becomed quite strong, but the journey is not yet over."); - } else if (level == 155) { - yellowMessage("At level 155, Zakum should be a joke to you. Nice job!"); - } else if (level == 160) { - yellowMessage("Level 160 is pretty impressive. Try taking a picture and putting it on Instagram."); - } else if (level == 165) { - yellowMessage("At this level, you should start looking into doing some boss runs."); - } else if (level == 170) { - yellowMessage("Level 170, huh? You have the heart of a champion."); - } else if (level == 175) { - yellowMessage("You came a long way from level 1. Amazing job so far."); - } else if (level == 180) { - yellowMessage("Have you ever tried taking a boss on by yourself? It is quite difficult."); - } else if (level == 185) { - yellowMessage("Legend has it that you're a legend."); - } else if (level == 190) { - yellowMessage("You only have 10 more levels to go until you hit 200!"); - } else if (level == 195) { - yellowMessage("Nothing is stopping you at this point, level 195!"); - } else if (level == 200) { - yellowMessage("Very nicely done! You have reached the so-long dreamed LEVEL 200!!! You are truly a hero among men, cheers upon you!"); - } - } - public void setPlayerRates() { this.expRate *= GameConstants.getPlayerBonusExpRate(this.level / 20); this.mesoRate *= GameConstants.getPlayerBonusMesoRate(this.level / 20); 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 8db12fc8cd..345c135c7a 100644 --- a/src/main/java/client/processor/npc/DueyProcessor.java +++ b/src/main/java/client/processor/npc/DueyProcessor.java @@ -284,7 +284,20 @@ 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."); + log.warn("Chr {} tried to use duey with too long of a text", c.getPlayer().getName()); + c.disconnect(true, false); + return; + } if (!quick) { fee += 5000; } else if (!c.getPlayer().haveItem(ItemId.QUICK_DELIVERY_TICKET)) { diff --git a/src/main/java/client/processor/npc/StorageProcessor.java b/src/main/java/client/processor/npc/StorageProcessor.java index bd7f4333a0..6fa24a7399 100644 --- a/src/main/java/client/processor/npc/StorageProcessor.java +++ b/src/main/java/client/processor/npc/StorageProcessor.java @@ -50,6 +50,8 @@ public class StorageProcessor { ItemInformationProvider ii = ItemInformationProvider.getInstance(); Character chr = c.getPlayer(); Storage storage = chr.getStorage(); + String gmBlockedStorageMessage = "You cannot use the storage as a GM of this level."; + byte mode = p.readByte(); if (chr.getLevel() < 15) { @@ -61,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 @@ -70,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)); @@ -107,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(); @@ -120,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; @@ -173,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; @@ -208,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; } @@ -217,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; + } } diff --git a/src/main/java/config/ServerConfig.java b/src/main/java/config/ServerConfig.java index 9aae6876aa..c4c99cc958 100644 --- a/src/main/java/config/ServerConfig.java +++ b/src/main/java/config/ServerConfig.java @@ -317,6 +317,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/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) { diff --git a/src/main/java/net/server/channel/handlers/WeddingHandler.java b/src/main/java/net/server/channel/handlers/WeddingHandler.java index 1a31949e09..592d86cce4 100644 --- a/src/main/java/net/server/channel/handlers/WeddingHandler.java +++ b/src/main/java/net/server/channel/handlers/WeddingHandler.java @@ -69,7 +69,7 @@ public final class WeddingHandler extends AbstractPacketHandler { if (!item.isUntradeable()) { if (itemid == item.getItemId() && quantity <= item.getQuantity()) { newItem = item.copy(); - + newItem.setQuantity(quantity); marriage.addGiftItem(groomWishlist, newItem); InventoryManipulator.removeFromSlot(c, type, slot, quantity, false, false); @@ -161,4 +161,4 @@ public final class WeddingHandler extends AbstractPacketHandler { } } } -} \ No newline at end of file +} 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.");