From 45ca7009c8322bed2951409fe16c9ec4415fd423 Mon Sep 17 00:00:00 2001 From: James McDowell Date: Sun, 16 May 2021 10:32:51 +1000 Subject: [PATCH 01/14] Updated to allow a generic rebirth npc id to be passed through and used for rebirthing if it's enabled. --- config.yaml | 1 + scripts/npc/9010021.js | 46 ++----------- scripts/npc/rebirth.js | 66 +++++++++++++++++++ src/main/java/config/ServerConfig.java | 1 + .../channel/handlers/NPCTalkHandler.java | 2 + 5 files changed, 74 insertions(+), 42 deletions(-) create mode 100644 scripts/npc/rebirth.js diff --git a/config.yaml b/config.yaml index 34a13ef794..e3a5fc5f2f 100644 --- a/config.yaml +++ b/config.yaml @@ -319,6 +319,7 @@ server: NAME_CHANGE_COOLDOWN: 2592000000 # (30*24*60*60*1000) Cooldown for name changes, default (GMS) is 30 days. WORLD_TRANSFER_COOLDOWN: 2592000000 # (30*24*60*60*1000) Cooldown for world tranfers, default is same as name change (30 days). INSTANT_NAME_CHANGE: false #Whether or not to wait for server restart to apply name changes. Does on reconnect otherwise (requires queries on every login). + REBIRTH_NPC_ID: 9010021 #ID of the NPC that should be replaced with the rebirth mechanic, if enabled. #Dangling Items/Locks Configuration ITEM_EXPIRE_TIME: 180000 # (3 * 60 * 1000) Time before items start disappearing. Recommended to be set up to 3 minutes. diff --git a/scripts/npc/9010021.js b/scripts/npc/9010021.js index 0abd074218..8899b84e00 100644 --- a/scripts/npc/9010021.js +++ b/scripts/npc/9010021.js @@ -21,47 +21,9 @@ */ /* 9010021 - Wolf Spirit Ryko @author Ronan - */ - var status; - + @author wejrox +*/ function start() { - status = -1; - if (!Packages.config.YamlConfig.config.server.USE_REBIRTH_SYSTEM) { - cm.sendOk("... I came from distant planes to assist the fight against the #rBlack Magician#k. Right now I search my master, have you seen him?"); - cm.dispose(); - return; - } - action(1, 0, 0); -} - -function action(mode, type, selection) { - if (mode == 1) { - status++; - } else { - cm.dispose(); - return; - } - if (status == 0) { - cm.sendNext("Come to me when you want to be reborn again. You currently have a total of #r" + cm.getChar().getReborns() + " #krebirths."); - } else if (status == 1) { - cm.sendSimple("What do you want me to do today: \r\n \r\n #L0##bI want to be rebirthed#l \r\n #L1##bMaybe next time#k#l"); - } else if (status == 2) { - if (selection == 0) { - if (cm.getChar().getLevel() == 200) { - cm.sendYesNo("Are you sure you want to be rebirthed?"); - } else { - cm.sendOk("You are not level 200, please come back when you hit level 200."); - cm.dispose(); - } - } else if (selection == 1) { - cm.sendOk("Ok Bye") - cm.dispose(); - } - } else if (status == 3 && type == 1) { - cm.getChar().executeReborn(); - cm.sendOk("You have now been reborn. That's a total of #r" + cm.getChar().getReborns() + "#k rebirths"); - cm.dispose(); - } - - + cm.sendOk("... I came from distant planes to assist the fight against the #rBlack Magician#k. Right now I search my master, have you seen him?"); + cm.dispose(); } \ No newline at end of file diff --git a/scripts/npc/rebirth.js b/scripts/npc/rebirth.js new file mode 100644 index 0000000000..c32670e46a --- /dev/null +++ b/scripts/npc/rebirth.js @@ -0,0 +1,66 @@ +/* + This file is part of the OdinMS Maple Story Server + Copyright (C) 2008 Patrick Huy + Matthias Butz + Jan Christian Meyer + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation version 3 as published by + the Free Software Foundation. You may not use, modify or distribute + this program under any other version of the GNU Affero General Public + License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ +/* 9010021 - Wolf Spirit Ryko + @author Ronan + @author wejrox +*/ +var status; + +function start() { + status = -1; + if (!Packages.config.YamlConfig.config.server.USE_REBIRTH_SYSTEM) { + cm.sendOk("Rebirths aren't enabled on this server, how did you get here?"); + cm.dispose(); + return; + } + action(1, 0, 0); +} + +function action(mode, type, selection) { + if (mode == 1) { + status++; + } else { + cm.dispose(); + return; + } + if (status == 0) { + cm.sendNext("Come to me when you want to be reborn again. You currently have a total of #r" + cm.getChar().getReborns() + " #krebirths."); + } else if (status == 1) { + cm.sendSimple("What do you want me to do today: \r\n \r\n #L0##bI want to be reborn!#l \r\n #L1##bNothing for now...#k#l"); + } else if (status == 2) { + if (selection == 0) { + if (cm.getChar().getLevel() == 200) { + cm.sendYesNo("Are you sure you want to be reborn?"); + } else { + cm.sendOk("You are not level 200, please come back when you hit level 200."); + cm.dispose(); + } + } else if (selection == 1) { + cm.sendOk("See you soon!") + cm.dispose(); + } + } else if (status == 3 && type == 1) { + cm.getChar().executeReborn(); + cm.sendOk("You have now been reborn. That's a total of #r" + cm.getChar().getReborns() + "#k rebirths"); + cm.dispose(); + } +} \ No newline at end of file diff --git a/src/main/java/config/ServerConfig.java b/src/main/java/config/ServerConfig.java index dbdd9e0a76..5aee568e01 100644 --- a/src/main/java/config/ServerConfig.java +++ b/src/main/java/config/ServerConfig.java @@ -163,6 +163,7 @@ public class ServerConfig { public long NAME_CHANGE_COOLDOWN; public long WORLD_TRANSFER_COOLDOWN=NAME_CHANGE_COOLDOWN;//Cooldown for world tranfers, default is same as name change (30 days). public boolean INSTANT_NAME_CHANGE; + public long REBIRTH_NPC_ID; //Dangling Items/Locks Configuration public int ITEM_EXPIRE_TIME ; diff --git a/src/main/java/net/server/channel/handlers/NPCTalkHandler.java b/src/main/java/net/server/channel/handlers/NPCTalkHandler.java index 71f71c345c..73fec20467 100644 --- a/src/main/java/net/server/channel/handlers/NPCTalkHandler.java +++ b/src/main/java/net/server/channel/handlers/NPCTalkHandler.java @@ -65,6 +65,8 @@ public final class NPCTalkHandler extends AbstractMaplePacketHandler { NPCScriptManager.getInstance().start(c, npc.getId(), "gachapon", null); } else if (npc.getName().endsWith("Maple TV")) { NPCScriptManager.getInstance().start(c, npc.getId(), "mapleTV", null); + } else if (YamlConfig.config.server.USE_REBIRTH_SYSTEM && npc.getId() == YamlConfig.config.server.REBIRTH_NPC_ID) { + NPCScriptManager.getInstance().start(c, npc.getId(), "rebirth", null); } else { boolean hasNpcScript = NPCScriptManager.getInstance().start(c, npc.getId(), oid, null); if (!hasNpcScript) { From cff3d3df567ad711652ec398281035f7bbc56b64 Mon Sep 17 00:00:00 2001 From: James McDowell Date: Sun, 16 May 2021 14:46:38 +1000 Subject: [PATCH 02/14] Added the ability to specify a custom rebirth npc id, which is automatically added to the list of scriptable npcs for overriding. Changed scriptable npcs to use config instead of a constants file, so that users can easily modify them without digging into the code and requiring a rebuild. --- config.yaml | 4 ++ src/main/java/config/ServerConfig.java | 8 ++- .../game/ScriptableNPCConstants.java | 24 --------- .../handlers/PlayerLoggedinHandler.java | 10 +++- src/main/java/tools/MaplePacketCreator.java | 53 +++++++++++-------- 5 files changed, 49 insertions(+), 50 deletions(-) delete mode 100644 src/main/java/constants/game/ScriptableNPCConstants.java diff --git a/config.yaml b/config.yaml index e3a5fc5f2f..73710b8b87 100644 --- a/config.yaml +++ b/config.yaml @@ -461,3 +461,7 @@ server: #Event End Timestamp EVENT_END_TIMESTAMP: 1428897600000 + #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 # Cody + - 9001105 # Grandpa moon bunny diff --git a/src/main/java/config/ServerConfig.java b/src/main/java/config/ServerConfig.java index 5aee568e01..7d5372d373 100644 --- a/src/main/java/config/ServerConfig.java +++ b/src/main/java/config/ServerConfig.java @@ -1,5 +1,9 @@ package config; +import tools.Pair; + +import java.util.*; + public class ServerConfig { //Thread Tracker Configuration public boolean USE_THREAD_TRACKER; @@ -163,7 +167,7 @@ public class ServerConfig { public long NAME_CHANGE_COOLDOWN; public long WORLD_TRANSFER_COOLDOWN=NAME_CHANGE_COOLDOWN;//Cooldown for world tranfers, default is same as name change (30 days). public boolean INSTANT_NAME_CHANGE; - public long REBIRTH_NPC_ID; + public int REBIRTH_NPC_ID; //Dangling Items/Locks Configuration public int ITEM_EXPIRE_TIME ; @@ -305,4 +309,6 @@ public class ServerConfig { //Event End Timestamp public long EVENT_END_TIMESTAMP; + //Custom NPC overrides. NPC ID to Name pair. + public List NPCS_SCRIPTABLE = new ArrayList<>(); } diff --git a/src/main/java/constants/game/ScriptableNPCConstants.java b/src/main/java/constants/game/ScriptableNPCConstants.java deleted file mode 100644 index df8a255cf9..0000000000 --- a/src/main/java/constants/game/ScriptableNPCConstants.java +++ /dev/null @@ -1,24 +0,0 @@ -package constants.game; - -/** - * @brief ScriptableNPCConstants - * @author GabrielSin - * @date 16/09/2018 - * - * Adaptations to use Pair and Set, in order to suit a one-packet marshall. - * Adapted by Ronan - */ - -import java.util.HashSet; -import java.util.Set; -import tools.Pair; - -public class ScriptableNPCConstants { - - public static final Set> SCRIPTABLE_NPCS = new HashSet>(){{ - //add(new Pair<>(9200000, "Cody")); - add(new Pair<>(9001105, "Grandpa Moon Bunny")); - }}; - -} - \ No newline at end of file diff --git a/src/main/java/net/server/channel/handlers/PlayerLoggedinHandler.java b/src/main/java/net/server/channel/handlers/PlayerLoggedinHandler.java index 4db6a00253..d0d18c88e7 100644 --- a/src/main/java/net/server/channel/handlers/PlayerLoggedinHandler.java +++ b/src/main/java/net/server/channel/handlers/PlayerLoggedinHandler.java @@ -26,7 +26,6 @@ import client.inventory.*; import client.keybind.MapleKeyBinding; import config.YamlConfig; import constants.game.GameConstants; -import constants.game.ScriptableNPCConstants; import net.AbstractMaplePacketHandler; import net.server.PlayerBuffValueHolder; import net.server.Server; @@ -409,7 +408,14 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler { } if (YamlConfig.config.server.USE_NPCS_SCRIPTABLE) { - c.announce(MaplePacketCreator.setNPCScriptable(ScriptableNPCConstants.SCRIPTABLE_NPCS)); + List npcsIds = YamlConfig.config.server.NPCS_SCRIPTABLE; + + // Any npc be specified as the rebirth npc. Allow the npc to use custom scripts explicitly. + if (YamlConfig.config.server.USE_REBIRTH_SYSTEM) { + npcsIds.add(YamlConfig.config.server.REBIRTH_NPC_ID); + } + + c.announce(MaplePacketCreator.setNPCScriptable(YamlConfig.config.server.NPCS_SCRIPTABLE)); } if(newcomer) player.setLoginTime(System.currentTimeMillis()); diff --git a/src/main/java/tools/MaplePacketCreator.java b/src/main/java/tools/MaplePacketCreator.java index 453561979c..1bb4ccf090 100644 --- a/src/main/java/tools/MaplePacketCreator.java +++ b/src/main/java/tools/MaplePacketCreator.java @@ -8318,17 +8318,24 @@ public class MaplePacketCreator { mplew.writeInt(transition); return mplew.getPacket(); } - - public static byte[] setNPCScriptable(Set> scriptNpcDescriptions) { // thanks to GabrielSin + + /** + * Makes the NPCs provided set as scriptable, informing the client to search for js scripts for these NPCs even + * if they already have entries within the wz files. + * + * @param scriptableNpcIds Ids of npcs to enable scripts for. + * @return a packet which makes the npc's provided scriptable. + */ + public static byte[] setNPCScriptable(List scriptableNpcIds) { // thanks to GabrielSin MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); mplew.writeShort(SendOpcode.SET_NPC_SCRIPTABLE.getValue()); - mplew.write(scriptNpcDescriptions.size()); - for (Pair p : scriptNpcDescriptions) { - mplew.writeInt(p.getLeft()); - mplew.writeMapleAsciiString(p.getRight()); + mplew.write(scriptableNpcIds.size()); + scriptableNpcIds.forEach(id -> { + mplew.writeInt(id); + mplew.writeMapleAsciiString("NPC " + id); // The client needs a name for the npc, but it doesn't seem to do anything. mplew.writeInt(0); // start time mplew.writeInt(Integer.MAX_VALUE); // end time - } + }); return mplew.getPacket(); } @@ -8374,17 +8381,17 @@ public class MaplePacketCreator { final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); mplew.writeShort(SendOpcode.TOURNAMENT_SET_PRIZE.getValue()); - //0 = "You have failed the set the prize. Please check the item number again." - //1 = "You have successfully set the prize." - mplew.write(bSetPrize); - - mplew.write(bHasPrize); - - if(bHasPrize != 0) - { - mplew.writeInt(nItemID1); - mplew.writeInt(nItemID2); - } + //0 = "You have failed the set the prize. Please check the item number again." + //1 = "You have successfully set the prize." + mplew.write(bSetPrize); + + mplew.write(bHasPrize); + + if(bHasPrize != 0) + { + mplew.writeInt(nItemID1); + mplew.writeInt(nItemID2); + } return mplew.getPacket(); } @@ -8393,11 +8400,11 @@ public class MaplePacketCreator { final MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); mplew.writeShort(SendOpcode.TOURNAMENT_UEW.getValue()); - //Is this a bitflag o.o ? - //2 = "You have reached the finals by default." - //4 = "You have reached the semifinals by default." - //8 or 16 = "You have reached the round of %n by default." | Encodes nState as %n ?! - mplew.write(nState); + //Is this a bitflag o.o ? + //2 = "You have reached the finals by default." + //4 = "You have reached the semifinals by default." + //8 or 16 = "You have reached the round of %n by default." | Encodes nState as %n ?! + mplew.write(nState); return mplew.getPacket(); } From 0345ce844e16df6b753c7bcdd91da5125e69dfb4 Mon Sep 17 00:00:00 2001 From: James McDowell Date: Sun, 16 May 2021 14:51:54 +1000 Subject: [PATCH 03/14] Removed unnecessary import --- src/main/java/config/ServerConfig.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/config/ServerConfig.java b/src/main/java/config/ServerConfig.java index 7d5372d373..da05372eba 100644 --- a/src/main/java/config/ServerConfig.java +++ b/src/main/java/config/ServerConfig.java @@ -1,7 +1,5 @@ package config; -import tools.Pair; - import java.util.*; public class ServerConfig { From 9128329d37fda178605a2d6f254f98a9a897c594 Mon Sep 17 00:00:00 2001 From: James McDowell Date: Thu, 20 May 2021 19:16:22 +1000 Subject: [PATCH 04/14] Swapped from list to set to prevent duplicates Use a set instead, clone instead of adding directly to the list. --- src/main/java/config/ServerConfig.java | 2 +- .../net/server/channel/handlers/PlayerLoggedinHandler.java | 6 ++++-- src/main/java/tools/MaplePacketCreator.java | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/config/ServerConfig.java b/src/main/java/config/ServerConfig.java index da05372eba..7095bce226 100644 --- a/src/main/java/config/ServerConfig.java +++ b/src/main/java/config/ServerConfig.java @@ -307,6 +307,6 @@ public class ServerConfig { //Event End Timestamp public long EVENT_END_TIMESTAMP; - //Custom NPC overrides. NPC ID to Name pair. + //Custom NPC overrides. List of NPC IDs. public List NPCS_SCRIPTABLE = new ArrayList<>(); } diff --git a/src/main/java/net/server/channel/handlers/PlayerLoggedinHandler.java b/src/main/java/net/server/channel/handlers/PlayerLoggedinHandler.java index d0d18c88e7..f5ec11e317 100644 --- a/src/main/java/net/server/channel/handlers/PlayerLoggedinHandler.java +++ b/src/main/java/net/server/channel/handlers/PlayerLoggedinHandler.java @@ -408,14 +408,16 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler { } if (YamlConfig.config.server.USE_NPCS_SCRIPTABLE) { - List npcsIds = YamlConfig.config.server.NPCS_SCRIPTABLE; + + // Create a set to remove duplicate entries if they exist. + Set npcsIds = new HashSet<>(YamlConfig.config.server.NPCS_SCRIPTABLE); // Any npc be specified as the rebirth npc. Allow the npc to use custom scripts explicitly. if (YamlConfig.config.server.USE_REBIRTH_SYSTEM) { npcsIds.add(YamlConfig.config.server.REBIRTH_NPC_ID); } - c.announce(MaplePacketCreator.setNPCScriptable(YamlConfig.config.server.NPCS_SCRIPTABLE)); + c.announce(MaplePacketCreator.setNPCScriptable(npcsIds)); } if(newcomer) player.setLoginTime(System.currentTimeMillis()); diff --git a/src/main/java/tools/MaplePacketCreator.java b/src/main/java/tools/MaplePacketCreator.java index 1bb4ccf090..d7f259eda7 100644 --- a/src/main/java/tools/MaplePacketCreator.java +++ b/src/main/java/tools/MaplePacketCreator.java @@ -8326,7 +8326,7 @@ public class MaplePacketCreator { * @param scriptableNpcIds Ids of npcs to enable scripts for. * @return a packet which makes the npc's provided scriptable. */ - public static byte[] setNPCScriptable(List scriptableNpcIds) { // thanks to GabrielSin + public static byte[] setNPCScriptable(Set scriptableNpcIds) { // thanks to GabrielSin MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); mplew.writeShort(SendOpcode.SET_NPC_SCRIPTABLE.getValue()); mplew.write(scriptableNpcIds.size()); From e967294eb9a1dd4beb58228b7521ddf231d01a53 Mon Sep 17 00:00:00 2001 From: James McDowell Date: Wed, 26 May 2021 19:41:27 +1000 Subject: [PATCH 05/14] Add back in NPC conversation names The names of the npc conversations were useful for context. Added them back in. --- config.yaml | 4 ++-- src/main/java/config/ServerConfig.java | 2 +- .../channel/handlers/PlayerLoggedinHandler.java | 14 ++++++++++---- src/main/java/tools/MaplePacketCreator.java | 7 ++++--- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/config.yaml b/config.yaml index 73710b8b87..54d43f32bf 100644 --- a/config.yaml +++ b/config.yaml @@ -463,5 +463,5 @@ server: #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 # Cody - - 9001105 # Grandpa moon bunny + #9200000: Talk to Cody # Cody + 9001105: Rescue Gaga! # Grandpa moon bunny diff --git a/src/main/java/config/ServerConfig.java b/src/main/java/config/ServerConfig.java index 7095bce226..34beaea4df 100644 --- a/src/main/java/config/ServerConfig.java +++ b/src/main/java/config/ServerConfig.java @@ -308,5 +308,5 @@ public class ServerConfig { public long EVENT_END_TIMESTAMP; //Custom NPC overrides. List of NPC IDs. - public List NPCS_SCRIPTABLE = new ArrayList<>(); + public Map NPCS_SCRIPTABLE = new HashMap<>(); } diff --git a/src/main/java/net/server/channel/handlers/PlayerLoggedinHandler.java b/src/main/java/net/server/channel/handlers/PlayerLoggedinHandler.java index f5ec11e317..75c2d12958 100644 --- a/src/main/java/net/server/channel/handlers/PlayerLoggedinHandler.java +++ b/src/main/java/net/server/channel/handlers/PlayerLoggedinHandler.java @@ -54,6 +54,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; import java.util.Map.Entry; +import java.util.stream.Collectors; public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler { @@ -406,15 +407,20 @@ public final class PlayerLoggedinHandler extends AbstractMaplePacketHandler { eim.registerPlayer(player); } } - + + // Tell the client to use the custom scripts available for the NPCs provided, instead of the WZ entries. if (YamlConfig.config.server.USE_NPCS_SCRIPTABLE) { - // Create a set to remove duplicate entries if they exist. - Set npcsIds = new HashSet<>(YamlConfig.config.server.NPCS_SCRIPTABLE); + // Create a copy to prevent always adding entries to the server's list. + Map npcsIds = YamlConfig.config.server.NPCS_SCRIPTABLE + .entrySet().stream().collect(Collectors.toMap( + entry -> Integer.parseInt(entry.getKey()), + Entry::getValue + )); // Any npc be specified as the rebirth npc. Allow the npc to use custom scripts explicitly. if (YamlConfig.config.server.USE_REBIRTH_SYSTEM) { - npcsIds.add(YamlConfig.config.server.REBIRTH_NPC_ID); + npcsIds.put(YamlConfig.config.server.REBIRTH_NPC_ID, "Rebirth"); } c.announce(MaplePacketCreator.setNPCScriptable(npcsIds)); diff --git a/src/main/java/tools/MaplePacketCreator.java b/src/main/java/tools/MaplePacketCreator.java index d7f259eda7..50ee148ad7 100644 --- a/src/main/java/tools/MaplePacketCreator.java +++ b/src/main/java/tools/MaplePacketCreator.java @@ -8326,13 +8326,14 @@ public class MaplePacketCreator { * @param scriptableNpcIds Ids of npcs to enable scripts for. * @return a packet which makes the npc's provided scriptable. */ - public static byte[] setNPCScriptable(Set scriptableNpcIds) { // thanks to GabrielSin + public static byte[] setNPCScriptable(Map scriptableNpcIds) { // thanks to GabrielSin MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter(); mplew.writeShort(SendOpcode.SET_NPC_SCRIPTABLE.getValue()); mplew.write(scriptableNpcIds.size()); - scriptableNpcIds.forEach(id -> { + scriptableNpcIds.forEach((id, name) -> { mplew.writeInt(id); - mplew.writeMapleAsciiString("NPC " + id); // The client needs a name for the npc, but it doesn't seem to do anything. + // The client needs a name for the npc conversation, which is displayed under etc when the npc has a quest available. + mplew.writeMapleAsciiString(name); mplew.writeInt(0); // start time mplew.writeInt(Integer.MAX_VALUE); // end time }); From 136ea68ab379798f914126730242dd9208f33197 Mon Sep 17 00:00:00 2001 From: James McDowell Date: Wed, 26 May 2021 19:45:58 +1000 Subject: [PATCH 06/14] Updated the rebirth NPC to use GraalJS --- scripts/npc/rebirth.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/scripts/npc/rebirth.js b/scripts/npc/rebirth.js index c32670e46a..72d2a5f8a6 100644 --- a/scripts/npc/rebirth.js +++ b/scripts/npc/rebirth.js @@ -19,7 +19,7 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ -/* 9010021 - Wolf Spirit Ryko +/* Rebirth NPC @author Ronan @author wejrox */ @@ -27,7 +27,8 @@ var status; function start() { status = -1; - if (!Packages.config.YamlConfig.config.server.USE_REBIRTH_SYSTEM) { + const YamlConfig = Java.type('config.YamlConfig'); + if (!YamlConfig.config.server.USE_REBIRTH_SYSTEM) { cm.sendOk("Rebirths aren't enabled on this server, how did you get here?"); cm.dispose(); return; @@ -36,29 +37,29 @@ function start() { } function action(mode, type, selection) { - if (mode == 1) { + if (mode === 1) { status++; } else { cm.dispose(); return; } - if (status == 0) { + if (status === 0) { cm.sendNext("Come to me when you want to be reborn again. You currently have a total of #r" + cm.getChar().getReborns() + " #krebirths."); - } else if (status == 1) { + } else if (status === 1) { cm.sendSimple("What do you want me to do today: \r\n \r\n #L0##bI want to be reborn!#l \r\n #L1##bNothing for now...#k#l"); - } else if (status == 2) { - if (selection == 0) { - if (cm.getChar().getLevel() == 200) { + } else if (status === 2) { + if (selection === 0) { + if (cm.getChar().getLevel() === 200) { cm.sendYesNo("Are you sure you want to be reborn?"); } else { cm.sendOk("You are not level 200, please come back when you hit level 200."); cm.dispose(); } - } else if (selection == 1) { + } else if (selection === 1) { cm.sendOk("See you soon!") cm.dispose(); } - } else if (status == 3 && type == 1) { + } else if (status === 3 && type === 1) { cm.getChar().executeReborn(); cm.sendOk("You have now been reborn. That's a total of #r" + cm.getChar().getReborns() + "#k rebirths"); cm.dispose(); From 00abbb4acdc4f888995e530d63bfb6b6bca7a37e Mon Sep 17 00:00:00 2001 From: P0nk Date: Sun, 20 Jun 2021 17:15:10 +0200 Subject: [PATCH 07/14] Add InPacket interface and ByteBuf implementation Replacement for LittleEndianAccessor, SeekableLittleEndianAccessor, GenericLittleEndianAccessor, and GenericSeekableLittleEndianAccessor. --- pom.xml | 5 ++ src/main/java/net/packet/ByteBufInPacket.java | 79 +++++++++++++++++++ .../java/net/packet/ByteBufOutPacket.java | 11 +++ src/main/java/net/packet/InPacket.java | 17 ++++ src/main/java/net/packet/OutPacket.java | 4 + src/main/java/net/packet/Packet.java | 5 ++ 6 files changed, 121 insertions(+) create mode 100644 src/main/java/net/packet/ByteBufInPacket.java create mode 100644 src/main/java/net/packet/ByteBufOutPacket.java create mode 100644 src/main/java/net/packet/InPacket.java create mode 100644 src/main/java/net/packet/OutPacket.java create mode 100644 src/main/java/net/packet/Packet.java diff --git a/pom.xml b/pom.xml index 7df287a87f..ba08e2d62a 100644 --- a/pom.xml +++ b/pom.xml @@ -47,6 +47,11 @@ jcip-annotations 1.0 + + io.netty + netty-buffer + 4.1.65.Final + diff --git a/src/main/java/net/packet/ByteBufInPacket.java b/src/main/java/net/packet/ByteBufInPacket.java new file mode 100644 index 0000000000..481c5855cb --- /dev/null +++ b/src/main/java/net/packet/ByteBufInPacket.java @@ -0,0 +1,79 @@ +package net.packet; + +import io.netty.buffer.ByteBuf; + +import java.awt.*; + +public class ByteBufInPacket implements InPacket { + private final ByteBuf byteBuf; + + public ByteBufInPacket(ByteBuf byteBuf) { + this.byteBuf = byteBuf; + } + + @Override + public byte[] getBytes() { + // TODO + return null; + } + + @Override + public byte readByte() { + return byteBuf.readByte(); + } + + @Override + public short readShort() { + return byteBuf.readShortLE(); + } + + @Override + public int readInt() { + return byteBuf.readIntLE(); + } + + @Override + public long readLong() { + return byteBuf.readLongLE(); + } + + @Override + public Point readPoint() { + final short x = byteBuf.readShortLE(); + final short y = byteBuf.readShortLE(); + return new Point(x, y); + } + + @Override + public String readString() { + // TODO + return null; + } + + @Override + public byte[] read(int numberOfBytes) { + byte[] bytes = new byte[numberOfBytes]; + byteBuf.readBytes(bytes); + return bytes; + } + + @Override + public void skip(int numberOfBytes) { + byteBuf.skipBytes(numberOfBytes); + } + + @Override + public int available() { + return byteBuf.readableBytes(); + } + + @Override + public void seek(int byteOffset) { + byteBuf.readerIndex(byteOffset); + } + + @Override + public int getPosition() { + return byteBuf.readerIndex(); + } +} diff --git a/src/main/java/net/packet/ByteBufOutPacket.java b/src/main/java/net/packet/ByteBufOutPacket.java new file mode 100644 index 0000000000..f2aa491cfb --- /dev/null +++ b/src/main/java/net/packet/ByteBufOutPacket.java @@ -0,0 +1,11 @@ +package net.packet; + +import io.netty.buffer.ByteBuf; + +public class ByteBufOutPacket implements OutPacket { + private final ByteBuf byteBuf; + + public ByteBufOutPacket(ByteBuf byteBuf) { + this.byteBuf = byteBuf; + } +} diff --git a/src/main/java/net/packet/InPacket.java b/src/main/java/net/packet/InPacket.java new file mode 100644 index 0000000000..53ef38bb42 --- /dev/null +++ b/src/main/java/net/packet/InPacket.java @@ -0,0 +1,17 @@ +package net.packet; + +import java.awt.*; + +public interface InPacket extends Packet { + byte readByte(); + short readShort(); + int readInt(); + long readLong(); + Point readPoint(); + String readString(); + byte[] read(int numberOfBytes); + void skip(int numberOfBytes); + int available(); + void seek(int byteOffset); + int getPosition(); +} diff --git a/src/main/java/net/packet/OutPacket.java b/src/main/java/net/packet/OutPacket.java new file mode 100644 index 0000000000..6d1fb8982a --- /dev/null +++ b/src/main/java/net/packet/OutPacket.java @@ -0,0 +1,4 @@ +package net.packet; + +public interface OutPacket extends Packet { +} diff --git a/src/main/java/net/packet/Packet.java b/src/main/java/net/packet/Packet.java new file mode 100644 index 0000000000..8e1b7cfb99 --- /dev/null +++ b/src/main/java/net/packet/Packet.java @@ -0,0 +1,5 @@ +package net.packet; + +public interface Packet { + byte[] getBytes(); +} From f3faee2e16755154f084e96c41d01f0729af9169 Mon Sep 17 00:00:00 2001 From: P0nk Date: Sun, 20 Jun 2021 20:40:23 +0200 Subject: [PATCH 08/14] Add OutPacket interface and ByteBuf implementation Replacement for LittleEndianWriter, GenericLittleEndianWriter, and MaplePacketLittleEndianWriter. --- src/main/java/net/packet/ByteBufInPacket.java | 17 ++-- .../java/net/packet/ByteBufOutPacket.java | 79 ++++++++++++++++++- src/main/java/net/packet/InPacket.java | 2 +- src/main/java/net/packet/OutPacket.java | 16 ++++ src/main/java/net/packet/Packet.java | 1 + 5 files changed, 107 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/packet/ByteBufInPacket.java b/src/main/java/net/packet/ByteBufInPacket.java index 481c5855cb..c2e2984499 100644 --- a/src/main/java/net/packet/ByteBufInPacket.java +++ b/src/main/java/net/packet/ByteBufInPacket.java @@ -11,10 +11,15 @@ public class ByteBufInPacket implements InPacket { this.byteBuf = byteBuf; } + @Override + public short getHeader() { + return byteBuf.getShortLE(0); + } + @Override public byte[] getBytes() { - // TODO - return null; + // TODO implement + throw new UnsupportedOperationException(); } @Override @@ -51,15 +56,15 @@ public class ByteBufInPacket implements InPacket { } @Override - public byte[] read(int numberOfBytes) { - byte[] bytes = new byte[numberOfBytes]; + public byte[] readBytes(int bytesToRead) { + byte[] bytes = new byte[bytesToRead]; byteBuf.readBytes(bytes); return bytes; } @Override - public void skip(int numberOfBytes) { - byteBuf.skipBytes(numberOfBytes); + public void skip(int bytesToSkip) { + byteBuf.skipBytes(bytesToSkip); } @Override diff --git a/src/main/java/net/packet/ByteBufOutPacket.java b/src/main/java/net/packet/ByteBufOutPacket.java index f2aa491cfb..d36c594f83 100644 --- a/src/main/java/net/packet/ByteBufOutPacket.java +++ b/src/main/java/net/packet/ByteBufOutPacket.java @@ -1,11 +1,88 @@ package net.packet; import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import net.jcip.annotations.NotThreadSafe; +import net.opcodes.SendOpcode; +import java.awt.*; + +@NotThreadSafe public class ByteBufOutPacket implements OutPacket { private final ByteBuf byteBuf; - public ByteBufOutPacket(ByteBuf byteBuf) { + public ByteBufOutPacket(SendOpcode op) { + ByteBuf byteBuf = Unpooled.buffer(); + byteBuf.writeShortLE((short) op.getValue()); this.byteBuf = byteBuf; } + + public ByteBufOutPacket(SendOpcode op, int initialCapacity) { + ByteBuf byteBuf = Unpooled.buffer(initialCapacity); + byteBuf.writeShortLE((short) op.getValue()); + this.byteBuf = byteBuf; + } + + @Override + public short getHeader() { + return byteBuf.getShortLE(0); + } + + @Override + public byte[] getBytes() { + // TODO implement + throw new UnsupportedOperationException(); + } + + @Override + public void writeByte(byte value) { + byteBuf.writeByte(value); + } + + @Override + public void writeByte(int value) { + writeByte((byte) value); + } + + @Override + public void writeBytes(byte[] value) { + byteBuf.writeBytes(value); + } + + @Override + public void writeShort(short value) { + byteBuf.writeShortLE(value); + } + + @Override + public void writeInt(int value) { + byteBuf.writeIntLE(value); + } + + @Override + public void writeLong(long value) { + byteBuf.writeLongLE(value); + } + + @Override + public void writeBoolean(boolean value) { + byteBuf.writeByte(value ? 1 : 0); + } + + @Override + public void writeString(String value) { + writeShort((short) value.length()); + writeBytes(value.getBytes(STRING_CHARSET)); + } + + @Override + public void writePoint(Point value) { + writeShort((short) value.getX()); + writeShort((short) value.getY()); + } + + @Override + public void skip(int bytesToSkip) { + writeBytes(new byte[bytesToSkip]); + } } diff --git a/src/main/java/net/packet/InPacket.java b/src/main/java/net/packet/InPacket.java index 53ef38bb42..c2493227a4 100644 --- a/src/main/java/net/packet/InPacket.java +++ b/src/main/java/net/packet/InPacket.java @@ -9,7 +9,7 @@ public interface InPacket extends Packet { long readLong(); Point readPoint(); String readString(); - byte[] read(int numberOfBytes); + byte[] readBytes(int bytesToRead); void skip(int numberOfBytes); int available(); void seek(int byteOffset); diff --git a/src/main/java/net/packet/OutPacket.java b/src/main/java/net/packet/OutPacket.java index 6d1fb8982a..9b6804abb8 100644 --- a/src/main/java/net/packet/OutPacket.java +++ b/src/main/java/net/packet/OutPacket.java @@ -1,4 +1,20 @@ package net.packet; +import java.awt.*; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + public interface OutPacket extends Packet { + Charset STRING_CHARSET = StandardCharsets.US_ASCII; + + void writeByte(byte value); + void writeByte(int value); + void writeBytes(byte[] value); + void writeShort(short value); + void writeInt(int value); + void writeLong(long value); + void writeBoolean(boolean value); + void writeString(String value); + void writePoint(Point value); + void skip(int numberOfBytes); } diff --git a/src/main/java/net/packet/Packet.java b/src/main/java/net/packet/Packet.java index 8e1b7cfb99..6bbd4cc4dc 100644 --- a/src/main/java/net/packet/Packet.java +++ b/src/main/java/net/packet/Packet.java @@ -1,5 +1,6 @@ package net.packet; public interface Packet { + short getHeader(); byte[] getBytes(); } From aaf4b558f3345c86c3679c60bb81c943e65ebd14 Mon Sep 17 00:00:00 2001 From: P0nk Date: Sun, 20 Jun 2021 21:27:50 +0200 Subject: [PATCH 09/14] Finish InPacket & OutPacket implementations --- src/main/java/net/packet/ByteBufInPacket.java | 28 ++++++++++--------- .../java/net/packet/ByteBufOutPacket.java | 17 +++++------ src/main/java/net/packet/InPacket.java | 2 +- src/main/java/net/packet/OutPacket.java | 2 +- src/main/java/net/packet/Packet.java | 1 - 5 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/main/java/net/packet/ByteBufInPacket.java b/src/main/java/net/packet/ByteBufInPacket.java index c2e2984499..02c8f3cb41 100644 --- a/src/main/java/net/packet/ByteBufInPacket.java +++ b/src/main/java/net/packet/ByteBufInPacket.java @@ -11,15 +11,12 @@ public class ByteBufInPacket implements InPacket { this.byteBuf = byteBuf; } - @Override - public short getHeader() { - return byteBuf.getShortLE(0); - } - @Override public byte[] getBytes() { - // TODO implement - throw new UnsupportedOperationException(); + byte[] bytes = new byte[byteBuf.readableBytes()]; + int readerIndex = byteBuf.readerIndex(); + byteBuf.getBytes(readerIndex, bytes); + return bytes; } @Override @@ -51,20 +48,25 @@ public class ByteBufInPacket implements InPacket { @Override public String readString() { - // TODO - return null; + short length = readShort(); + char[] characters = new char[length]; + for(int i = 0; i < length; i++) { + characters[i] = (char) readByte(); + } + + return String.valueOf(characters); } @Override - public byte[] readBytes(int bytesToRead) { - byte[] bytes = new byte[bytesToRead]; + public byte[] readBytes(int numberOfBytes) { + byte[] bytes = new byte[numberOfBytes]; byteBuf.readBytes(bytes); return bytes; } @Override - public void skip(int bytesToSkip) { - byteBuf.skipBytes(bytesToSkip); + public void skip(int numberOfBytes) { + byteBuf.skipBytes(numberOfBytes); } @Override diff --git a/src/main/java/net/packet/ByteBufOutPacket.java b/src/main/java/net/packet/ByteBufOutPacket.java index d36c594f83..5fc77f3c3d 100644 --- a/src/main/java/net/packet/ByteBufOutPacket.java +++ b/src/main/java/net/packet/ByteBufOutPacket.java @@ -23,15 +23,12 @@ public class ByteBufOutPacket implements OutPacket { this.byteBuf = byteBuf; } - @Override - public short getHeader() { - return byteBuf.getShortLE(0); - } - @Override public byte[] getBytes() { - // TODO implement - throw new UnsupportedOperationException(); + byte[] bytes = new byte[byteBuf.readableBytes()]; + int readerIndex = byteBuf.readerIndex(); + byteBuf.getBytes(readerIndex, bytes); + return bytes; } @Override @@ -50,7 +47,7 @@ public class ByteBufOutPacket implements OutPacket { } @Override - public void writeShort(short value) { + public void writeShort(int value) { byteBuf.writeShortLE(value); } @@ -82,7 +79,7 @@ public class ByteBufOutPacket implements OutPacket { } @Override - public void skip(int bytesToSkip) { - writeBytes(new byte[bytesToSkip]); + public void skip(int numberOfBytes) { + writeBytes(new byte[numberOfBytes]); } } diff --git a/src/main/java/net/packet/InPacket.java b/src/main/java/net/packet/InPacket.java index c2493227a4..2c899c2ade 100644 --- a/src/main/java/net/packet/InPacket.java +++ b/src/main/java/net/packet/InPacket.java @@ -9,7 +9,7 @@ public interface InPacket extends Packet { long readLong(); Point readPoint(); String readString(); - byte[] readBytes(int bytesToRead); + byte[] readBytes(int numberOfBytes); void skip(int numberOfBytes); int available(); void seek(int byteOffset); diff --git a/src/main/java/net/packet/OutPacket.java b/src/main/java/net/packet/OutPacket.java index 9b6804abb8..615f932db0 100644 --- a/src/main/java/net/packet/OutPacket.java +++ b/src/main/java/net/packet/OutPacket.java @@ -10,7 +10,7 @@ public interface OutPacket extends Packet { void writeByte(byte value); void writeByte(int value); void writeBytes(byte[] value); - void writeShort(short value); + void writeShort(int value); void writeInt(int value); void writeLong(long value); void writeBoolean(boolean value); diff --git a/src/main/java/net/packet/Packet.java b/src/main/java/net/packet/Packet.java index 6bbd4cc4dc..8e1b7cfb99 100644 --- a/src/main/java/net/packet/Packet.java +++ b/src/main/java/net/packet/Packet.java @@ -1,6 +1,5 @@ package net.packet; public interface Packet { - short getHeader(); byte[] getBytes(); } From 926371c9a7c04087ecfef32f05af3ae58315d489 Mon Sep 17 00:00:00 2001 From: P0nk Date: Sun, 20 Jun 2021 22:53:20 +0200 Subject: [PATCH 10/14] Add unit tests for ByteBufInPacket --- pom.xml | 14 ++ .../java/net/packet/ByteBufInPacketTest.java | 169 ++++++++++++++++++ 2 files changed, 183 insertions(+) create mode 100644 src/test/java/net/packet/ByteBufInPacketTest.java diff --git a/pom.xml b/pom.xml index ba08e2d62a..b3916598c8 100644 --- a/pom.xml +++ b/pom.xml @@ -86,6 +86,20 @@ js-scriptengine ${graalvm.version} + + + + org.junit.jupiter + junit-jupiter-api + 5.7.2 + + + org.junit.jupiter + junit-jupiter-engine + 5.7.2 + + + diff --git a/src/test/java/net/packet/ByteBufInPacketTest.java b/src/test/java/net/packet/ByteBufInPacketTest.java new file mode 100644 index 0000000000..595055cd00 --- /dev/null +++ b/src/test/java/net/packet/ByteBufInPacketTest.java @@ -0,0 +1,169 @@ +package net.packet; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.awt.*; +import java.nio.charset.StandardCharsets; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ByteBufInPacketTest { + private ByteBuf byteBuf; + private InPacket inPacket; + + @BeforeEach + void reset() { + this.byteBuf = Unpooled.buffer(); + this.inPacket = new ByteBufInPacket(byteBuf); + } + + @Test + void readByte() { + final byte writtenByte = 123; + byteBuf.writeByte(writtenByte); + + byte readByte = inPacket.readByte(); + + assertEquals(writtenByte, readByte); + } + + @Test + void readShort() { + final short writtenShort = 12_345; + byteBuf.writeShortLE(writtenShort); + + short readShort = inPacket.readShort(); + + assertEquals(writtenShort, readShort); + } + + @Test + void readInt() { + final int writtenInt = 1_234_567_890; + byteBuf.writeIntLE(writtenInt); + + int readInt = inPacket.readInt(); + + assertEquals(writtenInt, readInt); + } + + @Test + void readLong() { + final long writtenLong = 9_223_372_036_854_775_807L; + byteBuf.writeLongLE(writtenLong); + + long readLong = inPacket.readLong(); + + assertEquals(writtenLong, readLong); + } + + @Test + void readPoint() { + final Point writtenPoint = new Point(111, 222); + byteBuf.writeShortLE((short) writtenPoint.getX()); + byteBuf.writeShortLE((short) writtenPoint.getY()); + + Point readPoint = inPacket.readPoint(); + + assertEquals(writtenPoint, readPoint); + } + + @Test + void readString() { + final String writtenString = "You have gained experience (+3200)"; + byteBuf.writeShortLE(writtenString.length()); + byte[] writtenStringBytes = writtenString.getBytes(StandardCharsets.US_ASCII); + byteBuf.writeBytes(writtenStringBytes); + + String readString = inPacket.readString(); + + assertEquals(writtenString, readString); + } + + @Test + void readBytes() { + byte[] writtenBytes = {10, 11, 12, 13, 14, 15}; + byteBuf.writeBytes(writtenBytes); + + byte[] byteBatch1 = inPacket.readBytes(1); + assertEquals(1, byteBatch1.length); + assertEquals(10, byteBatch1[0]); + + byte[] byteBatch2 = inPacket.readBytes(2); + assertEquals(2, byteBatch2.length); + assertEquals(11, byteBatch2[0]); + assertEquals(12, byteBatch2[1]); + + byte[] byteBatch3 = inPacket.readBytes(3); + assertEquals(3, byteBatch3.length); + assertEquals(13, byteBatch3[0]); + assertEquals(14, byteBatch3[1]); + assertEquals(15, byteBatch3[2]); + } + + @Test + void skip() { + byte[] writtenBytes = {20, 21, 22, 23, 24, 25}; + byteBuf.writeBytes(writtenBytes); + + byte firstByte = inPacket.readByte(); + assertEquals(20, firstByte); + + inPacket.skip(3); + + byte fifthByte = inPacket.readByte(); + assertEquals(24, fifthByte); + } + + @Test + void available() { + byte[] writtenBytes = {30, 31, 32, 33, 34, 35}; + byteBuf.writeBytes(writtenBytes); + + assertEquals(6, inPacket.available()); + + inPacket.readByte(); + assertEquals(5, inPacket.available()); + + inPacket.readInt(); + assertEquals(1, inPacket.available()); + } + + @Test + void seek() { + byte[] writtenBytes = {40, 41, 42, 43, 44, 45}; + byteBuf.writeBytes(writtenBytes); + + inPacket.seek(2); + assertEquals(4, inPacket.available()); + byte byteAtSeek = inPacket.readByte(); + assertEquals(42, byteAtSeek); + + inPacket.seek(0); + byte byteAtReset = inPacket.readByte(); + assertEquals(40, byteAtReset); + } + + @Test + void getPosition() { + byte[] writtenBytes = {50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60}; + byteBuf.writeBytes(writtenBytes); + + assertEquals(0, inPacket.getPosition()); + + inPacket.readByte(); + assertEquals(1, inPacket.getPosition()); + + inPacket.readShort(); + assertEquals(3, inPacket.getPosition()); + + inPacket.readInt(); + assertEquals(7, inPacket.getPosition()); + + inPacket.seek(5); + assertEquals(5, inPacket.getPosition()); + } +} \ No newline at end of file From 6d02a952732cc644e64d1a93cfe2f4432d9a37a5 Mon Sep 17 00:00:00 2001 From: P0nk Date: Sun, 20 Jun 2021 23:02:01 +0200 Subject: [PATCH 11/14] Simplify test setup for written bytes --- .../java/net/packet/ByteBufInPacketTest.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/test/java/net/packet/ByteBufInPacketTest.java b/src/test/java/net/packet/ByteBufInPacketTest.java index 595055cd00..df5c88d68d 100644 --- a/src/test/java/net/packet/ByteBufInPacketTest.java +++ b/src/test/java/net/packet/ByteBufInPacketTest.java @@ -20,6 +20,12 @@ class ByteBufInPacketTest { this.inPacket = new ByteBufInPacket(byteBuf); } + private void givenWrittenBytes(int... bytes) { + for (int b : bytes) { + byteBuf.writeByte(b); + } + } + @Test void readByte() { final byte writtenByte = 123; @@ -85,8 +91,7 @@ class ByteBufInPacketTest { @Test void readBytes() { - byte[] writtenBytes = {10, 11, 12, 13, 14, 15}; - byteBuf.writeBytes(writtenBytes); + givenWrittenBytes(10, 11, 12, 13, 14, 15); byte[] byteBatch1 = inPacket.readBytes(1); assertEquals(1, byteBatch1.length); @@ -106,8 +111,7 @@ class ByteBufInPacketTest { @Test void skip() { - byte[] writtenBytes = {20, 21, 22, 23, 24, 25}; - byteBuf.writeBytes(writtenBytes); + givenWrittenBytes(20, 21, 22, 23, 24, 25); byte firstByte = inPacket.readByte(); assertEquals(20, firstByte); @@ -120,8 +124,7 @@ class ByteBufInPacketTest { @Test void available() { - byte[] writtenBytes = {30, 31, 32, 33, 34, 35}; - byteBuf.writeBytes(writtenBytes); + givenWrittenBytes(30, 31, 32, 33, 34, 35); assertEquals(6, inPacket.available()); @@ -134,8 +137,7 @@ class ByteBufInPacketTest { @Test void seek() { - byte[] writtenBytes = {40, 41, 42, 43, 44, 45}; - byteBuf.writeBytes(writtenBytes); + givenWrittenBytes(40, 41, 42, 43, 44, 45); inPacket.seek(2); assertEquals(4, inPacket.available()); @@ -149,8 +151,7 @@ class ByteBufInPacketTest { @Test void getPosition() { - byte[] writtenBytes = {50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60}; - byteBuf.writeBytes(writtenBytes); + givenWrittenBytes(50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60); assertEquals(0, inPacket.getPosition()); From 4fd64884f2f1903108b9ecad78bb9f99cb7fc002 Mon Sep 17 00:00:00 2001 From: P0nk Date: Mon, 21 Jun 2021 21:45:06 +0200 Subject: [PATCH 12/14] Simplify getBytes and add tests for it --- src/main/java/net/packet/ByteBufInPacket.java | 6 ++--- .../java/net/packet/ByteBufOutPacket.java | 6 ++--- .../java/net/packet/ByteBufInPacketTest.java | 23 +++++++++++++++++++ 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/packet/ByteBufInPacket.java b/src/main/java/net/packet/ByteBufInPacket.java index 02c8f3cb41..d1b9f4f87e 100644 --- a/src/main/java/net/packet/ByteBufInPacket.java +++ b/src/main/java/net/packet/ByteBufInPacket.java @@ -1,6 +1,7 @@ package net.packet; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import java.awt.*; @@ -13,10 +14,7 @@ public class ByteBufInPacket implements InPacket { @Override public byte[] getBytes() { - byte[] bytes = new byte[byteBuf.readableBytes()]; - int readerIndex = byteBuf.readerIndex(); - byteBuf.getBytes(readerIndex, bytes); - return bytes; + return ByteBufUtil.getBytes(byteBuf); } @Override diff --git a/src/main/java/net/packet/ByteBufOutPacket.java b/src/main/java/net/packet/ByteBufOutPacket.java index 5fc77f3c3d..5aa7a20b79 100644 --- a/src/main/java/net/packet/ByteBufOutPacket.java +++ b/src/main/java/net/packet/ByteBufOutPacket.java @@ -1,6 +1,7 @@ package net.packet; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import net.jcip.annotations.NotThreadSafe; import net.opcodes.SendOpcode; @@ -25,10 +26,7 @@ public class ByteBufOutPacket implements OutPacket { @Override public byte[] getBytes() { - byte[] bytes = new byte[byteBuf.readableBytes()]; - int readerIndex = byteBuf.readerIndex(); - byteBuf.getBytes(readerIndex, bytes); - return bytes; + return ByteBufUtil.getBytes(byteBuf); } @Override diff --git a/src/test/java/net/packet/ByteBufInPacketTest.java b/src/test/java/net/packet/ByteBufInPacketTest.java index df5c88d68d..1ed28e1d56 100644 --- a/src/test/java/net/packet/ByteBufInPacketTest.java +++ b/src/test/java/net/packet/ByteBufInPacketTest.java @@ -8,6 +8,7 @@ import org.junit.jupiter.api.Test; import java.awt.*; import java.nio.charset.StandardCharsets; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; class ByteBufInPacketTest { @@ -167,4 +168,26 @@ class ByteBufInPacketTest { inPacket.seek(5); assertEquals(5, inPacket.getPosition()); } + + @Test + void getBytes() { + givenWrittenBytes(20, 19, 21, 18, 22); + + byte[] bytes = inPacket.getBytes(); + + assertArrayEquals(new byte[]{20, 19, 21, 18, 22}, bytes); + } + + @Test + void whenGetBytes_shouldBeRepeatable() { + givenWrittenBytes(1, 2, 3, 4, 5); + + byte[] bytes = inPacket.getBytes(); + assertEquals(5, bytes.length); + + byte[] sameBytes = inPacket.getBytes(); + assertEquals(5, sameBytes.length); + + assertArrayEquals(bytes, sameBytes); + } } \ No newline at end of file From c4c5700d32010756cdaba025c5457158bd44a67c Mon Sep 17 00:00:00 2001 From: P0nk Date: Mon, 21 Jun 2021 21:45:30 +0200 Subject: [PATCH 13/14] Add basic unit tests for ByteBufOutPacket --- .../java/net/packet/ByteBufOutPacketTest.java | 206 ++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 src/test/java/net/packet/ByteBufOutPacketTest.java diff --git a/src/test/java/net/packet/ByteBufOutPacketTest.java b/src/test/java/net/packet/ByteBufOutPacketTest.java new file mode 100644 index 0000000000..3673254736 --- /dev/null +++ b/src/test/java/net/packet/ByteBufOutPacketTest.java @@ -0,0 +1,206 @@ +package net.packet; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import net.opcodes.SendOpcode; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.awt.*; +import java.nio.charset.StandardCharsets; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ByteBufOutPacketTest { + private ByteBufOutPacket outPacket; + + @BeforeEach + void reset() { + outPacket = new ByteBufOutPacket(SendOpcode.ADMIN_SHOP); // Any opcode will do + } + + private static ByteBuf wrapExplicitlyWrittenBytes(OutPacket outPacket) { + byte[] packetBytes = outPacket.getBytes(); + ByteBuf byteBuf = Unpooled.copiedBuffer(packetBytes); + byteBuf.readShortLE(); // Skip over opcode + return byteBuf; + } + + @Test + void whenInstantiatingNew_shouldWriteOpcode() { + byte[] packetBytes = new ByteBufOutPacket(SendOpcode.NPC_TALK).getBytes(); + assertEquals(2, packetBytes.length); + } + + @Test + void getBytes() { + ByteBufOutPacket outPacket = new ByteBufOutPacket(SendOpcode.PING); // This opcode has value 0x11 = 17 in decimal + outPacket.writeByte(10); + outPacket.writeByte(20); + outPacket.writeByte(30); + + byte[] bytes = outPacket.getBytes(); + + assertArrayEquals(new byte[]{(byte) 17, (byte) 0, (byte) 10, (byte) 20, (byte) 30}, bytes); + } + + @Test + void writeByte() { + final byte writtenByte = 19; + outPacket.writeByte(writtenByte); + + ByteBuf wrapped = wrapExplicitlyWrittenBytes(outPacket); + byte readByte = wrapped.readByte(); + + assertEquals(writtenByte, readByte); + } + + @Test + void writeByteFromInt() { + final int writtenInt = 123; + outPacket.writeByte(writtenInt); + + ByteBuf wrapped = wrapExplicitlyWrittenBytes(outPacket); + byte readByte = wrapped.readByte(); + + assertEquals(writtenInt, readByte); + } + + @Test + void whenWritingByteFromInt_shouldOnlyWrite1Byte() { + final int writtenInt = Integer.MAX_VALUE; + outPacket.writeByte(writtenInt); + + byte[] bytes = outPacket.getBytes(); + assertEquals(2 + 1, bytes.length); // 2 for opcode + } + + @Test + void writeBytes() { + byte[] writtenBytes = {101, 102, 103}; + outPacket.writeBytes(writtenBytes); + + ByteBuf wrapped = wrapExplicitlyWrittenBytes(outPacket); + + assertEquals(101, wrapped.readByte()); + assertEquals(102, wrapped.readByte()); + assertEquals(103, wrapped.readByte()); + } + + @Test + void writeShort() { + final short writtenShort = 4312; + outPacket.writeShort(writtenShort); + + ByteBuf wrapped = wrapExplicitlyWrittenBytes(outPacket); + short readShort = wrapped.readShortLE(); + + assertEquals(writtenShort, readShort); + } + + @Test + void whenWritingShortFromInt_shouldOnlyWrite2Bytes() { + final int writtenInt = Integer.MAX_VALUE; + outPacket.writeShort(writtenInt); + + byte[] bytes = outPacket.getBytes(); + assertEquals(2 + 2, bytes.length); // 2 for opcode + } + + @Test + void writeShortFromInt() { + final int writtenInt = 34_567; + outPacket.writeShort(writtenInt); + + ByteBuf wrapped = wrapExplicitlyWrittenBytes(outPacket); + short readShort = wrapped.readShortLE(); + + assertEquals((short) writtenInt, readShort); + } + + @Test + void writeInt() { + final int writtenInt = 1_010_101_010; + outPacket.writeInt(writtenInt); + + ByteBuf wrapped = wrapExplicitlyWrittenBytes(outPacket); + int readInt = wrapped.readIntLE(); + + assertEquals(writtenInt, readInt); + } + + @Test + void writeLong() { + final long writtenLong = 100_200_300_400_500_600L; + outPacket.writeLong(writtenLong); + + ByteBuf wrapped = wrapExplicitlyWrittenBytes(outPacket); + long readLong = wrapped.readLongLE(); + + assertEquals(writtenLong, readLong); + } + + @Test + void writeBoolean_true() { + outPacket.writeBoolean(true); + + ByteBuf wrapped = wrapExplicitlyWrittenBytes(outPacket); + byte readByte = wrapped.readByte(); + + assertEquals(1, readByte); + } + + @Test + void writeBoolean_false() { + outPacket.writeBoolean(false); + + ByteBuf wrapped = wrapExplicitlyWrittenBytes(outPacket); + byte readByte = wrapped.readByte(); + + assertEquals(0, readByte); + } + + @Test + void writeString() { + final String writtenString = "You've been weakened, making you unable to jump."; + outPacket.writeString(writtenString); + + ByteBuf wrapped = wrapExplicitlyWrittenBytes(outPacket); + int length = wrapped.readShortLE(); + byte[] stringBytes = new byte[length]; + wrapped.readBytes(stringBytes); + String readString = new String(stringBytes, StandardCharsets.US_ASCII); + + assertEquals(writtenString, readString); + } + + @Test + void writePoint() { + final Point writtenPoint = new Point(23, 42); + outPacket.writePoint(writtenPoint); + + ByteBuf wrapped = wrapExplicitlyWrittenBytes(outPacket); + short readX = wrapped.readShortLE(); + short readY = wrapped.readShortLE(); + + assertEquals((short) writtenPoint.getX(), readX); + assertEquals((short) writtenPoint.getY(), readY); + } + + @Test + void whenSkipping_shouldWriteZeroes() { + final byte firstWrittenByte = 9; + final byte secondWrittenByte = 11; + outPacket.writeByte(firstWrittenByte); + outPacket.skip(2); + outPacket.writeByte(secondWrittenByte); + + ByteBuf wrapped = wrapExplicitlyWrittenBytes(outPacket); + + assertEquals(firstWrittenByte, wrapped.readByte()); + assertEquals(0, wrapped.readByte()); + assertEquals(0, wrapped.readByte()); + assertEquals(secondWrittenByte, wrapped.readByte()); + } +} \ No newline at end of file From 72ff8d563baada9fcbd731a192db9f76f8ce3b3c Mon Sep 17 00:00:00 2001 From: P0nk Date: Mon, 21 Jun 2021 22:03:20 +0200 Subject: [PATCH 14/14] Refactor packet string charset --- src/main/java/net/packet/ByteBufInPacket.java | 9 +++------ src/main/java/net/packet/OutPacket.java | 4 ---- src/main/java/net/packet/Packet.java | 5 +++++ src/test/java/net/packet/ByteBufInPacketTest.java | 3 +-- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/main/java/net/packet/ByteBufInPacket.java b/src/main/java/net/packet/ByteBufInPacket.java index d1b9f4f87e..0977172354 100644 --- a/src/main/java/net/packet/ByteBufInPacket.java +++ b/src/main/java/net/packet/ByteBufInPacket.java @@ -47,12 +47,9 @@ public class ByteBufInPacket implements InPacket { @Override public String readString() { short length = readShort(); - char[] characters = new char[length]; - for(int i = 0; i < length; i++) { - characters[i] = (char) readByte(); - } - - return String.valueOf(characters); + byte[] stringBytes = new byte[length]; + byteBuf.readBytes(stringBytes); + return new String(stringBytes, STRING_CHARSET); } @Override diff --git a/src/main/java/net/packet/OutPacket.java b/src/main/java/net/packet/OutPacket.java index 615f932db0..57e953a6f7 100644 --- a/src/main/java/net/packet/OutPacket.java +++ b/src/main/java/net/packet/OutPacket.java @@ -1,12 +1,8 @@ package net.packet; import java.awt.*; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; public interface OutPacket extends Packet { - Charset STRING_CHARSET = StandardCharsets.US_ASCII; - void writeByte(byte value); void writeByte(int value); void writeBytes(byte[] value); diff --git a/src/main/java/net/packet/Packet.java b/src/main/java/net/packet/Packet.java index 8e1b7cfb99..79f257cd38 100644 --- a/src/main/java/net/packet/Packet.java +++ b/src/main/java/net/packet/Packet.java @@ -1,5 +1,10 @@ package net.packet; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + public interface Packet { + Charset STRING_CHARSET = StandardCharsets.US_ASCII; + byte[] getBytes(); } diff --git a/src/test/java/net/packet/ByteBufInPacketTest.java b/src/test/java/net/packet/ByteBufInPacketTest.java index 1ed28e1d56..80a611abd8 100644 --- a/src/test/java/net/packet/ByteBufInPacketTest.java +++ b/src/test/java/net/packet/ByteBufInPacketTest.java @@ -6,7 +6,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.awt.*; -import java.nio.charset.StandardCharsets; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -82,7 +81,7 @@ class ByteBufInPacketTest { void readString() { final String writtenString = "You have gained experience (+3200)"; byteBuf.writeShortLE(writtenString.length()); - byte[] writtenStringBytes = writtenString.getBytes(StandardCharsets.US_ASCII); + byte[] writtenStringBytes = writtenString.getBytes(Packet.STRING_CHARSET); byteBuf.writeBytes(writtenStringBytes); String readString = inPacket.readString();