Refactored the processing of incoming packets to do so synchronously on the start of the tick cycle (rather than being processed as soon as the packet is received)

Decoupled decoding of packets from processing of packets, so that both 530 and 578 packets can be decoded into the same data structures and processed the same way
De-spaghettied many things, e.g. farming and the poster in stronghold of player safety
This commit is contained in:
Ceikry
2022-12-07 12:40:49 +00:00
committed by Ryan
parent 7f9656d40a
commit 4193e6131c
43 changed files with 1941 additions and 2611 deletions
@@ -8,9 +8,11 @@ import core.game.node.entity.player.link.request.RequestModule;
import core.game.node.item.GroundItemManager;
import core.game.node.item.Item;
import core.game.system.monitor.PlayerMonitor;
import rs09.game.system.SystemLogger;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@@ -395,6 +397,8 @@ public final class TradeModule implements RequestModule {
private void giveContainers(final TradeModule module) {
final Container pContainer = module.getContainer();
final Container oContainer = TradeModule.getExtension(module.getTarget()).getContainer();
SystemLogger.logTrade(module.getPlayer().getUsername() + " -> " + module.getTarget().getUsername() + " " + Arrays.toString(pContainer.toArray()));
SystemLogger.logTrade(module.getTarget().getUsername() + " -> " + module.getPlayer().getUsername() + " " + Arrays.toString(oContainer.toArray()));
addContainer(module.getPlayer(), module.getTarget(), oContainer);
addContainer(module.getTarget(), module.getPlayer(), pContainer);
module.getTarget().getPacketDispatch().sendMessage("Accepted trade.");
@@ -1,5 +1,6 @@
package core.game.node.entity.skill.firemaking
import core.game.node.item.GroundItem
import org.rs09.consts.Items
import rs09.game.interaction.InteractionListener
import rs09.game.interaction.IntType
@@ -13,5 +14,9 @@ class FiremakingListener : InteractionListener
player.pulseManager.run(FireMakingPulse(player, with.asItem(), null))
return@onUseWith true
}
onUseWith(IntType.GROUNDITEM, Items.TINDERBOX_590, *logs) { player, _, with ->
player.pulseManager.run(FireMakingPulse(player, with.asItem(), with as GroundItem))
return@onUseWith true
}
}
}
@@ -7,6 +7,9 @@ import core.net.IoSession;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
import core.net.packet.PacketRepository;
import rs09.net.packet.PacketProcessor;
import rs09.net.packet.in.Decoders530;
import rs09.net.packet.in.Packet;
import java.nio.ByteBuffer;
@@ -94,21 +97,17 @@ public final class GameReadEvent extends IoReadEvent {
buffer.get(data);
IoBuffer buf = new IoBuffer(opcode, null, ByteBuffer.wrap(data));
//SystemLogger.log("Packet opcode " + opcode + "received.");
IncomingPacket packet = PacketRepository.getIncoming(opcode);
//IncomingPacket packet = PacketRepository.getIncoming(opcode);
session.setLastPing(System.currentTimeMillis());
if (packet == null) {
SystemLogger.logErr(this.getClass(), "Unhandled packet [opcode=" + opcode + ", previous=" + last + ", size=" + size + ", header=" + header + "]");
if (GameWorld.getSettings().isDevMode()) {
SystemLogger.logErr(this.getClass(), "Unhandled packet [opcode=" + opcode + ", previous=" + last + ", size=" + size + ", header=" + header + "]");
}
continue;
}
last = opcode;
try {
packet.decode(session.getPlayer(), opcode, buf);
//System.out.println("Handled packed " + opcode + "!");
} catch (Throwable t) {
t.printStackTrace();
Packet processed = Decoders530.process(session.getPlayer(), opcode, buf);
if (processed instanceof Packet.UnhandledOp) {
SystemLogger.logWarn(this.getClass(), "Unhandled opcode: " + opcode);
} else if (processed instanceof Packet.DecodingError) {
SystemLogger.logErr(this.getClass(), ((Packet.DecodingError) processed).getMessage());
} else if (!(processed instanceof Packet.NoProcess)) {
PacketProcessor.enqueue(processed);
}
}
}
@@ -1,13 +1,9 @@
package core.net.packet;
import core.net.packet.in.*;
import core.net.packet.out.GrandExchangePacket;
import core.net.packet.out.*;
import rs09.game.system.SystemLogger;
import rs09.net.packet.PacketWriteQueue;
import rs09.net.packet.in.ItemOnGroundItemPacket;
import rs09.net.packet.in.QuickChatPacketHandler;
import rs09.net.packet.in.RunScriptPacketHandler;
import java.util.HashMap;
import java.util.Map;
@@ -23,11 +19,6 @@ public final class PacketRepository {
*/
public final static Map<Class<?>, OutgoingPacket<? extends Context>> OUTGOING_PACKETS = new HashMap<>();
/**
* The incoming packets mapping.
*/
private final static Map<Integer, IncomingPacket> INCOMING_PACKETS = new HashMap<>();
/**
* Populate the mappings.
*/
@@ -80,105 +71,6 @@ public final class PacketRepository {
OUTGOING_PACKETS.put(CSConfigPacket.class, new CSConfigPacket()); //
OUTGOING_PACKETS.put(Varbit.class, new Varbit());
OUTGOING_PACKETS.put(VarcUpdate.class, new VarcUpdate());
INCOMING_PACKETS.put(22, new ClientFocusPacket());
INCOMING_PACKETS.put(93, new PingPacketHandler());
INCOMING_PACKETS.put(44, new CommandPacket());
INCOMING_PACKETS.put(237, new ChatPacket());
INCOMING_PACKETS.put(21, new CameraMovementPacket());
INCOMING_PACKETS.put(75, new MouseClickPacket());
INCOMING_PACKETS.put(243, new DisplayUpdatePacket());
INCOMING_PACKETS.put(177, new UpdateInterfaceCounter());
INCOMING_PACKETS.put(4, new DummyPacket());
INCOMING_PACKETS.put(245, new IdlePacketHandler());
INCOMING_PACKETS.put(111, new core.net.packet.in.GrandExchangePacket());
IncomingPacket packet = new WalkPacket();
INCOMING_PACKETS.put(39, packet);
INCOMING_PACKETS.put(77, packet);
INCOMING_PACKETS.put(215, packet);
packet = new ItemActionPacket();
INCOMING_PACKETS.put(134, packet);//item on object
INCOMING_PACKETS.put(115, packet);//on npc
INCOMING_PACKETS.put(27, packet);//item on item
INCOMING_PACKETS.put(248, packet);//on player
INCOMING_PACKETS.put(101,new ItemOnGroundItemPacket()); //Item on Ground Item
INCOMING_PACKETS.put(3, packet = new InteractionPacket());
INCOMING_PACKETS.put(180, packet);//Player interact options v
INCOMING_PACKETS.put(68, packet);
INCOMING_PACKETS.put(71, packet);
INCOMING_PACKETS.put(114, packet);
INCOMING_PACKETS.put(175, packet);//Player interact options ^
INCOMING_PACKETS.put(30, packet);
INCOMING_PACKETS.put(78, packet);
INCOMING_PACKETS.put(148, packet);
INCOMING_PACKETS.put(218, packet);
INCOMING_PACKETS.put(84, packet);
INCOMING_PACKETS.put(170, packet);
INCOMING_PACKETS.put(254, packet);
INCOMING_PACKETS.put(194, packet);
INCOMING_PACKETS.put(66, packet);
INCOMING_PACKETS.put(33, packet);
INCOMING_PACKETS.put(247, packet);
INCOMING_PACKETS.put(156, packet = new ActionButtonPacket()); //Item V
INCOMING_PACKETS.put(55, packet);
INCOMING_PACKETS.put(153, packet);
INCOMING_PACKETS.put(161, packet);
INCOMING_PACKETS.put(135, packet); //^
INCOMING_PACKETS.put(81, packet);
INCOMING_PACKETS.put(184, packet);//close interface
INCOMING_PACKETS.put(155, packet); //Interface V
INCOMING_PACKETS.put(196, packet);
INCOMING_PACKETS.put(124, packet);
INCOMING_PACKETS.put(199, packet);
INCOMING_PACKETS.put(234, packet);
INCOMING_PACKETS.put(168, packet);
INCOMING_PACKETS.put(166, packet);
INCOMING_PACKETS.put(64, packet);
INCOMING_PACKETS.put(53, packet);
INCOMING_PACKETS.put(9, packet); //^
INCOMING_PACKETS.put(132, packet); //Dialogue
INCOMING_PACKETS.put(10, packet); //logout
INCOMING_PACKETS.put(206, packet);//operate
INCOMING_PACKETS.put(72, packet = new ExaminePacket());
INCOMING_PACKETS.put(92, packet);
INCOMING_PACKETS.put(94, packet);
/*INCOMING_PACKETS.put(57, packet);
INCOMING_PACKETS.put(34, packet);
INCOMING_PACKETS.put(213, packet);*/
//INCOMING_PACKETS.put(69, packet);
//packet 98 - 530 settings interface
INCOMING_PACKETS.put(104, packet = new ClanPacketHandler());
INCOMING_PACKETS.put(188, packet);
INCOMING_PACKETS.put(162, packet);
INCOMING_PACKETS.put(157, new ChatSettingsPacket());
INCOMING_PACKETS.put(244, packet = new RunScriptPacketHandler());
INCOMING_PACKETS.put(23, packet);
INCOMING_PACKETS.put(65, packet);
INCOMING_PACKETS.put(110, new RegionChangePacket());
INCOMING_PACKETS.put(195, packet = new InterfaceUseOnPacket());
INCOMING_PACKETS.put(239, packet);
INCOMING_PACKETS.put(73, packet);
INCOMING_PACKETS.put(253, packet);
INCOMING_PACKETS.put(233, packet);
INCOMING_PACKETS.put(231, packet = new SlotSwitchPacket());
INCOMING_PACKETS.put(79, packet);
INCOMING_PACKETS.put(167, new QuickChatPacketHandler());
INCOMING_PACKETS.put(201, packet = new CommunicationPacket());
INCOMING_PACKETS.put(120, packet);
INCOMING_PACKETS.put(57, packet);
INCOMING_PACKETS.put(34, packet);
INCOMING_PACKETS.put(213, packet);
INCOMING_PACKETS.put(99, packet = new ReportAbusePacket());
INCOMING_PACKETS.put(98, packet = new MapClosedPacket()); // this packet is sent when the world map is closed by the client
INCOMING_PACKETS.put(137,packet = new MusicPacketHandler()); //this packet is received when the client stops playing a song
// INCOMING_PACKETS.put(77, packet);
// INCOMING_PACKETS.put(191, packet);
// INCOMING_PACKETS.put(139, packet);
// INCOMING_PACKETS.put(251, packet);
// INCOMING_PACKETS.put(55, packet);
//Packet 22 is sent on focus gain/loss
//packet 177 is sent when opening/closing interfaces
}
/**
@@ -199,12 +91,4 @@ public final class PacketRepository {
}
}
/**
* Gets an incoming packet.
* @param opcode The opcode.
* @return The incoming packet.
*/
public static IncomingPacket getIncoming(int opcode) {
return INCOMING_PACKETS.get(opcode);
}
}
@@ -1,350 +0,0 @@
package core.net.packet.in;
import api.events.ButtonClickEvent;
import core.game.component.Component;
import core.game.component.ComponentPlugin;
import core.game.container.Container;
import core.game.content.dialogue.DialogueAction;
import core.game.interaction.Option;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.info.login.LoginConfiguration;
import core.game.node.entity.player.link.request.assist.AssistSession;
import core.game.node.item.Item;
import core.game.system.task.Pulse;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
import rs09.game.interaction.InterfaceListeners;
import rs09.game.world.GameWorld;
import java.util.List;
/**
* The incoming reward button packet.
* @author Emperor
*/
public class ActionButtonPacket implements IncomingPacket {
@Override
public void decode(final Player player, int opcode, IoBuffer buffer) {
if (player == null) {
return;
}
int[] args = getArguments(player, buffer);
if (args == null || (buffer.opcode() != 76 && args[0] != 106 && args[0] != 108 && args[0] != 110 && args[0] != 646 && player.getLocks().isComponentLocked() && player.getExtension(AssistSession.class) == null)) {
player.debug("Check this code in reward button packet, where args arent null && opcode !=");
return;
}
int componentId = args[0];
int buttonId = args[1];
int slot = args[2];
int itemId = args[3];
player.debug("Component=" + componentId + ", button=" + buttonId + ", slot=" + slot + ", item=" + itemId + ", opcode=" + buffer.opcode());
if (player.getDialogueInterpreter().getDialogue() != null && buffer.opcode() != 132 && componentId != 64) {
player.getDialogueInterpreter().close();
}
if (player.getLocks().isComponentLocked()) {
return;
}
if (itemId > -1 && slot > -1) {
Container container = getContainer(player, componentId);
if (container != null) {
handleItemInteraction(player, buffer.opcode(), itemId, slot, container);
return;
}
}
if (player.getZoneMonitor().clickButton(componentId, buttonId, slot, itemId, opcode)) {
return;
}
Component c = player.getInterfaceManager().getComponent(componentId);
if (c == null || c.isHidden()) {
player.debug("Component " + c + " wasn't opened in interface manager.");
return;
}
int cOpcode = buffer.opcode();
ComponentPlugin plugin = c.getPlugin();
player.dispatch(new ButtonClickEvent(c.getId(), buttonId));
if (plugin != null) {
player.debug("Component plugin = " + plugin.getClass().getSimpleName());
plugin.handle(player, c, cOpcode, buttonId, slot, itemId);
} else {
if(InterfaceListeners.run(player,c,cOpcode,buttonId,slot,itemId)){
return;
}
}
}
/**
* Gets the container for the component id.
* @param player The player.
* @param componentId The component id.
* @return The container.
*/
private Container getContainer(Player player, int componentId) {
switch (componentId) {
case 149:
return player.getInventory();
}
return null;
}
/**
* Gets the arguments for the reward button.
* @param player The player.
* @param buffer The buffer.
* @return The arguments [component, button, slot, item]
*/
private static int[] getArguments(final Player player, IoBuffer buffer) {
int data = -1;
int componentId = -1;
int buttonId = -1;
int itemId = -1;
int slot = -1;
switch (buffer.opcode()) {
case 81:
//System.out.println("Using action handler81");
slot = buffer.getShortA();
itemId = buffer.getShort();
buttonId = buffer.getShort();
componentId = buffer.getShort();
break;
case 156:
//System.out.println("Using action handler156");
slot = buffer.getLEShortA();
itemId = buffer.getShortA();
data = buffer.getLEInt();
componentId = data >> 16;
buttonId = data & 0xffff;
break;
case 55:
//System.out.println("Using action handler55");
itemId = buffer.getLEShort();
slot = buffer.getShortA();
data = buffer.getIntA();
componentId = data >> 16;
buttonId = data & 0xffff;
break;
case 153:
//System.out.println("Using action handler153");
data = buffer.getLEInt();
slot = buffer.getLEShort();
itemId = buffer.getLEShort();
componentId = (data >> 16) & 0xFFFF;
buttonId = data & 0xFFFF;
break;
case 161:
//System.out.println("Using action handler161");
data = buffer.getLEInt();
itemId = buffer.getLEShortA();
slot = buffer.getLEShortA();
componentId = (data >> 16) & 0xFFFF;
buttonId = data & 0xFFFF;
break;
case 135:
//System.out.println("Using action handler135");
itemId = buffer.getShortA();
slot = buffer.getShortA();
data = buffer.getIntB();
componentId = (data >> 16) & 0xFFFF;
buttonId = data & 0xFFFF;
break;
case 155: //Interface options
case 196:
case 124:
case 199:
case 234:
case 168:
case 166:
case 64:
case 53:
case 9:
//System.out.println("Using action handler155-9");
data = buffer.getInt();
slot = buffer.getShort();
componentId = (data >> 16) & 0xFFFF;
buttonId = data & 0xFFFF;
break;
case 132: //Dialogue options
//System.out.println("Using action handler132");
data = buffer.getIntA();
slot = buffer.getLEShort();
componentId = data >> 16;
buttonId = data & 0xffff;
if (player.getDialogueInterpreter().getDialogue() == null) {
player.getInterfaceManager().closeChatbox();
List<DialogueAction> actions = player.getDialogueInterpreter().getActions();
if (actions.size() > 0) {
DialogueAction action = actions.get(0);
action.handle(player, buttonId);
actions.remove(action);
}
break;
}
player.getDialogueInterpreter().handle(componentId, buttonId);
break;
case 133:
//System.out.println("Using action handler133");
data = buffer.getLEInt();
componentId = (data >> 16) & 0xFFFF;
buttonId = data & 0xFFFF;
slot = buffer.getShort();
itemId = buffer.getLEShortA();
break;
case 206:
//System.out.println("Using action handler206");
itemId = buffer.getShortA();
slot = buffer.getLEShort();
data = buffer.getLEInt();
componentId = (data >> 16) & 0xFFFF;
buttonId = data & 0xFFFF;
//player.sendMessage("itemId=" + itemId + ", data=" + data + ", buttonId=" + buttonId + ", compId= " + componentId);
break;
case 230: // Short
case 180:
case 10:
//System.out.println("Using action handler230-10");
data = buffer.getInt();
componentId = data >> 16;
buttonId = data & 0xffff;
if (buffer.opcode() == 230) {
slot = buffer.getShort();
}
if (componentId == 49) {
if (player.getDialogueInterpreter().getDialogue() == null) {
player.setAttribute("chatbox-buttonid",buttonId);
player.getInterfaceManager().closeChatbox();
return null;
}
player.setAttribute("chatbox-buttonid",buttonId);
player.getDialogueInterpreter().getDialogue().handle(componentId, buttonId);
}
break;
case 157:
//System.out.println("Using action handler157");
itemId = buffer.getLEShort();
slot = buffer.getLEShort();
data = buffer.getLEInt();
componentId = data >> 16;
buttonId = data & 0xffff;
break;
case 39:
//System.out.println("Using action handler39");
data = buffer.getInt();
slot = buffer.getShort();
componentId = (data >> 16) & 0xFFFF;
buttonId = data & 0xFFFF;
break;
case 128:
//System.out.println("Using action handler128");
data = buffer.getInt();
slot = buffer.getShort();
componentId = (data >> 16) & 0xFFFF;
buttonId = data & 0xffff;
break;
case 235:
//System.out.println("Using action handler235");
data = buffer.getInt();
slot = buffer.getShort();
componentId = (data >> 16) & 0xFFFF;
buttonId = data & 0xffff;
break;
case 243:
//System.out.println("Using action handler243");
data = buffer.getInt();
itemId = buffer.getShortA();
slot = buffer.getLEShortA();
componentId = data >> 16;
buttonId = data & 0xffff;
break;
case 170:
//System.out.println("Using action handler170");
slot = buffer.getLEShort();
itemId = buffer.getShortA();
data = buffer.getLEInt();
componentId = (data >> 16) & 0xFFFF;
buttonId = data & 0xFFFF;
break;
case 145:
//System.out.println("Using action handler145");
data = buffer.getIntB();
itemId = buffer.getShortA();
slot = buffer.getLEShort();
componentId = (data >> 16) & 0xFFFF;
buttonId = data & 0xffff;
// TODO dialogue with store X.
break;
case 127:// 3rd option on send item.
case 203:// 5th option on send item.
case 205:// 2 option
case 211:// 4rth option on send item.
case 187: // 6th
//System.out.println("Using action handler127-187");
data = buffer.getInt();
slot = buffer.getShort();
componentId = data >> 16;
buttonId = data & 0xffff;
itemId = -1;
break;
case 184:
case 95:
//System.out.println("Using action handler184-95");
if (player.getAttribute("logging_in") != null) {
player.getInterfaceManager().close();
GameWorld.getPulser().submit(new Pulse(1, player) {
@Override
public boolean pulse() {
player.removeAttribute("logging_in");
LoginConfiguration.configureGameWorld(player);
return true;
}
});
}
player.getInterfaceManager().close();
if (player.getAttribute("worldMap:viewing") != null) {
player.removeAttribute("worldMap:viewing");
player.getPacketDispatch().sendWindowsPane(player.getInterfaceManager().isResizable() ? 746 : 548, 2);
player.unlock();
}
break;
}
return new int[] { componentId, buttonId, slot, itemId };
}
/**
* Handles an item interaction.
* @param player The player.
* @param opcode The opcode.
* @param itemId The item.
*/
private static void handleItemInteraction(Player player, int opcode, int itemId, int slot, Container container) {
if (slot < 0 || slot >= container.capacity()) {
return;
}
Item item = container.get(slot);
if (item == null || item.getId() != itemId) {
return;
}
int index = 0;
switch (opcode) {
case 156: // First option
index = 0;
break;
case 55: // Second option (wield/wear)
index = 1;
break;
case 153: // Third option
index = 2;
break;
case 161: // Fourth option (summon)
index = 3;
break;
case 135: // Fifth option (drop/destroy)
index = 4;
break;
}
final Option option = item.getInteraction().get(index);
if (option == null || player.getLocks().isInteractionLocked()) {
return;
}
item.getInteraction().handleItemOption(player, option, container);
}
}
@@ -1,19 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.player.Player;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
/**
* Handles an incoming camera movement changed packet.
* @author Emperor
*/
public final class CameraMovementPacket implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
buffer.getShortA();
buffer.getLEShort();
}
}
@@ -1,56 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.player.Player;
import core.game.system.monitor.PlayerMonitor;
import core.game.system.task.Pulse;
import proto.management.ClanMessage;
import rs09.game.world.GameWorld;
import core.game.world.update.flag.context.ChatMessage;
import core.game.world.update.flag.player.ChatFlag;
import core.net.amsc.MSPacketRepository;
import core.net.amsc.WorldCommunicator;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
import core.tools.StringUtils;
import rs09.worker.ManagementEvents;
/**
* Represents the incoming chat packet.
* @author Emperor
*/
public class ChatPacket implements IncomingPacket {
@Override
public void decode(final Player player, int opcode, IoBuffer buffer) {
try {
final int effects = buffer.getShort();
final int numChars = buffer.getSmart();
final String message = StringUtils.decryptPlayerChat(buffer, numChars);
if (player.getDetails().isMuted()) {
player.getPacketDispatch().sendMessage("You have been " + (player.getDetails().isPermMute() ? "permanently" : "temporarily") + " muted due to breaking a rule.");
return;
}
if (message.startsWith("/") && player.getCommunication().getClan() != null) {
ClanMessage.Builder builder = ClanMessage.newBuilder();
builder.setSender(player.getName());
builder.setClanName(player.getCommunication().getClan().getOwner().toLowerCase().replace(" ", "_"));
builder.setMessage(message.substring(1));
builder.setRank(player.getDetails().getRights().ordinal());
ManagementEvents.publish(builder.build());
return;
}
player.getMonitor().log(message, PlayerMonitor.PUBLIC_CHAT_LOG);
ChatMessage ctx = new ChatMessage(player, message, effects, numChars);
GameWorld.getPulser().submit(new Pulse(0, player) {
@Override
public boolean pulse() {
player.getUpdateMasks().register(new ChatFlag(ctx));
return true;
}
});
} catch (Throwable t) {
t.printStackTrace();
}
}
}
@@ -1,26 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.player.Player;
import core.net.amsc.MSPacketRepository;
import core.net.amsc.WorldCommunicator;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
/**
* Handles an incoming chat settings update packet.
* @author Emperor
*/
public final class ChatSettingsPacket implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
int publicSetting = buffer.get();
int privateSetting = buffer.get();
int tradeSetting = buffer.get();
if (WorldCommunicator.isEnabled()) {
MSPacketRepository.sendChatSetting(player, publicSetting, privateSetting, tradeSetting);
}
player.getSettings().updateChatSettings(publicSetting, privateSetting, tradeSetting);
}
}
@@ -1,66 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.player.Player;
import core.game.system.communication.ClanRank;
import core.game.system.communication.ClanRepository;
import core.game.system.communication.CommunicationInfo;
import proto.management.JoinClanRequest;
import rs09.game.world.repository.Repository;
import core.net.amsc.MSPacketRepository;
import core.net.amsc.WorldCommunicator;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
import core.tools.StringUtils;
import rs09.worker.ManagementEvents;
/**
* Handles incoming clan packets.
* @author Emperor
*/
public class ClanPacketHandler implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
switch (buffer.opcode()) {
case 104:
if (player.getCommunication().getClan() != null) {
player.getCommunication().getClan().leave(player, true);
player.getCommunication().setClan(null);
return;
}
long nameLong = buffer.getLong();
String name = StringUtils.longToString(nameLong);
if (nameLong != 0L) {
player.getPacketDispatch().sendMessage("Attempting to join channel...:clan:");
}
JoinClanRequest.Builder builder = JoinClanRequest.newBuilder();
builder.setClanName(name);
builder.setUsername(player.getName());
ManagementEvents.publish(builder.build());
break;
case 188:
int rank = buffer.getA();
name = StringUtils.longToString(buffer.getLong());
if (WorldCommunicator.isEnabled()) {
MSPacketRepository.sendContactUpdate(player.getName(), name, false, false, ClanRank.values()[rank + 1]);
break;
}
CommunicationInfo.updateClanRank(player, name, ClanRank.values()[rank + 1]);
break;
case 162:
name = StringUtils.longToString(buffer.getLong());
if (WorldCommunicator.isEnabled()) {
MSPacketRepository.sendClanKick(player.getName(), name);
break;
}
ClanRepository clan = player.getCommunication().getClan();
Player target = Repository.getPlayerByName(name);
if (clan == null || target == null) {
break;
}
clan.kick(player, target);
break;
}
}
}
@@ -1,20 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.player.Player;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
/**
* Handles an incoming client focus changed packet.
* @author Emperor
*/
public final class ClientFocusPacket implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
if (player != null) {
player.getMonitor().setClientFocus(buffer.get() == 1);
}
}
}
@@ -1,35 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.player.Player;
import rs09.game.system.command.CommandSystem;
import core.game.system.monitor.PlayerMonitor;
import rs09.game.world.GameWorld;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
/**
* Handles an incoming command packet.
* @author Emperor
* @author 'Vexia
*/
public final class CommandPacket implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
final int data = buffer.get();
if (buffer.toByteBuffer().hasRemaining()) {
final String message = ((char) data + buffer.getString()).toLowerCase();
if (!GameWorld.getSettings().isDevMode()) {
int last = player.getAttribute("commandLast", 0);
if (last > GameWorld.getTicks()) {
return;
}
player.setAttribute("commandLast", GameWorld.getTicks() + 1);
}
if (CommandSystem.Companion.getCommandSystem().parse(player, message)) {
player.getMonitor().log(message, PlayerMonitor.COMMAND_LOG);
}
}
}
}
@@ -1,43 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.player.Player;
import core.game.system.communication.CommunicationInfo;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
import core.tools.StringUtils;
/**
* Represents the packet used to handle all incoming packets related to
* communication.
* @author 'Vexia
*/
public final class CommunicationPacket implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
switch (buffer.opcode()) {
case 120:
CommunicationInfo.add(player, StringUtils.longToString(buffer.getLong()));
break;
case 57:
CommunicationInfo.remove(player, StringUtils.longToString(buffer.getLong()), false);
break;
case 34:
CommunicationInfo.block(player, StringUtils.longToString(buffer.getLong()));
break;
case 213:
CommunicationInfo.remove(player, StringUtils.longToString(buffer.getLong()), true);
break;
case 201:
String name = StringUtils.longToString(buffer.getLong());
String message = StringUtils.decryptPlayerChat(buffer, buffer.get() & 0xFF);
if (player.getDetails().isMuted()) {
player.getPacketDispatch().sendMessage("You have been " + (player.getDetails().isPermMute() ? "permanently" : "temporarily") + " muted due to breaking a rule.");
return;
}
CommunicationInfo.sendMessage(player, name, message);
break;
}
}
}
@@ -1,26 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.player.Player;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
/**
* Handles the display update packet.
* @author Emperor
*
*/
public class DisplayUpdatePacket implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
int windowMode = buffer.get(); //Window mode
int screenWidth = buffer.getShort();
int screenHeight = buffer.getShort();
int displayMode = buffer.get(); //Display mode
player.getSession().getClientInfo().setScreenWidth(screenWidth);
player.getSession().getClientInfo().setScreenHeight(screenHeight);
player.getSession().getClientInfo().setDisplayMode(displayMode);
player.getInterfaceManager().switchWindowMode(windowMode);
}
}
@@ -1,13 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.player.Player;
import rs09.game.system.SystemLogger;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
public class DummyPacket implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
SystemLogger.logInfo(this.getClass(), "Received opcode " + opcode + " packet.");
}
}
@@ -1,63 +0,0 @@
package core.net.packet.in;
import core.cache.Cache;
import core.cache.def.impl.ItemDefinition;
import core.cache.def.impl.NPCDefinition;
import core.cache.def.impl.SceneryDefinition;
import core.cache.def.impl.VarbitDefinition;
import core.game.node.entity.player.Player;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
import org.rs09.consts.Items;
import java.util.Arrays;
/**
* Handles the incoming examine packets.
* @author Emperor
*/
public final class ExaminePacket implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
String name;
switch (buffer.opcode()) {
case 94: // Object examine
int id = buffer.getLEShortA();
if (id < 0 || id > Cache.getObjectDefinitionsSize()) {
break;
}
SceneryDefinition d = SceneryDefinition.forId(id);
name = d.getExamine();
//String coords = id + ", " + player.getLocation().getX() + ", " + player.getLocation().getY() + ", " + player.getLocation().getZ();
player.debug("Object id: " + id + ", models: " + (d.getModelIds() != null ? Arrays.toString(d.getModelIds()) : null) + ", anim: " + d.animationId + ", config: " + (d.getVarbitID() != -1 ? d.getVarbitID() + " (file)" : d.getConfigId()) + ".");
player.debug("Varp config index: " + VarbitDefinition.forObjectID(d.getVarbitID()).getVarpId());
player.getPacketDispatch().sendMessage(""+name+"");
/*if {
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection("LandscapeParser.removeGameObject(new GameObject("+coords+"));//"+ d.getName() ), null);
}*/
break;
case 235:
case 92: // Item examine
id = buffer.getLEShortA();
if (id < 0 || id > Cache.getItemDefinitionsSize()) {
break;
}
ItemDefinition itemDef = ItemDefinition.forId(id);
player.getPacketDispatch().sendMessage(itemDef.getExamine());
break;
case 72: // NPC examine
id = buffer.getShort();
if (id < 0 || id > Cache.getNPCDefinitionsSize()) {
break;
}
player.debug("NPC id: " + id + ".");
NPCDefinition def = NPCDefinition.forId(id);
if (def == null) {
break;
}
player.getPacketDispatch().sendMessage(def.getExamine());
break;
}
}
}
@@ -1,40 +0,0 @@
package core.net.packet.in;
import api.ContentAPIKt;
import core.game.node.entity.player.Player;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
import rs09.game.ge.GrandExchange;
import rs09.game.ge.GrandExchangeOffer;
import rs09.game.ge.PriceIndex;
import rs09.game.interaction.inter.ge.StockMarket;
/**
* Represents the <b>Incoming</b> packet of the grand exchange.
* @author Emperor
*/
public class GrandExchangePacket implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
int itemId = buffer.getShort();
GrandExchangeOffer offer = player.getAttribute("ge-temp", new GrandExchangeOffer());
int index = player.getAttribute("ge-index", -1);
offer.setItemID(itemId);
offer.setSell(false);
if(!PriceIndex.canTrade(offer.getItemID()))
{
ContentAPIKt.sendMessage(player, "That item is blacklisted from the grand exchange.");
return;
}
offer.setPlayer(player);
offer.setAmount(1);
offer.setOfferedValue(GrandExchange.getRecommendedPrice(itemId, false));
offer.setIndex(index);
StockMarket.updateVarbits(player, offer, index, false);
player.setAttribute("ge-temp",offer);
player.getPacketDispatch().sendString(GrandExchange.getOfferStats(itemId, false), 105, 142);
player.getInterfaceManager().closeChatbox();
}
}
@@ -1,26 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.info.Rights;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
import rs09.game.ai.general.GeneralBotCreator;
/**
* Handles the idle packet handler.
* @author Emperor
*/
public final class IdlePacketHandler implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
if (player.getDetails().getRights() != Rights.ADMINISTRATOR) {
GeneralBotCreator.BotScriptPulse pulse = player.getAttribute("botting:script",null);
if(pulse != null && pulse.isRunning()){
return;
}
player.getPacketDispatch().sendLogout();
}
}
}
@@ -1,413 +0,0 @@
package core.net.packet.in;
import core.cache.def.impl.SceneryDefinition;
import core.cache.def.impl.VarbitDefinition;
import core.game.content.quest.PluginInteractionManager;
import core.game.interaction.Interaction;
import core.game.interaction.MovementPulse;
import core.game.interaction.Option;
import core.game.interaction.SpecialGroundItems;
import core.game.node.Node;
import core.game.node.entity.impl.PulseType;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.item.GroundItem;
import core.game.node.item.GroundItemManager;
import core.game.node.scenery.Scenery;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
import core.net.packet.PacketRepository;
import core.net.packet.context.PlayerContext;
import core.net.packet.out.ClearMinimapFlag;
import rs09.ServerConstants;
import rs09.game.ai.AIPlayer;
import rs09.game.interaction.IntType;
import rs09.game.interaction.InteractionListener;
import rs09.game.interaction.InteractionListeners;
import rs09.game.world.repository.Repository;
import java.util.Arrays;
import java.util.List;
/**
* Handles the incoming interaction packets.
* @author Emperor
*/
public final class InteractionPacket implements IncomingPacket {
static int[] hweenNPCs = new int[] {307, 375, 743, 744, 755, 2634, 2690, 2691, 2692, 530, 531, 556, 557, 558, 559, 583, 585, 1860, 3299, 3671, 922, 970};
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
if (player == null) {
return;
}
if (buffer.opcode() != 105) {
player = getPlayer(player);
}
if (player.getLocks().isInteractionLocked() || !player.getInterfaceManager().close()) {
return;
}
player.getInterfaceManager().closeChatbox();
player.debug("Received " + buffer.opcode());
try {
switch (buffer.opcode()) {
case 78: // NPC reward 1
int index = buffer.getLEShort();
handleNPCInteraction(player, 0, index);
break;
case 3: // NPC reward 2
index = buffer.getLEShortA();
handleNPCInteraction(player, 1, index);
break;
case 148: // NPC reward 3
index = buffer.getShortA();
handleNPCInteraction(player, 2, index);
break;
case 30: // NPC reward 4
index = buffer.getShort();
handleNPCInteraction(player, 3, index);
break;
case 218: // NPC reward 5
index = buffer.getLEShort();
handleNPCInteraction(player, 4, index);
break;
case 254: // Object reward 1
int x = buffer.getLEShort();
int objectId = buffer.getShortA() & 0xFFFF;
int y = buffer.getShort();
handleObjectInteraction(player, 0, x, y, objectId);
break;
case 194: // Object reward 2
y = buffer.getLEShortA();
x = buffer.getLEShort();
objectId = buffer.getShort() & 0xFFFF;
handleObjectInteraction(player, 1, x, y, objectId);
break;
case 84: // Object reward 3
objectId = buffer.getLEShortA() & 0xFFFF;
y = buffer.getLEShortA();
x = buffer.getLEShort();
handleObjectInteraction(player, 2, x, y, objectId);
break;
case 152: // Object reward 4 TODO
objectId = buffer.getLEShortA() & 0xFFFF;
x = buffer.getLEShort();
y = buffer.getLEShortA();
handleObjectInteraction(player, 3, x, y, objectId);
break;
case 247://Object reward 4
y = buffer.getLEShort() & 0xFFFF;
x = buffer.getLEShortA();
objectId = buffer.getShort() & 0xFFFF;
handleObjectInteraction(player, 3, x, y, objectId);
break;
case 170: // Object reward 5
objectId = buffer.getLEShortA() & 0xFFFF;
x = buffer.getLEShortA();
y = buffer.getLEShortA();
handleObjectInteraction(player, 4, x, y, objectId);
break;
case 68: // Player reward 1 - Challenge
index = buffer.getLEShortA();
handlePlayerInteraction(player, 0, index);
break;
/*case : // Player reward 2 TODO
index = buffer.getLEShort();
handlePlayerInteraction(player, 1, index);
break;*/
case 71: // Player reward 3 - follow
index = buffer.getLEShortA();
handlePlayerInteraction(player, 2, index);
break;
case 180: // Player reward 4 - trade
index = buffer.getLEShortA();
handlePlayerInteraction(player, 3, index);
break;
/*case : // Player reward 5 TODO
index = buffer.getLEShortA();
handlePlayerInteraction(player, 4, index);
break;*/
/*case : // Player reward 6 TODO
index = buffer.getShort();
handlePlayerInteraction(player, 5, index);
break;*/
case 114: // Player reward 7 - req assistance
index = buffer.getLEShortA();
handlePlayerInteraction(player, 6, index);
break;
case 175: // Player reward 8 - "whack" (also "control" for AIPs)
index = buffer.getShortA();
handlePlayerInteraction(player, 7, index);
break;
case 66: // Ground item reward 1
x = buffer.getLEShort();
int itemId = buffer.getShort();
y = buffer.getLEShortA();
handleGroundItemInteraction(player, 2, itemId, Location.create(x, y, player.getLocation().getZ()));
break;
case 33: // Ground item reward 2
itemId = buffer.getShort();
x = buffer.getShort();
y = buffer.getLEShort();
handleGroundItemInteraction(player, 3, itemId, Location.create(x, y, player.getLocation().getZ()));
break;
}
} catch (Exception e){
e.printStackTrace();
}
}
/**
* Handles the NPC interaction.
* @param player the player.
* @param index the index.
*/
public static void handleNPCInteraction(Player player, int optionIndex, final int index) {
if (index < 1 || index > ServerConstants.MAX_NPCS) {
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
return;
}
final NPC npc = Repository.getNpcs().get(index);
if (npc == null) {
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
return;
}
if (player.getAttribute("removenpc", false)) {
npc.clear();
player.getPacketDispatch().sendMessage("Removed npc=" + npc.toString());
return;
}
NPC shown = npc.getShownNPC(player);
Option option = shown.getInteraction().get(optionIndex);
if (option == null) {
if (Arrays.stream(hweenNPCs).anyMatch(i -> i == shown.getId())) {
option = new Option("trick-or-treat", -1);
}
}
if(option == null) {
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
Interaction.handleInvalidInteraction(player, npc, Option.NULL);
return;
}
player.debug("NPC Interacting with \"" + shown.getUsername() + "\" [index=" + index + ", renderable=" + npc.isRenderable() + "]");
player.debug("option=" + option.getName() + ", slot=" + option.getIndex() + ", id=" + shown.getId() + " original=" + npc.getId() + ", location=" + npc.getLocation() + "");
player.debug("spawn=" + npc.getProperties().getSpawnLocation() + ".");
player.debug("Varp ID= " + npc.getDefinition().getConfigId() + " Offset=" + npc.getDefinition().getVarbitOffset() + " Size=" + npc.getDefinition().getVarbitSize());
handleAIPLegion(player, 0, optionIndex, index);
if(InteractionListeners.run(shown.getId(),IntType.NPC, option.getName(),player,npc)){
return;
}
if(PluginInteractionManager.handle(player,shown,option)){
return;
}
npc.getInteraction().handle(player, option);
}
/**
* Handles Node interaction with the first index
* @param player The interacting player.
* @param n The node to interact with.
*/
public static void handleObjectInteraction(final Player player, Node n)
{
handleObjectInteraction(player, 0, n.getLocation(), n.getId());
}
/**
* Handles object interaction
* @param player The interacting player.
* @param optionIndex The option index.
* @param l The (x,y) location of the object.
* @param objectId The object id.
*/
public static void handleObjectInteraction(final Player player, int optionIndex, Location l, int objectId) {
handleObjectInteraction(player, optionIndex, l.getX(), l.getY(), objectId);
}
/**
* Handles object interaction
* @param player The interacting player.
* @param optionIndex The option index.
* @param x The x-coordinate of the object.
* @param y The y-coordinate of the object.
* @param objectId The object id.
*/
public static void handleObjectInteraction(final Player player, int optionIndex, int x, int y, int objectId) {
Scenery object = RegionManager.getObject(player.getLocation().getZ(), x, y, objectId);
if (objectId == 29735) {//player safety.
player.getPulseManager().run(new MovementPulse(player, Location.create(x, y, player .getLocation().getZ())) {
@Override
public boolean pulse() {
player.getDialogueInterpreter().sendDialogue("There appears to be a tunnel behind the poster.");
player.getDialogueInterpreter().addAction((player1, buttonId) -> player1.teleport(new Location(3140, 4230, 2)));
return true;
}
}, PulseType.STANDARD);
return;
}
if (objectId == 6898) {
object = new Scenery(6898, new Location(3219, 9618));
} else if (objectId == 6899) {
object = new Scenery(6899, new Location(3221, 9618));
}
// Family crest levers don't have varps associated with them, so their state is validated with attributes
// instead, and they always appear as their down/odd variant in the server's map
if(2421 <= objectId && objectId <= 2426 && objectId % 2 == 0) {
object = new Scenery(objectId - 1, new Location(x, y, player.getLocation().getZ()));
objectId -= 1;
}
if (object == null || object.getId() != objectId) {
player.debug("Scenery(" + objectId + ") interaction was " + object + " at location " + x + ", " + y + ".");
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
Interaction.handleInvalidInteraction(player, object, Option.NULL);
return;
}
if (!object.isActive()) {
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
Interaction.handleInvalidInteraction(player, object, Option.NULL);
return;
}
object = object.getChild(player);
Option option = object.getInteraction().get(optionIndex);
if (option == null) {
player.debug("Invalid option" + object + ", original: " + objectId + ".");
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
Interaction.handleInvalidInteraction(player, object, Option.NULL);
return;
}
player.debug(object + ", original=" + objectId + ", option=" + option.getName() + "");
player.debug("dir=" + object.getDirection());
VarbitDefinition def = VarbitDefinition.forObjectID(SceneryDefinition.forId(objectId).getVarbitID());
player.debug("Varp ID=" + def.getVarpId() + " Offset=" + def.getStartBit() + " Size=" + def.getEndBit());
player.debug("Varbit: " + def.getId());
if (option.getHandler() != null) {
player.debug("Object handler: " + option.getHandler().getClass().getSimpleName());
}
handleAIPLegion(player, 1, optionIndex, x, y, objectId);
if(InteractionListeners.run(object.getId(), IntType.SCENERY, option.getName(),player,object)){
return;
}
if(PluginInteractionManager.handle(player,object)){
return;
}
object.getInteraction().handle(player, option);
}
/**
* Handles player interaction.
* @param player The player interacting.
* @param optionIndex The option index.
* @param index The target index.
*/
private static void handlePlayerInteraction(Player player, int optionIndex, int index) {
if (index < 1 || index > ServerConstants.MAX_PLAYERS) {
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
return;
}
final Player target = Repository.getPlayers().get(index);
if (target == null || !target.isActive()) {
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
return;
}
final Option option = player.getInteraction().get(optionIndex);
//Handling for "Pelt" option
if (option == null) {
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
return;
}
if (!InteractionListeners.run(-1, IntType.PLAYER, option.getName().toLowerCase(), player, target)) {
handleAIPLegion(player, 2, optionIndex, index);
target.getInteraction().handle(player, option);
}
}
/**
* Handles the ground item interaction.
* @param player The player.
* @param index The index of the reward.
* @param itemId The item id.
* @param location The location of the item.
*/
private static void handleGroundItemInteraction(final Player player, int index, int itemId, Location location) {
final GroundItem item = GroundItemManager.get(itemId, location, player);
SpecialGroundItems[] groundItems = SpecialGroundItems.values();
for(SpecialGroundItems specialItem : groundItems){
if(specialItem.getItemid() == itemId && specialItem.getLocation().getX() == location.getX() && specialItem.getLocation().getY() == location.getY()){
player.debug("Using special ground item handler");
specialItem.getInteraction().handle(player,item.getInteraction().get(index));
return;
}
}
if (item == null) {
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
return;
}
final Option option = item.getInteraction().get(index);
if (option == null) {
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
Interaction.handleInvalidInteraction(player, item, Option.NULL);
return;
}
if(PluginInteractionManager.handle(player,item,option)){
player.debug("Handled by quest interaction manager.");
return;
}
if(InteractionListeners.run(item.getId(), IntType.GROUNDITEM, option.getName(), player, item)) {
return;
}
if(InteractionListeners.run(item.getId(), IntType.ITEM, option.getName(), player, item)) {
return;
}
item.getInteraction().handle(player, option);
}
/**
* Handles the AIPlayer legion.
* @param player The player.
* @param type The interaction type.
* @param args The arguments.
*/
private static void handleAIPLegion(Player player, int type, int... args) {
if (player.isArtificial()) {
List<AIPlayer> legion = player.getAttribute("aip_legion");
if (legion != null) {
for (AIPlayer aip : legion) {
if (aip != player) {
switch (type) {
case 0:
handleNPCInteraction(aip, args[0], args[1]);
break;
case 1:
handleObjectInteraction(aip, args[0], args[1], args[2], args[3]);
break;
case 2:
handlePlayerInteraction(aip, args[0], args[1]);
break;
}
}
}
}
}
}
/**
* Gets the player instance (used for AIP controlling).
* @param player The player.
* @return The player instance, or the AIP when the player is controlling an
* AIP.
*/
private static Player getPlayer(Player player) {
AIPlayer aip = player.getAttribute("aip_select");
if (aip != null && aip.getLocation().withinDistance(player.getLocation())) {
return aip;
}
return player;
}
}
@@ -1,270 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.impl.PulseType;
import rs09.ServerConstants;
import core.game.node.entity.skill.magic.MagicSpell;
import core.game.node.entity.skill.summoning.familiar.FamiliarSpecial;
import core.game.interaction.MovementPulse;
import rs09.game.node.entity.combat.CombatSwingHandler;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.entity.player.link.SpellBookManager;
import core.game.node.item.GroundItemManager;
import core.game.node.item.Item;
import core.game.node.scenery.Scenery;
import rs09.game.node.entity.skill.magic.SpellListener;
import rs09.game.node.entity.skill.magic.SpellListeners;
import rs09.game.node.entity.skill.magic.SpellUtils;
import rs09.game.world.GameWorld;
import core.game.world.map.Location;
import core.game.world.map.RegionManager;
import rs09.game.world.repository.Repository;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
import core.net.packet.PacketRepository;
import core.net.packet.context.PlayerContext;
import core.net.packet.out.ClearMinimapFlag;
/**
* Handles the Interface "Use" on packets.
* @author Stacx
*/
public class InterfaceUseOnPacket implements IncomingPacket {
@SuppressWarnings("unused")
@Override
public void decode(final Player player, int opcode, IoBuffer buffer) {
int payload;
int interfaceId;
int componentId;
int itemId;
int x;
int y;
switch (buffer.opcode()) {
case 73: // Interface On GroundItem
componentId = buffer.getShort();
interfaceId = buffer.getShort();
y = buffer.getShort();
itemId = buffer.getLEShortA();
x = buffer.getLEShortA();
final int spell = buffer.getLEShort();
final Item groundItem = GroundItemManager.get(itemId, Location.create(x, y, player.getLocation().getZ()), player);
if (groundItem == null || !player.getLocation().withinDistance(groundItem.getLocation())) {
break;
}
if (player.getAttribute("magic:delay", -1) > GameWorld.getTicks()) {
break;
}
if (player.getZoneMonitor().clickButton(interfaceId, componentId, spell, itemId, opcode)) {
break;
}
if (CombatSwingHandler.isProjectileClipped(player, groundItem, false)) {
SpellListeners.run(spell, SpellListener.GROUND_ITEM, SpellUtils.getBookFromInterface(interfaceId),player,groundItem);
MagicSpell.castSpell(player, SpellBookManager.SpellBook.MODERN, spell, groundItem);
} else {
player.getPulseManager().run(new MovementPulse(player, groundItem) {
@Override
public boolean update() {
if (CombatSwingHandler.isProjectileClipped(player, groundItem, false)) {
super.destination = player.getLocation();
}
boolean finished = super.update();
if (finished) {
player.getWalkingQueue().reset();
}
return finished;
}
@Override
public boolean pulse() {
SpellListeners.run(spell, SpellListener.GROUND_ITEM,SpellUtils.getBookFromInterface(interfaceId),player,groundItem);
MagicSpell.castSpell(player, SpellBookManager.SpellBook.MODERN, spell, groundItem);
return true;
}
}, PulseType.STANDARD);
}
break;
case 195: // Interface On Player
//payload = buffer.getShortA();
buffer.getShortA();
componentId = buffer.getLEShort();
interfaceId = buffer.getLEShort();
int targetIndex = buffer.getLEShortA();
// Logger.log("Interface:" + interfaceId+ " Component:" +
// componentId + " Target Index:"+ targetIndex);
//System.out.println("magic on player component = "+componentId+"!");
final Player target = Repository.getPlayers().get(targetIndex);
if (target == null || !player.getLocation().withinDistance(target.getLocation())) {
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
break;
}
if(!SpellUtils.getBookFromInterface(interfaceId).equals("none")){
SpellListeners.run(componentId,SpellListener.PLAYER,SpellUtils.getBookFromInterface(interfaceId),player,target);
}
switch (interfaceId) {
case 192:
MagicSpell.castSpell(player, SpellBookManager.SpellBook.MODERN, componentId, target);
break;
case 193:
MagicSpell.castSpell(player, SpellBookManager.SpellBook.ANCIENT, componentId, target);
break;
case 430:
MagicSpell.castSpell(player, SpellBookManager.SpellBook.LUNAR, componentId, target);
break;
case 662:
switch (componentId) {
case 67:
case 69:
case 119:
case 121:
default:
if (!player.getFamiliarManager().hasFamiliar()) {
player.getPacketDispatch().sendMessage("You don't have a familiar.");
} else {
player.getFamiliarManager().getFamiliar().executeSpecialMove(new FamiliarSpecial(target));
}
break;
}
break;
default:
player.debug("Option usage [inter=" + interfaceId + ", child=" + componentId + ", target=" + target + "].");
}
break;
case 233: // Interface On Object
y = buffer.getLEShortA();
x = buffer.getShortA();
itemId = buffer.getLEShortA();
if (itemId == 65535) {
itemId = -1;
}
payload = buffer.getIntA();
interfaceId = payload >> 16;
componentId = payload & 0xFFFF;
int objectId = buffer.getShortA();
player.debug("Option usage [inter=" + interfaceId + ", child=" + componentId + ", target=(" + objectId + "," + x + "," + y + "), item=" + itemId + "].");
Scenery object = RegionManager.getObject(player.getLocation().getZ(), x, y);
if (object == null) {
object = RegionManager.getObject(Location.create(x, y, 0));
}
if (object != null) {
object = object.getChild(player);
}
if (object == null || (object.getId() != objectId && object.getWrapper().getId() != objectId) || !player.getLocation().withinDistance(object.getLocation())) {
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
break;
}
if(!SpellUtils.getBookFromInterface(interfaceId).equals("none")){
SpellListeners.run(componentId,SpellListener.OBJECT,SpellUtils.getBookFromInterface(interfaceId),player,object);
}
switch (interfaceId) {
case 430:
MagicSpell.castSpell(player, SpellBookManager.SpellBook.LUNAR, componentId, object);
break;
case 192:
MagicSpell.castSpell(player, SpellBookManager.SpellBook.MODERN, componentId, object);
break;
case 662:
switch (componentId) {
case 137:
default:
player.getFamiliarManager().getFamiliar().executeSpecialMove(new FamiliarSpecial(object));
break;
}
break;
}
break;
case 239: // Interface On NPC
componentId = buffer.getLEShort();
interfaceId = buffer.getLEShort();
buffer.getShortA();
int index = buffer.getLEShortA();
if (index < 1 || index > ServerConstants.MAX_NPCS) {
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
break;
}
NPC npc = Repository.getNpcs().get(index);
if (npc == null || !player.getLocation().withinDistance(npc.getLocation())) {
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
break;
}
if (player.getAttribute("magic:delay", -1) > GameWorld.getTicks()) {
break;
}
if(!SpellUtils.getBookFromInterface(interfaceId).equals("none")){
SpellListeners.run(componentId,SpellListener.NPC, SpellUtils.getBookFromInterface(interfaceId),player,npc);
}
switch (interfaceId) {
case 430:
MagicSpell.castSpell(player, SpellBookManager.SpellBook.LUNAR, componentId, npc);
break;
case 192:
MagicSpell.castSpell(player, SpellBookManager.SpellBook.MODERN, componentId, npc);
break;
case 193:
MagicSpell.castSpell(player, SpellBookManager.SpellBook.ANCIENT, componentId, npc);
break;
case 662:
switch (componentId) {
case 67:
case 69:
case 177:
case 121:
case 119:
default:
if (!player.getFamiliarManager().hasFamiliar()) {
player.getPacketDispatch().sendMessage("You don't have a familiar.");
} else {
player.getFamiliarManager().getFamiliar().executeSpecialMove(new FamiliarSpecial(npc));
}
break;
}
break;
default:
player.debug("Option usage [inter=" + interfaceId + ", child=" + componentId + ", target=" + npc + "].");
}
break;
case 253: // Interface On Item
componentId = buffer.getLEShort();
interfaceId = buffer.getLEShort();
int itemSlot = buffer.getLEShortA();
itemId = buffer.getShortA();
buffer.getShortA();
if (itemSlot < 0 || itemSlot > 27) {
break;
}
Item item = player.getInventory().get(itemSlot);
if (item == null) {
break;
}
if(!SpellUtils.getBookFromInterface(interfaceId).equals("none")){
SpellListeners.run(componentId,SpellListener.ITEM,SpellUtils.getBookFromInterface(interfaceId),player,item);
}
switch (interfaceId) {
case 430:
if (player.getAttribute("magic:delay", -1) > GameWorld.getTicks()) {
break;
}
MagicSpell.castSpell(player, SpellBookManager.SpellBook.LUNAR, componentId, item);
break;
case 192:
if (player.getAttribute("magic:delay", -1) > GameWorld.getTicks()) {
break;
}
MagicSpell.castSpell(player, SpellBookManager.SpellBook.MODERN, componentId, item);
break;
case 662:
if (player.getFamiliarManager().hasFamiliar()) {
player.getFamiliarManager().getFamiliar().executeSpecialMove(new FamiliarSpecial(item, interfaceId, componentId, item));
} else {
player.getPacketDispatch().sendMessage("You don't have a follower.");
}
break;
default:
player.debug("Option usage [inter=" + interfaceId + ", child=" + componentId + ", target=" + item + "].");
}
break;
}
}
}
@@ -1,247 +0,0 @@
package core.net.packet.in;
import core.game.content.quest.PluginInteractionManager;
import core.game.interaction.DestinationFlag;
import core.game.interaction.MovementPulse;
import core.game.interaction.NodeUsageEvent;
import core.game.interaction.UseWithHandler;
import core.game.node.entity.npc.NPC;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.game.node.scenery.Scenery;
import core.game.world.map.RegionManager;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
import core.net.packet.PacketRepository;
import core.net.packet.context.PlayerContext;
import core.net.packet.out.ClearMinimapFlag;
import org.rs09.consts.Items;
import rs09.game.interaction.IntType;
import rs09.game.interaction.InteractionListeners;
import rs09.game.node.entity.skill.farming.CompostBins;
import rs09.game.node.entity.skill.farming.FarmingPatch;
import rs09.game.node.entity.skill.farming.UseWithBinHandler;
import rs09.game.node.entity.skill.farming.UseWithPatchHandler;
import rs09.game.system.SystemLogger;
import rs09.game.system.command.rottenpotato.RottenPotatoUseWithHandler;
import rs09.game.world.repository.Repository;
/**
* The incoming item reward packet.
* @author Emperor
*/
public class ItemActionPacket implements IncomingPacket {
@SuppressWarnings("unused")
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
if (player.getLocks().isInteractionLocked()) {
return;
}
int usedWithItemId = -1;
int usedWithSlot = -1;
int interfaceHash1 = -1;
int interfaceId1 = -1;
int childId1 = -1;
int usedItemId = -1;
int usedSlot = -1;
int interfaceHash2 = -1;
int interfaceId2 = -1;
int childId2 = -1;
NodeUsageEvent event = null;
Item used = null;
player.debug(String.format("ItemActionPacket.decode(%d)", opcode));
switch (buffer.opcode()) {
case 115: // Item on NPC
int interfaceId = buffer.getIntA() >> 16;
int slotId = buffer.getLEShort();
int npcIndex = buffer.getLEShort();
int itemId = buffer.getLEShortA();
NPC npc = Repository.getNpcs().get(npcIndex);
Item item = player.getInventory().get(slotId);
if (item == null || item.getId() != itemId) {
return;
}
if(itemId == Items.ROTTEN_POTATO_5733){
RottenPotatoUseWithHandler.handle(npc,player);
return;
}
event = new NodeUsageEvent(player, interfaceId, item, npc);
if(PluginInteractionManager.handle(player,event)){
return;
}
if(InteractionListeners.run(item,npc,IntType.NPC,player)){
return;
}
if(player.getZoneMonitor().useWith(used,npc)){
return;
}
event = new NodeUsageEvent(player, interfaceId, item, npc);
try {
UseWithHandler.run(event);
} catch (Exception e){
e.printStackTrace();
}
return;
case 248: // Item on Player
int playerIndex = buffer.getLEShortA();
itemId = buffer.getShort();
slotId = buffer.getShort();
interfaceId = buffer.getInt() >> 16;
Player target = Repository.getPlayers().get(playerIndex);
item = player.getInventory().get(slotId);
if (target == null || item == null || item.getId() != itemId) {
return;
}
if(itemId == Items.ROTTEN_POTATO_5733){
RottenPotatoUseWithHandler.handle(target,player);
return;
}
event = new NodeUsageEvent(player, interfaceId, item, target);
if(PluginInteractionManager.handle(player,event)){
return;
}
if(InteractionListeners.run(item, target, IntType.PLAYER, player)){
return;
}
if(player.getZoneMonitor().useWith(used,player)){
return;
}
event = new NodeUsageEvent(player, interfaceId, item, target);
try {
UseWithHandler.run(event);
} catch (Exception e){
e.printStackTrace();
}
return;
case 27://Item on Item
usedSlot = buffer.getShort();
interfaceHash1 = buffer.getLEInt();
usedWithSlot = buffer.getLEShort();
interfaceHash2 = buffer.getLEInt();
usedItemId = buffer.getLEShortA();
usedWithItemId = buffer.getLEShortA();
interfaceId1 = interfaceHash1 >> 16;
childId1 = interfaceHash1 & 0xFFFF;
interfaceId2 = interfaceHash2 >> 16;
childId2 = interfaceHash2 & 0xFFFF;
used = player.getInventory().get(usedSlot);
Item with = player.getInventory().get(usedWithSlot);
if (used == null || with == null || used.getId() != usedItemId || with.getId() != usedWithItemId) {
return;
}
if(used.getId() == Items.ROTTEN_POTATO_5733){
RottenPotatoUseWithHandler.handle(with,player);
return;
}
if(with.getId() == Items.ROTTEN_POTATO_5733){
RottenPotatoUseWithHandler.handle(used,player);
return;
}
if(InteractionListeners.run(used,with,IntType.ITEM,player)){
return;
}
if(player.getZoneMonitor().useWith(used,with)){
return;
}
if (usedItemId < usedWithItemId) {
item = used;
used = with;
with = item;
}
player.debug("USED: " + used + " WITH: " + with);
event = new NodeUsageEvent(player, interfaceId1, used, with);
if(PluginInteractionManager.handle(player,event)){
return;
}
event = new NodeUsageEvent(player, interfaceId1, used, with);
try {
UseWithHandler.run(event);
} catch (Exception e){
e.printStackTrace();
}
break;
case 134://Item on Object
int x = buffer.getShortA();
int id = buffer.getShort();
int y = buffer.getLEShort();
int slot = buffer.getShort();
buffer.getLEShort();
buffer.getShort();
int objectId = buffer.getShortA();
int z = player.getLocation().getZ();
Scenery object = RegionManager.getObject(z, x, y);
//player.debug(String.format("opcode 134: oid %d iid %d", objectId, id));
//player.debug(String.format("opcode 134: %d %d", object != null ? object.getId() : -1, object != null && object.getChild(player) != null ? object.getChild(player).getId() : -1));
Scenery child = object != null ? object.getChild(player) : null;
if(object == null || (object.getId() != objectId && (child == null || child.getId() != objectId))) {
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
return;
}
used = player.getInventory().get(slot);
if (used == null || used.getId() != id) {
return;
}
if(used.getId() == Items.ROTTEN_POTATO_5733){
RottenPotatoUseWithHandler.handle(object,player);
return;
}
if(InteractionListeners.run(used,child,IntType.SCENERY,player)){
return;
}
if(InteractionListeners.run(used,object,IntType.SCENERY,player)){
return;
}
if(player.getZoneMonitor().useWith(used,object)){
return;
}
event = new NodeUsageEvent(player, 0, used, child != null ? child : object);
/**
* Farming-specific handler for item -> patch
*/
if(FarmingPatch.forObject(object) != null && UseWithPatchHandler.allowedNodes.contains(used.getId())){
NodeUsageEvent finalEvent = event;
player.getPulseManager().run(new MovementPulse(player,object, DestinationFlag.OBJECT) {
@Override
public boolean pulse() {
player.faceLocation(destination.getLocation());
UseWithPatchHandler.handle(finalEvent);
return true;
}
});
return;
}
/**
* Farming-specific handler for item -> compost bin
*/
if(CompostBins.forObject(object) != null && UseWithBinHandler.allowedNodes.contains(used.getId())){
NodeUsageEvent finalEvent = event;
player.getPulseManager().run(new MovementPulse(player,object,DestinationFlag.OBJECT){
@Override
public boolean pulse() {
player.faceLocation(destination.getLocation());
UseWithBinHandler.handle(finalEvent);
return true;
}
});
return;
}
if(PluginInteractionManager.handle(player,event)){
return;
}
try {
UseWithHandler.run(event);
} catch (Exception e){
e.printStackTrace();
}
return;
default:
SystemLogger.logErr(this.getClass(), "Error in Item Action Packet! Unhandled opcode = " + buffer.opcode());
return;
}
}
}
@@ -1,12 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.player.Player;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
public class MapClosedPacket implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
//This buffer contains an int that is actually a bunch of booleans bitshifted into specific positions. No clue what the use might be.
}
}
@@ -1,27 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.player.Player;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
/**
* Handles incoming mouse click packets.
* @author Emperor
*/
public final class MouseClickPacket implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
int data = buffer.getLEShortA();
int positioning = buffer.getIntB();
boolean rightClick = ((data >> 15) & 0x1) == 1;
int delay = data & 0x7FF;
int x = positioning >> 16;
int y = positioning & 0xFFFF;
if (player == null) {
return;
}
player.getMonitor().handleMouseClick(x, y, delay, rightClick);
}
}
@@ -1,23 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.player.Player;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
/**
* Handles music-related incoming packets.
* @author Ceikry
*/
public final class MusicPacketHandler implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
int musicId = buffer.getLEShortA();
if (player.getMusicPlayer().isLooping()) {
player.getMusicPlayer().replay();
return;
}
player.getMusicPlayer().setPlaying(false);
}
}
@@ -1,18 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.player.Player;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
/**
* Handles an incoming ping packet.
* @author Emperor
*/
public final class PingPacketHandler implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
}
}
@@ -1,19 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.player.Player;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
/**
* Packet received when a player's region has changed.
* @author Emperor
* @author 'Vexia
*/
public class RegionChangePacket implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
//TODO: no data is sen't so not sure what to do.
}
}
@@ -1,36 +0,0 @@
package core.net.packet.in;
import rs09.ServerConstants;
import core.game.content.global.report.AbuseReport;
import core.game.content.global.report.Rule;
import core.game.node.entity.player.Player;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
import core.tools.StringUtils;
import rs09.game.world.GameWorld;
import java.io.File;
/**
* Represents the incoming packet to handle a report against a player.
* @author Vexia
*/
public class ReportAbusePacket implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
String target = StringUtils.longToString(buffer.getLong());
Rule rule = Rule.forId(buffer.get());
boolean mute = buffer.get() == 1;
if (!GameWorld.getAccountStorage().checkUsernameTaken(target.toLowerCase())) {
player.getPacketDispatch().sendMessage("Invalid player name.");
return;
}
if (target.equalsIgnoreCase(player.getUsername())) {
player.getPacketDispatch().sendMessage("You can't report yourself!");
return;
}
AbuseReport abuse = new AbuseReport(player.getName(), target, rule);
abuse.construct(player, mute);
}
}
@@ -1,119 +0,0 @@
package core.net.packet.in;
import core.game.container.Container;
import core.game.container.impl.BankContainer;
import core.game.node.entity.player.Player;
import core.game.node.item.Item;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
import static api.ContentAPIKt.getAttribute;
/**
* Represents the packet to handle an item slot switch.
* @author 'Vexia
*/
public class SlotSwitchPacket implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
if (buffer.opcode() == 79) {
int interfaceHash = buffer.getIntB();
int secondSlot = buffer.getLEShort();
int interfaceHash2 = buffer.getInt();
int slot = buffer.getLEShort();
int interfaceId = interfaceHash >> 16;
int childId = interfaceHash & 0xFF;
int withInterfaceId = interfaceHash2 >> 16;
int withChildId = interfaceHash2 & 0xFF;
Container container = player.getInventory();
switch (interfaceId) {
case 762:
if (withInterfaceId == 762) {
if (withChildId == 73) {
container = player.getBank();
switchItem(slot, secondSlot, container, player.getBank().isInsertItems(), player);
player.debug("Switching item [" + slot + ", " + interfaceId + ", " + childId + "] with [" + secondSlot + ", " + withInterfaceId + ", " + withChildId + "]!");
}
else {
int tabIndex = BankContainer.getArrayIndex(withChildId);
if (tabIndex > -1) {
secondSlot = tabIndex == 10 ? player.getBank().freeSlot() : player.getBank().getTabStartSlot()[tabIndex] + player.getBank().getItemsInTab(tabIndex);
Item inSlot = player.getBank().get(slot);
if (secondSlot == -1 && player.getBank().remove(inSlot)) {
player.getBank().add(inSlot);
return;
}
childId = player.getBank().getTabByItemSlot(slot);
if (secondSlot > slot) {
player.getBank().insert(slot, secondSlot - 1);
} else if (slot > secondSlot) {
player.getBank().insert(slot, secondSlot);
}
player.getBank().increaseTabStartSlots(tabIndex);
player.getBank().decreaseTabStartSlots(childId);
player.getBank().setTabConfigurations();
return;
}
}
break;
}
break;
default:
player.debug("Switching item slot [from=" + slot + ", to=" + secondSlot + ", child=" + childId + ", to child=" + withChildId + "].");
switchItem(slot, secondSlot, container, false, player);
break;
}
return;
}
int slot = buffer.getShort();
int interfaceHash = buffer.getLEInt();
int secondSlot = buffer.getShortA();
boolean insert = buffer.get() == 1;
int interfaceId = interfaceHash >> 16;
Container container = interfaceId == 762 ? player.getBank() : (interfaceId == 15 || interfaceId == 149 || interfaceId == 763) ? player.getInventory() : null;
switchItem(slot, secondSlot, container, insert, player);
}
/**
* Switches an item.
* @param slot The slot.
* @param secondSlot The slot to switch slots with.
* @param container The container.
* @param insert If inserting should happen.
*/
public void switchItem(int slot, int secondSlot, Container container, boolean insert, Player player) {
if (container == null || slot < 0 || slot >= container.toArray().length || secondSlot < 0 || secondSlot >= container.toArray().length) {
return;
}
final Item item = container.get(slot);
final Item second = container.get(secondSlot);
if (player.getInterfaceManager().hasChatbox() && !getAttribute(player, "close_c_", false)) {
player.getInterfaceManager().closeChatbox();
switchItem(secondSlot,slot,container,insert,player);
container.refresh();
return;
}
if (item == null) {
return;
}
if (!insert) {
container.replace(second, slot, false);
container.replace(item, secondSlot, false);
if (item != null) {
item.setIndex(secondSlot);
}
if (second != null) {
second.setIndex(slot);
}
} else {
container.insert(slot, secondSlot, false);
}
container.refresh();
}
}
@@ -1,20 +0,0 @@
package core.net.packet.in;
import core.game.node.entity.player.Player;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
/**
* Handles the update interface packet counter packet.
* @author Emperor
*
*/
public final class UpdateInterfaceCounter implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
int count = buffer.getShort() - player.getInterfaceManager().getPacketCount(0);
player.getInterfaceManager().getPacketCount(count);
}
}
@@ -1,102 +0,0 @@
package core.net.packet.in;
import core.game.interaction.MovementPulse;
import core.game.node.entity.Entity;
import core.game.node.entity.impl.PulseType;
import core.game.node.entity.player.Player;
import rs09.game.ai.AIPlayer;
import core.game.world.map.Location;
import core.net.packet.IncomingPacket;
import core.net.packet.IoBuffer;
import core.net.packet.PacketRepository;
import core.net.packet.context.PlayerContext;
import core.net.packet.out.ClearMinimapFlag;
/**
* Handles an incoming walk packet.
* @author Emperor
*/
public final class WalkPacket implements IncomingPacket {
@Override
public void decode(Player player, int opcode, IoBuffer buffer) {
player = getPlayer(player);
if (player == null) {
return;
}
if (player.getLocks().isMovementLocked() || !player.getInterfaceManager().close() || !player.getInterfaceManager().closeSingleTab() || !player.getDialogueInterpreter().close()) {
PacketRepository.send(ClearMinimapFlag.class, new PlayerContext(player));
player.debug("[WalkPacket] did not handle - [locked=" + player.getLocks().isMovementLocked() + "]!");
return;
}
player.getProperties().setSpell(null);
player.getInterfaceManager().close();
player.getInterfaceManager().closeChatbox();
player.getDialogueInterpreter().getActions().clear();
boolean running = buffer.getA() == 1;
int x = buffer.getShort();
int y = buffer.getShortA();
int steps = (buffer.toByteBuffer().remaining() - (buffer.opcode() == 39 ? 14 : 0)) >> 1;
for (int i = 0; i < steps; i++) {
int offsetX = buffer.getA();
int offsetY = buffer.getS();
if (i == steps - 1) {
x += offsetX;
y += offsetY;
}
}
if (opcode == 77) {
player.getWalkingQueue().setRunning(running);
return; // Action walking.
}
player.face((Entity) null);
player.faceLocation((Location) null);
//player.getWalkingQueue().reset(running);
Player finalPlayer = player;
player.getPulseManager().run(new MovementPulse(finalPlayer, Location.create(x, y, player.getLocation().getZ()), running) {
@Override
public boolean pulse() {
if(running){
finalPlayer.getWalkingQueue().setRunning(false);
}
return true;
}
}, PulseType.STANDARD);
if (opcode == 39) {
buffer.get(); // The x-coordinate of where we clicked on the
// minimap.
buffer.get(); // The y-coordinate of where we clicked on the
// minimap.
buffer.getShort(); // The rotation of the minimap.
buffer.get(); // Always 57.
buffer.get();
buffer.get();
buffer.get(); // Always 89
buffer.getShort();
buffer.getShort();
buffer.get();
buffer.get(); // Always 63
}
}
/**
* Gets the player instance (used for AIP controlling).
* @param player The player.
* @return The player instance, or the AIP when the player is controlling an
* AIP.
*/
private static Player getPlayer(Player player) {
if (player == null) {
return null;
}
AIPlayer aip = player.getAttribute("aip_select");
if (aip != null && aip.getLocation().withinDistance(player.getLocation())) {
if (!player.getAttribute("aip_perm_select", true)) {
player.removeAttribute("aip_select");
}
return aip;
}
return player;
}
}
@@ -21,7 +21,6 @@ import core.game.world.map.path.Pathfinder;
import core.game.world.map.zone.impl.WildernessZone;
import rs09.game.world.repository.Repository;
import core.net.packet.context.MessageContext;
import core.net.packet.in.InteractionPacket;
import core.plugin.Plugin;
import core.tools.RandomFunction;
import core.tools.StringUtils;
@@ -578,6 +577,6 @@ public class AIPlayer extends Player {
public void interact(Node n) {
InteractionPacket.handleObjectInteraction(this, 0, n.getLocation(), n.getId());
// InteractionPacket.handleObjectInteraction(this, 0, n.getLocation(), n.getId());
}
}
@@ -10,6 +10,7 @@ import core.game.world.map.Location
import core.game.world.map.zone.ZoneBorders
import core.game.world.update.flag.context.Animation
import org.rs09.consts.NPCs
import rs09.game.ai.AIPlayer
import rs09.game.content.dialogue.DialogueFile
import rs09.game.world.GameWorld
@@ -19,7 +20,7 @@ class MorytaniaArea : MapArea {
}
override fun areaEnter(entity: Entity) {
if (entity is Player && !isQuestComplete(entity, "Priest in Peril")) {
if (entity is Player && entity !is AIPlayer && !isQuestComplete(entity, "Priest in Peril")) {
kickThemOut(entity)
}
}
@@ -178,6 +178,7 @@ object InteractionListeners {
val flag = when(type){
IntType.NPC, IntType.PLAYER -> DestinationFlag.ENTITY
IntType.SCENERY -> DestinationFlag.OBJECT
IntType.GROUNDITEM -> DestinationFlag.ITEM
else -> DestinationFlag.OBJECT
}
@@ -0,0 +1,18 @@
package rs09.game.interaction.region.dungeons.edgeville
import api.sendDialogue
import api.teleport
import core.game.world.map.Location
import org.rs09.consts.Scenery
import rs09.game.interaction.IntType
import rs09.game.interaction.InteractionListener
class PosterListener : InteractionListener {
override fun defineListeners() {
on(Scenery.POSTER_29586, IntType.SCENERY, "pull-back") {player, _ ->
sendDialogue(player, "There appears to be a tunnel behind this poster.")
teleport(player, Location.create(3140, 4230, 2))
return@on true
}
}
}
@@ -131,7 +131,6 @@ class CompostBin(val player: Player, val bin: CompostBins) {
}
if (isClosed) player.varpManager.get(bin.varpIndex).setVarbit(bin.varpOffest + 6, 1)
}
SystemLogger.logAlert(this::class.java, "Sending " + player.varpManager.get(bin.varpIndex).getValue())
player.varpManager.get(bin.varpIndex).send(player)
}
@@ -1,20 +1,85 @@
package rs09.game.node.entity.skill.farming
import api.toIntArray
import core.game.interaction.NodeUsageEvent
import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.update.flag.context.Animation
import org.rs09.consts.Items
import rs09.game.interaction.IntType
import rs09.game.interaction.InteractionListener
object UseWithBinHandler {
class UseWithBinHandler : InteractionListener {
@JvmField
val allowedNodes = ArrayList<Int>(100)
val fillAnim = Animation(832)
val compostPotionAnimation = Animation(2259)
val scoopAnimation = Animation(8905)
init {
val bins = 7836..7840
override fun defineListeners() {
loadNodes()
onUseWith(IntType.SCENERY, allowedNodes.toIntArray(), *bins.toIntArray()) {player, usedNode, with ->
val cBin = CompostBins.forObject(with.asScenery()) ?: return@onUseWith true
val bin = cBin.getBinForPlayer(player)
val used = usedNode.id
when(used){
Items.COMPOST_POTION1_6476,Items.COMPOST_POTION2_6474, Items.COMPOST_POTION3_6472,Items.COMPOST_POTION4_6470 -> {
if(!bin.isSuperCompost && bin.isFinished && !bin.isClosed){
player.animator.animate(compostPotionAnimation)
player.pulseManager.run(object : Pulse(compostPotionAnimation.duration){
override fun pulse(): Boolean {
if(player.inventory.remove(usedNode.asItem())) {
bin.convert()
player.inventory.add(Item(used.getNext()))
}
return true
}
})
} else {
player.dialogueInterpreter.sendDialogue("You can only do this with an open bin of","finished regular compost.")
}
}
Items.BUCKET_1925 -> {
if(bin.isFinished && !bin.isClosed){
player.pulseManager.run(object : Pulse(scoopAnimation.duration){
override fun pulse(): Boolean {
if(!player.inventory.containsItem(usedNode.asItem())) return true
player.animator.animate(scoopAnimation)
val item = bin.takeItem()
if(item != null && player.inventory.remove(usedNode.asItem())){
player.inventory.add(item)
}
return item == null || !player.inventory.containsItem(usedNode.asItem())
}
})
} else {
player.dialogueInterpreter.sendDialogue("You can only scoop an opened bin of finished compost.")
}
}
else ->
if(bin.isFull()){
player.sendMessage("This compost bin is already full.")
return@onUseWith true
} else {
player.pulseManager.run(object : Pulse(fillAnim.duration){
override fun pulse(): Boolean {
player.animator.animate(fillAnim)
if(player.inventory.remove(usedNode.asItem())){
bin.addItem(usedNode.asItem())
}
return bin.isFull() || player.inventory.getAmount(usedNode.asItem()) == 0
}
})
}
}
return@onUseWith true
}
}
fun loadNodes() {
@@ -32,70 +97,6 @@ object UseWithBinHandler {
allowedNodes.add(Items.BUCKET_1925)
}
@JvmStatic
fun handle(event: NodeUsageEvent?): Boolean {
event ?: return false
val player = event.player
val used = event.used.id
val cBin = CompostBins.forObject(event.usedWith.asScenery()) ?: return false
val bin = cBin.getBinForPlayer(player)
when(used){
Items.COMPOST_POTION1_6476,Items.COMPOST_POTION2_6474, Items.COMPOST_POTION3_6472,Items.COMPOST_POTION4_6470 -> {
if(!bin.isSuperCompost && bin.isFinished && !bin.isClosed){
player.animator.animate(compostPotionAnimation)
player.pulseManager.run(object : Pulse(compostPotionAnimation.duration){
override fun pulse(): Boolean {
if(player.inventory.remove(event.usedItem)) {
bin.convert()
player.inventory.add(Item(used.getNext()))
}
return true
}
})
} else {
player.dialogueInterpreter.sendDialogue("You can only do this with an open bin of","finished regular compost.")
}
}
Items.BUCKET_1925 -> {
if(bin.isFinished && !bin.isClosed){
player.pulseManager.run(object : Pulse(scoopAnimation.duration){
override fun pulse(): Boolean {
if(!player.inventory.containsItem(event.usedItem)) return true
player.animator.animate(scoopAnimation)
val item = bin.takeItem()
if(item != null && player.inventory.remove(event.usedItem)){
player.inventory.add(item)
}
return item == null || !player.inventory.containsItem(event.usedItem)
}
})
} else {
player.dialogueInterpreter.sendDialogue("You can only scoop an opened bin of finished compost.")
}
}
else ->
if(bin.isFull()){
player.sendMessage("This compost bin is already full.")
return true
} else {
player.pulseManager.run(object : Pulse(fillAnim.duration){
override fun pulse(): Boolean {
player.animator.animate(fillAnim)
if(player.inventory.remove(event.usedItem)){
bin.addItem(event.usedItem)
}
return bin.isFull() || player.inventory.getAmount(event.usedItem) == 0
}
})
}
}
return true
}
private fun Int.getNext(): Int{
if(this != 6476) return this + 2
else return Items.VIAL_229
@@ -8,9 +8,12 @@ import core.game.node.item.Item
import core.game.system.task.Pulse
import core.game.world.update.flag.context.Animation
import org.rs09.consts.Items
import org.rs09.consts.Scenery
import rs09.game.interaction.IntType
import rs09.game.interaction.InteractionListener
import rs09.game.node.entity.skill.farming.CropHarvester
object UseWithPatchHandler{
class UseWithPatchHandler : InteractionListener {
val RAKE = Items.RAKE_5341
val SEED_DIBBER = Items.SEED_DIBBER_5343
val SPADE = Items.SPADE_952
@@ -23,28 +26,15 @@ object UseWithPatchHandler{
@JvmField
val allowedNodes = ArrayList<Int>()
val patches = ArrayList<Int>()
init {
override fun defineListeners() {
loadNodes()
}
onUseWith(IntType.SCENERY, allowedNodes.toIntArray(), *patches.toIntArray()) {player, used, with ->
val patch = FarmingPatch.forObject(with.asScenery()) ?: return@onUseWith true
val usedItem = used.asItem()
@JvmStatic
fun loadNodes(){
for(p in Plantable.values()){
allowedNodes.add(p.itemID)
}
allowedNodes.addAll(arrayListOf(RAKE,SEED_DIBBER,SPADE,SECATEURS,TROWEL,Items.SUPERCOMPOST_6034,Items.COMPOST_6032,Items.PLANT_CURE_6036,Items.WATERING_CAN1_5333,Items.WATERING_CAN2_5334,Items.WATERING_CAN3_5335,Items.WATERING_CAN4_5336,Items.WATERING_CAN5_5337,Items.WATERING_CAN6_5338,Items.WATERING_CAN7_5339,Items.WATERING_CAN8_5340, Items.PLANT_POT_5350))
}
@JvmStatic
fun handle(event: NodeUsageEvent?): Boolean {
event ?: return false
val player = event.player
val usedItem = event.usedItem
val patch = FarmingPatch.forObject(event.usedWith.asScenery())
patch ?: return false
player.faceLocation(event.usedWith.location)
player.faceLocation(with.location)
when(usedItem.id){
RAKE -> PatchRaker.rake(player,patch)
SEED_DIBBER -> player.sendMessage("I should plant a seed, not the seed dibber.")
@@ -61,7 +51,7 @@ object UseWithPatchHandler{
}
})
} else if(p.plantable == Plantable.WILLOW_SAPLING && p.harvestAmt > 0) {
val pulse = CropHarvester.harvestPulse(player, event.usedWith, Items.WILLOW_BRANCH_5933) ?: return false
val pulse = CropHarvester.harvestPulse(player, with, Items.WILLOW_BRANCH_5933) ?: return@onUseWith false
player.pulseManager.run(pulse)
}
}
@@ -69,22 +59,22 @@ object UseWithPatchHandler{
TROWEL, Items.PLANT_POT_5350 -> {
if(!player.inventory.containsAtLeastOneItem(TROWEL)) {
player.sendMessage("You need a trowel to fill plant pots with dirt.")
return true
return@onUseWith true
}
val p = patch.getPatchFor(player)
if(!p.isWeedy()){
player.sendMessage("This patch has something growing in it.")
return true
return@onUseWith true
} else if (p.currentGrowthStage != 3){
player.sendMessage("I should clear this of weeds before trying to take some dirt.")
return true
return@onUseWith true
}
val potAmount = player.inventory.getAmount(Items.PLANT_POT_5350)
if(potAmount == 0){
player.sendMessage("You have no plant pots to fill.")
return true
return@onUseWith true
}
val anim = Animation(2272)
@@ -107,7 +97,7 @@ object UseWithPatchHandler{
override fun pulse(): Boolean {
player.animator.animate(plantCureAnim)
player.audioManager.send(2438)
if(player.inventory.remove(event.usedItem)){
if(player.inventory.remove(usedItem)){
player.inventory.add(Item(Items.VIAL_229))
p.cureDisease()
}
@@ -131,7 +121,7 @@ object UseWithPatchHandler{
}
player.animator.animate(wateringCanAnim)
player.audioManager.send(2446)
if(player.inventory.remove(event.usedItem)){
if(player.inventory.remove(usedItem)){
player.inventory.add(Item(usedItem.id.getNext()))
p.water()
}
@@ -148,7 +138,7 @@ object UseWithPatchHandler{
player.audioManager.send(2427)
player.pulseManager.run(object : Pulse(){
override fun pulse(): Boolean {
if(player.inventory.remove(event.usedItem,false)){
if(player.inventory.remove(usedItem,false)){
p.compost = if(usedItem.id == Items.SUPERCOMPOST_6034) CompostType.SUPER else CompostType.NORMAL
if(p.compost == CompostType.SUPER) rewardXP(player, Skills.FARMING, 26.0) else rewardXP(player, Skills.FARMING, 18.5)
if(p.plantable != null && p.plantable?.applicablePatch != PatchType.FLOWER) {
@@ -166,26 +156,25 @@ object UseWithPatchHandler{
}
else -> {
val plantable = Plantable.forItemID(usedItem.id)
if(plantable == null) return false
val plantable = Plantable.forItemID(usedItem.id) ?: return@onUseWith false
if(plantable.applicablePatch != patch.type){
player.sendMessage("You can't plant that seed in this patch.")
return true
return@onUseWith true
}
if(plantable.requiredLevel > player.skills.getLevel(Skills.FARMING)){
player.sendMessage("You need a Farming level of ${plantable.requiredLevel} to plant this.")
return true
return@onUseWith true
}
val p = patch.getPatchFor(player)
if(p.getCurrentState() < 3 && p.isWeedy()){
player.sendMessage("You must weed your patch before you can plant a seed in it.")
return true
return@onUseWith true
} else if(p.getCurrentState() > 3){
player.sendMessage("There is already something growing in this patch.")
return true
return@onUseWith true
}
val plantItem =
@@ -198,18 +187,18 @@ object UseWithPatchHandler{
if(patch.type == PatchType.ALLOTMENT){
if(!player.inventory.containsItem(plantItem)){
player.sendMessage("You need 3 seeds to plant an allotment patch.")
return true
return@onUseWith true
}
}
if(patch.type != PatchType.FRUIT_TREE && patch.type != PatchType.TREE){
if(!player.inventory.contains(Items.SEED_DIBBER_5343,1)){
player.sendMessage("You need a seed dibber to plant that.")
return true
return@onUseWith true
}
} else {
if(!player.inventory.contains(Items.SPADE_952,1)){
player.sendMessage("You need a spade to plant that.")
return true
return@onUseWith true
}
}
player.lock()
@@ -235,7 +224,32 @@ object UseWithPatchHandler{
}
}
return true
return@onUseWith true
}
}
fun loadNodes(){
patches.addAll(8550..8557) //allotment wrappers
patches.addAll(7847..7853) //flower patch wrappers
patches.addAll(8150..8156) //herb patch wrappers
patches.addAll(8388..8390) // Tree patches
patches.add(19147) //Tree patch
patches.addAll(7962..7965) //fruit trees
patches.addAll(8173..8176) //hops
patches.addAll(7577..7580) //bush
patches.add(23760) //evil turnip
patches.add(7572) //belladonna
patches.add(8337) //mushroom
patches.add(27197) //jade vine
patches.add(7771) //cactus
patches.add(7807) //calquat
patches.addAll(8382..8383)//spirit trees
patches.add(8338) //spirit tree
patches.add(18816) //death plateau wrapper
for(p in Plantable.values()){
allowedNodes.add(p.itemID)
}
allowedNodes.addAll(arrayListOf(RAKE,SEED_DIBBER,SPADE,SECATEURS,TROWEL,Items.SUPERCOMPOST_6034,Items.COMPOST_6032,Items.PLANT_CURE_6036,Items.WATERING_CAN1_5333,Items.WATERING_CAN2_5334,Items.WATERING_CAN3_5335,Items.WATERING_CAN4_5336,Items.WATERING_CAN5_5337,Items.WATERING_CAN6_5338,Items.WATERING_CAN7_5339,Items.WATERING_CAN8_5340, Items.PLANT_POT_5350))
}
private fun Int.getNext(): Int {
@@ -0,0 +1,743 @@
package rs09.net.packet
import api.events.ButtonClickEvent
import api.getAttribute
import api.sendMessage
import core.cache.def.impl.ItemDefinition
import core.cache.def.impl.NPCDefinition
import core.cache.def.impl.SceneryDefinition
import core.game.container.Container
import core.game.container.impl.BankContainer
import core.game.content.global.report.AbuseReport
import core.game.content.global.report.Rule
import core.game.content.quest.PluginInteractionManager
import core.game.interaction.Interaction
import core.game.interaction.MovementPulse
import core.game.interaction.NodeUsageEvent
import core.game.interaction.Option
import core.game.interaction.UseWithHandler
import core.game.node.Node
import core.game.node.entity.impl.PulseType
import core.game.node.entity.player.Player
import core.game.node.entity.player.info.Rights
import core.game.node.entity.player.info.login.LoginConfiguration
import core.game.node.entity.player.link.SpellBookManager
import core.game.node.entity.skill.magic.MagicSpell
import core.game.node.entity.skill.summoning.familiar.FamiliarSpecial
import core.game.node.item.GroundItemManager
import core.game.node.item.Item
import core.game.node.scenery.Scenery
import core.game.system.communication.ClanRank
import core.game.system.communication.CommunicationInfo
import core.game.system.monitor.PlayerMonitor
import core.game.system.task.Pulse
import core.game.world.map.Location
import core.game.world.map.RegionManager
import core.game.world.update.flag.context.ChatMessage
import core.game.world.update.flag.player.ChatFlag
import core.net.amsc.MSPacketRepository
import core.net.packet.PacketRepository
import core.net.packet.context.PlayerContext
import core.net.packet.out.ClearMinimapFlag
import discord.Discord
import org.rs09.consts.Components
import proto.management.ClanMessage
import proto.management.JoinClanRequest
import rs09.ServerConstants
import rs09.game.ge.GrandExchange
import rs09.game.ge.GrandExchange.Companion.getOfferStats
import rs09.game.ge.GrandExchange.Companion.getRecommendedPrice
import rs09.game.ge.GrandExchangeOffer
import rs09.game.ge.PriceIndex
import rs09.game.interaction.IntType
import rs09.game.interaction.InteractionListeners
import rs09.game.interaction.InterfaceListeners
import rs09.game.interaction.QCRepository
import rs09.game.interaction.inter.ge.StockMarket
import rs09.game.node.entity.skill.magic.SpellListener
import rs09.game.node.entity.skill.magic.SpellListeners
import rs09.game.node.entity.skill.magic.SpellUtils
import rs09.game.system.SystemLogger
import rs09.game.system.command.CommandSystem
import rs09.game.world.GameWorld
import rs09.game.world.repository.Repository
import rs09.net.packet.`in`.Packet
import rs09.net.packet.`in`.RunScript
import rs09.worker.ManagementEvents
import java.io.PrintWriter
import java.io.StringWriter
import java.util.*
object PacketProcessor {
val queue = LinkedList<Packet>()
@JvmStatic fun enqueue(pkt: Packet) {
queue.addLast(pkt)
}
@JvmStatic fun processQueue() {
var countThisCycle = queue.size
val sw = StringWriter()
val pw = PrintWriter(sw)
var pkt: Packet
while (countThisCycle-- > 0) {
pkt = queue.pop()
try {
process(pkt)
} catch (e: Exception) {
e.printStackTrace(pw)
SystemLogger.logErr(this::class.java, "Error Processing ${pkt::class.java.simpleName}: $sw")
}
}
}
private fun process(pkt: Packet) {
when (pkt) {
is Packet.ItemAction -> processItemAction(pkt)
is Packet.NpcAction -> processNpcAction(pkt)
is Packet.SceneryAction -> processSceneryAction(pkt)
is Packet.PlayerAction -> processPlayerAction(pkt)
is Packet.GroundItemAction -> processGroundItemAction(pkt)
is Packet.UseWithNpc,
is Packet.UseWithItem,
is Packet.UseWithScenery,
is Packet.UseWithGroundItem,
is Packet.UseWithPlayer -> processUseWith(pkt)
is Packet.IfAction -> processIfAction(pkt)
is Packet.CloseIface -> processCloseIface(pkt)
is Packet.WorldspaceWalk,
is Packet.MinimapWalk,
is Packet.InteractWalk -> processWalkPacket(pkt)
is Packet.AddFriend -> CommunicationInfo.add(pkt.player, pkt.username)
is Packet.RemoveFriend -> CommunicationInfo.remove(pkt.player, pkt.username, false)
is Packet.AddIgnore -> CommunicationInfo.block(pkt.player, pkt.username)
is Packet.RemoveIgnore -> CommunicationInfo.remove(pkt.player, pkt.username, true)
is Packet.ComponentItemAction,
is Packet.ComponentPlayerAction,
is Packet.ComponentNpcAction,
is Packet.ComponentSceneryAction,
is Packet.ComponentGroundItemAction -> processComponentUseWith(pkt)
is Packet.SlotSwitchSingleComponent,
is Packet.SlotSwitchMultiComponent -> processSlotSwitch(pkt)
is Packet.TrackingMouseClick,
is Packet.TrackingAfkTimeout,
is Packet.TrackingFocus,
is Packet.TrackingCameraPos,
is Packet.TrackingDisplayUpdate -> processTrackingPacket(pkt)
is Packet.PlayerPrefsUpdate -> {/*TODO implement something that cares about this */}
is Packet.Ping -> pkt.player.session.lastPing = System.currentTimeMillis()
is Packet.JoinClan -> {
if (pkt.clanName.isNotEmpty())
sendMessage(pkt.player, "Attempting to join channel....:clan:")
val builder = JoinClanRequest.newBuilder()
builder.clanName = pkt.clanName
builder.username = pkt.player.name
ManagementEvents.publish(builder.build())
}
is Packet.SetClanRank -> {
CommunicationInfo.updateClanRank(pkt.player, pkt.username, ClanRank.values()[pkt.rank + 1])
}
is Packet.KickFromClan -> {
val clan = pkt.player.communication.clan ?: return
val target = Repository.getPlayerByName(pkt.username) ?: return
clan.kick(pkt.player, target)
}
is Packet.QuickChat -> QCRepository.sendQC(pkt.player, pkt.multiplier, pkt.offset, pkt.type, pkt.indexA, pkt.indexB, pkt.forClan)
is Packet.InputPromptResponse -> {
val script: ((Any) -> Boolean) = pkt.player.getAttribute("runscript", null) ?: return
if (pkt.player.locks.isInteractionLocked)
return
try {
RunScript.processInput(pkt.player, pkt.response, script)
} finally {
pkt.player.removeAttribute("parseamount")
pkt.player.removeAttribute("runscript")
}
}
is Packet.ReportAbuse -> {
if (!GameWorld.accountStorage.checkUsernameTaken(pkt.target.lowercase())) {
sendMessage(pkt.player, "Invalid player name.")
return
}
if (pkt.target.equals(pkt.player.username, true)){
pkt.player.sendMessage("You can't report yourself!")
}
AbuseReport (
pkt.player.name,
pkt.target,
Rule.forId(pkt.rule)
).construct(pkt.player, pkt.modMute)
}
is Packet.TrackFinished -> {
if (pkt.player.musicPlayer.isLooping)
pkt.player.musicPlayer.replay()
else
pkt.player.musicPlayer.isPlaying = false
}
is Packet.GESetOfferItem -> {
val offer = pkt.player.getAttribute("ge-temp", GrandExchangeOffer())
val index = pkt.player.getAttribute("ge-index", -1)
offer.itemID = pkt.itemId
offer.sell = false
if (!PriceIndex.canTrade(pkt.itemId)) {
sendMessage(pkt.player, "That item is blacklisted from the grand exchange.")
return
}
offer.player = pkt.player
offer.amount = 1
offer.offeredValue = getRecommendedPrice(pkt.itemId, false)
offer.index = index
StockMarket.updateVarbits(pkt.player, offer, index, false)
pkt.player.setAttribute("ge-temp", offer)
pkt.player.packetDispatch.sendString(getOfferStats(pkt.itemId, false), 105, 142)
pkt.player.interfaceManager.closeChatbox()
}
is Packet.Command -> {
if (CommandSystem.commandSystem.parse(pkt.player, pkt.commandLine))
pkt.player.monitor.log(pkt.commandLine, PlayerMonitor.COMMAND_LOG)
}
is Packet.ChatMessage -> {
if (pkt.player.details.isMuted)
pkt.player.sendMessage("You have been muted due to breaking a rule.")
else {
if (pkt.message.startsWith("/") && pkt.player.communication.clan != null) {
val builder = ClanMessage.newBuilder()
builder.sender = pkt.player.name
builder.clanName = pkt.player.communication.clan.owner.lowercase().replace(" ", "_")
builder.message = pkt.message.substring(1)
builder.rank = pkt.player.rights.ordinal
ManagementEvents.publish(builder.build())
return
}
pkt.player.monitor.log(pkt.message, PlayerMonitor.PUBLIC_CHAT_LOG)
val ctx = ChatMessage(pkt.player, pkt.message, pkt.effects, pkt.message.length)
pkt.player.updateMasks.register(ChatFlag(ctx))
}
}
is Packet.ChatSetting -> {
MSPacketRepository.sendChatSetting(pkt.player, pkt.public, pkt.private, pkt.trade)
pkt.player.settings.updateChatSettings(pkt.public, pkt.private, pkt.trade)
}
is Packet.PrivateMessage -> {
if (pkt.player.details.isMuted)
pkt.player.sendMessage("You have been muted due to breaking a rule.")
else
CommunicationInfo.sendMessage(pkt.player, pkt.username, pkt.message)
}
is Packet.PacketCountUpdate -> {
val final = pkt.count - pkt.player.interfaceManager.getPacketCount(0)
pkt.player.interfaceManager.getPacketCount(final)
}
is Packet.DialogueOption -> {
val player = pkt.player
if (player.dialogueInterpreter.dialogue == null) {
player.interfaceManager.closeChatbox()
player.dialogueInterpreter.actions.removeFirstOrNull()?.handle(player, pkt.child)
return
}
player.dialogueInterpreter.handle(pkt.iface, pkt.child)
}
is Packet.ItemExamine -> {
val def = ItemDefinition.forId(pkt.id) ?: return
pkt.player.debug("[ITEM] ID: ${pkt.id} Value: ${def.value}")
pkt.player.sendMessage(def.examine)
}
is Packet.SceneryExamine -> {
val def = SceneryDefinition.forId(pkt.id) ?: return
pkt.player.debug("[SCENERY]---------------------")
pkt.player.debug("ID: ${pkt.id}")
if (def.configFile != null)
pkt.player.debug("Varbit: ${def.configFile.id}")
pkt.player.debug("------------------------------")
pkt.player.sendMessage(def.examine)
}
is Packet.NpcExamine -> {
val def = NPCDefinition.forId(pkt.id)
pkt.player.debug("[NPC]-------------------------")
pkt.player.debug("ID: ${pkt.id}")
if (def.configFileId != -1)
pkt.player.debug("Varbit: ${def.configFileId}")
pkt.player.debug("------------------------------")
pkt.player.sendMessage(def.examine)
}
else -> SystemLogger.logWarn(this::class.java, "Unprocessed Packet: ${pkt::class.java.simpleName}")
}
}
private fun processTrackingPacket(pkt: Packet) {
when(pkt) {
is Packet.TrackingFocus -> pkt.player.monitor.isClientFocus = pkt.isFocused
is Packet.TrackingDisplayUpdate -> {
pkt.player.session.clientInfo.screenWidth = pkt.screenWidth
pkt.player.session.clientInfo.screenHeight = pkt.screenHeight
pkt.player.session.clientInfo.displayMode = pkt.displayMode
pkt.player.interfaceManager.switchWindowMode(pkt.windowMode)
}
is Packet.TrackingAfkTimeout -> {
if (pkt.player.details.rights != Rights.ADMINISTRATOR)
pkt.player.packetDispatch.sendLogout()
}
is Packet.TrackingCameraPos -> {
//TODO Refactor the player monitor to be actually useful and log this
}
is Packet.TrackingMouseClick -> {
//TODO see above todo
if (!pkt.player.monitor.isClientFocus) {
Discord.postPlayerAlert(pkt.player.username, "Mouseclick without window focus!")
}
}
}
}
private fun processSlotSwitch(pkt: Packet) {
//TODO refactor this to function as callbacks to InterfaceListeners, e.g. onSlotSwitch
//TODO See above TODO, I hate Arios. This was hardcoded in the packet decoder.
if (pkt is Packet.SlotSwitchMultiComponent) {
if (pkt.destIface == 762) {
if (pkt.destChild == 73) {
val container = pkt.player.bank
switchItem(pkt.sourceSlot, pkt.destSlot, container, pkt.player.bank.isInsertItems, pkt.player)
} else {
val tabIndex = BankContainer.getArrayIndex(pkt.destChild)
if (tabIndex > -1) {
val secondSlot =
if (tabIndex == 10) pkt.player.bank.freeSlot() else pkt.player.bank.tabStartSlot[tabIndex] + pkt.player.bank.getItemsInTab(tabIndex)
val inSlot: Item = pkt.player.bank.get(pkt.sourceSlot)
if (secondSlot == -1 && pkt.player.bank.remove(inSlot)) {
pkt.player.bank.add(inSlot)
return
}
val childId = pkt.player.bank.getTabByItemSlot(pkt.sourceSlot)
if (secondSlot > pkt.sourceSlot) {
pkt.player.bank.insert(pkt.sourceSlot, secondSlot - 1)
} else if (pkt.sourceSlot > secondSlot) {
pkt.player.bank.insert(pkt.sourceSlot, secondSlot)
}
pkt.player.bank.increaseTabStartSlots(tabIndex)
pkt.player.bank.decreaseTabStartSlots(childId)
pkt.player.bank.setTabConfigurations()
return
}
}
return
} else {
switchItem(pkt.sourceSlot, pkt.destSlot, pkt.player.inventory, false, pkt.player)
}
}
else if (pkt is Packet.SlotSwitchSingleComponent) {
val container = if (pkt.iface == 762) pkt.player.bank else pkt.player.inventory
switchItem(pkt.sourceSlot, pkt.destSlot, container, pkt.isInsert, pkt.player)
}
}
private fun processComponentUseWith(pkt: Packet) {
val iface: Int
val child: Int
val target: Node
val targetId: Int
val player: Player
val type: Int
if (pkt is Packet.ComponentGroundItemAction) {
player = pkt.player
child = pkt.child
iface = pkt.iface
target = GroundItemManager.get(pkt.itemId, Location.create(pkt.x, pkt.y, player.location.z), player) ?: return sendClearMinimap(player).also { sendMessage(player, "Too late!") }
targetId = pkt.itemId
type = SpellListener.GROUND_ITEM
}
else if (pkt is Packet.ComponentPlayerAction) {
player = pkt.player
child = pkt.child
iface = pkt.iface
target = Repository.players[pkt.otherIndex] ?: return sendClearMinimap(player)
targetId = target.id
type = SpellListener.PLAYER
}
else if (pkt is Packet.ComponentSceneryAction) {
player = pkt.player
child = pkt.child
iface = pkt.iface
target = RegionManager.getObject(player.location.z, pkt.x, pkt.y) ?: return sendClearMinimap(player)
targetId = pkt.sceneryId
type = SpellListener.OBJECT
}
else if (pkt is Packet.ComponentNpcAction) {
if (pkt.npcIndex !in 1 until ServerConstants.MAX_NPCS)
return sendClearMinimap(pkt.player)
player = pkt.player
child = pkt.child
iface = pkt.iface
target = Repository.npcs[pkt.npcIndex] ?: return sendClearMinimap(player)
targetId = target.id
type = SpellListener.NPC
}
else {
if (pkt !is Packet.ComponentItemAction) return
player = pkt.player
child = pkt.child
iface = pkt.iface
target = player.inventory[pkt.slot] ?: return
targetId = pkt.itemId
type = SpellListener.ITEM
}
if (targetId != target.id)
return
if (player.getAttribute("magic:delay", -1) > GameWorld.ticks)
return
val book = SpellUtils.getBookFromInterface(iface)
if (book != "none")
SpellListeners.run(child, type, book, player, target)
when (iface) {
430,192 -> MagicSpell.castSpell(player, SpellBookManager.SpellBook.forInterface(iface), child, target)
662 -> {
if (player.familiarManager.hasFamiliar())
player.familiarManager.familiar.executeSpecialMove(FamiliarSpecial(target, iface, child, target as? Item))
else
player.sendMessage("You don't have a familiar.")
}
}
}
private fun processWalkPacket(pkt: Packet) {
val player: Player
val x: Int
val y: Int
val isRunning: Boolean
if (pkt is Packet.WorldspaceWalk) {
player = pkt.player
x = pkt.destX
y = pkt.destY
isRunning = pkt.isRun
}
else if (pkt is Packet.InteractWalk) {
player = pkt.player
x = pkt.destX
y = pkt.destY
isRunning = pkt.isRun
}
else {
if (pkt !is Packet.MinimapWalk) return
player = pkt.player
x = pkt.destX
y = pkt.destY
isRunning = pkt.isRun
//there's more data in this packet, we're just not using it
}
if (player.locks.isMovementLocked || !player.interfaceManager.close() || !player.interfaceManager.closeSingleTab() || !player.dialogueInterpreter.close()) {
player.debug("[WALK ACTION]-- NO HANDLE: PLAYER LOCKED OR INTERFACES SAY NO")
return sendClearMinimap(player)
}
if (pkt is Packet.InteractWalk) {
//Arios did this, so we're replicating it for now. Probably wrong.
player.walkingQueue.isRunning = isRunning
return
}
player.face(null)
player.faceLocation(null)
player.pulseManager.run(object : MovementPulse(player, Location.create(x,y,player.location.z), isRunning) {
override fun pulse(): Boolean {
if (isRunning)
player.walkingQueue.isRunning = false
return true
}
})
}
private fun processCloseIface(pkt: Packet.CloseIface) {
val player = pkt.player
player.interfaceManager.close()
if (player.getAttribute<Boolean>("logging_in") != null) {
GameWorld.Pulser.submit(object : Pulse() {
override fun pulse(): Boolean {
player.removeAttribute("logging_in")
LoginConfiguration.configureGameWorld(player)
return true
}
})
}
if (player.getAttribute<Any?>("worldMap:viewing") != null) {
player.removeAttribute("worldMap:viewing")
player.packetDispatch.sendWindowsPane(if (player.interfaceManager.isResizable) 746 else 548, 2)
player.unlock()
}
}
private fun processIfAction(pkt: Packet.IfAction) {
val player = pkt.player
player.debug("[IF ACTION]--------------------------")
player.debug("Iface: ${pkt.iface}, Button: ${pkt.child}")
player.debug("Slot: ${pkt.slot}, ItemID: ${pkt.itemId}")
player.debug("RCM Index: ${pkt.optIndex}, Op: ${pkt.opcode}")
player.debug("-------------------------------------")
if (player.dialogueInterpreter.dialogue != null && pkt.opcode != 132 && pkt.iface != 64)
player.dialogueInterpreter.close()
if (player.locks.isComponentLocked)
return
if (player.zoneMonitor.clickButton(pkt.iface, pkt.child, pkt.slot, pkt.itemId, pkt.opcode))
return
val c = player.interfaceManager.getComponent(pkt.iface) ?: return
if (c.isHidden)
return
val plugin = c.plugin
player.dispatch(ButtonClickEvent(c.id, pkt.child))
if (!InterfaceListeners.run(player, c, pkt.opcode, pkt.child, pkt.slot, pkt.itemId))
plugin?.handle(player, c, pkt.opcode, pkt.child, pkt.slot, pkt.itemId)
}
private fun processUseWith(pkt: Packet) {
val node: Node
var childNode: Node? = null
val item: Item
val itemId: Int
val nodeId: Int
val type: IntType
val player: Player
if (pkt is Packet.UseWithNpc) {
val container = getLikelyContainerForIface(pkt.player, pkt.iface) ?: return sendClearMinimap(pkt.player)
itemId = pkt.itemId
val itemSlot = pkt.slot
item = container[itemSlot] ?: return sendClearMinimap(pkt.player)
node = Repository.npcs[pkt.npcIndex] ?: return sendClearMinimap(pkt.player)
childNode = node.getShownNPC(pkt.player)
nodeId = node.id
type = IntType.NPC
player = pkt.player
}
else if (pkt is Packet.UseWithScenery) {
item = pkt.player.inventory[pkt.slot] ?: return sendClearMinimap(pkt.player)
node = RegionManager.getObject(pkt.player.location.z, pkt.x, pkt.y) ?: return sendClearMinimap(pkt.player)
childNode = node.asScenery().getChild(pkt.player)
itemId = pkt.itemId
nodeId = node.id
type = IntType.SCENERY
player = pkt.player
}
else if (pkt is Packet.UseWithItem) {
val containerUsed = getLikelyContainerForIface(pkt.player, pkt.usedIface) ?: return
val containerWith = getLikelyContainerForIface(pkt.player, pkt.usedWithIface) ?: return
item = containerUsed[pkt.usedSlot] ?: return
node = containerWith[pkt.usedWithSlot] ?: return
itemId = pkt.usedId
nodeId = pkt.usedWithId
type = IntType.ITEM
player = pkt.player
} else if (pkt is Packet.UseWithGroundItem) {
val container = getLikelyContainerForIface(pkt.player, pkt.iface) ?: return
item = container[pkt.slot]
itemId = pkt.usedId
node = GroundItemManager.get(pkt.withId, Location.create(pkt.x, pkt.y, pkt.player.location.z), pkt.player)
nodeId = pkt.withId
type = IntType.GROUNDITEM
player = pkt.player
} else {
if (pkt !is Packet.UseWithPlayer) return
val container = getLikelyContainerForIface(pkt.player, pkt.iface) ?: return sendClearMinimap(pkt.player)
item = container[pkt.slot] ?: return sendClearMinimap(pkt.player)
itemId = pkt.itemId
node = Repository.players[pkt.otherIndex] ?: return sendClearMinimap(pkt.player)
type = IntType.PLAYER
nodeId = node.id
player = pkt.player
}
if (item.id != itemId)
return sendClearMinimap(player)
if (node.id != nodeId)
return sendClearMinimap(player)
if (player.zoneMonitor.useWith(item, node))
return
if (InteractionListeners.run(item, node, type, player))
return
if (childNode != null && childNode.id != node.id) {
if (InteractionListeners.run(item, childNode, type, player))
return
}
val flipped = type == IntType.ITEM && item.id < node.id
val event = if (flipped)
NodeUsageEvent(player, 0, node, item)
else
NodeUsageEvent(player, 0, item, childNode ?: node)
if (PluginInteractionManager.handle(player, event))
return
UseWithHandler.run(event)
}
private fun processGroundItemAction(pkt: Packet.GroundItemAction) {
val item = GroundItemManager.get(pkt.id, Location.create(pkt.x, pkt.y, pkt.player.location.z), pkt.player)
val player = pkt.player
if (item == null) {
return sendClearMinimap(player)
}
val option = item.interaction[pkt.optIndex]
if (option == null) {
Interaction.handleInvalidInteraction(player, item, Option.NULL)
return sendClearMinimap(player)
}
if (PluginInteractionManager.handle(player, item, option))
return
if (InteractionListeners.run(item.id, IntType.GROUNDITEM, option.name, player, item))
return
if (InteractionListeners.run(item.id, IntType.ITEM, option.name, player, item))
return
item.interaction.handle(player, option)
}
private fun processPlayerAction(pkt: Packet.PlayerAction) {
val player = pkt.player
if (pkt.otherIndex !in 1 until ServerConstants.MAX_PLAYERS) {
return sendClearMinimap(player)
}
val other = Repository.players[pkt.otherIndex]
if (other == null || !other.isActive)
return sendClearMinimap(player)
val option = other.interaction[pkt.optIndex] ?: return sendClearMinimap(player)
if (!InteractionListeners.run(-1, IntType.PLAYER, option.name.lowercase(), player, other)) {
other.interaction.handle(player, option)
}
}
private fun processSceneryAction(pkt: Packet.SceneryAction) {
val player = pkt.player
var scenery = RegionManager.getObject(player.location.z, pkt.x, pkt.y, pkt.id)
var objId = pkt.id
//what follows is a series of hardcoded crimes against humanity
if (pkt.id == 6898)
scenery = Scenery(6898, Location(3219, 9618))
if (pkt.id == 6899)
scenery = Scenery(6899, Location(3221, 9618))
// Family crest levers don't have varps associated with them, so their state is validated with attributes
// instead, and they always appear as their down/odd variant in the server's map
if (objId in 2421..2426 && objId % 2 == 0) {
scenery = Scenery(objId - 1, Location(pkt.x, pkt.y, player.location.z))
objId -= 1
}
if (scenery == null || scenery.id != objId || !scenery.isActive) {
player.debug("[SCENERY INTERACT] NULL OR MISMATCH OR INACTIVE")
Interaction.handleInvalidInteraction(player, scenery, Option.NULL)
return sendClearMinimap(player)
}
val wrapperChild = scenery.getChild(player)
val option = wrapperChild.interaction[pkt.optIndex]
if (option == null) {
player.debug("[SCENERY INTERACT] NULL OPTION")
Interaction.handleInvalidInteraction(player, scenery, Option.NULL)
return sendClearMinimap(player)
}
val hasWrapper = wrapperChild.id != scenery.id
player.debug("[SCENERY INTERACT]------------------------------")
player.debug("ID: ${wrapperChild.id}, Option: ${option.name}[${option.index}]")
player.debug("Loc: ${scenery.location}, Dir: ${scenery.direction}")
if (hasWrapper) {
player.debug("WrapperID: ${scenery.id}, Varbit: ${scenery.definition.configFile.id}")
}
player.debug("------------------------------------------------")
if (InteractionListeners.run(wrapperChild.id, IntType.SCENERY, option.name, player, wrapperChild))
return
if (PluginInteractionManager.handle(player, wrapperChild))
return
wrapperChild.interaction.handle(player, option)
}
private fun processNpcAction(pkt: Packet.NpcAction) {
if (pkt.npcIndex !in 1 until ServerConstants.MAX_NPCS)
return sendClearMinimap(pkt.player)
val npc = Repository.npcs[pkt.npcIndex] ?: return sendClearMinimap(pkt.player)
val wrapperChild = npc.getShownNPC(pkt.player)
val option = wrapperChild.interaction[pkt.optIndex]
if (option == null) {
Interaction.handleInvalidInteraction(pkt.player, npc, Option.NULL)
return sendClearMinimap(pkt.player)
}
val hasWrapper = wrapperChild.id != npc.id
pkt.player.debug("[NPC INTERACT]-------------------")
pkt.player.debug("ID: ${wrapperChild.id}, Index: ${pkt.npcIndex}")
pkt.player.debug("Option: ${option.name}[${option.index}]")
pkt.player.debug("SpawnLoc: ${npc.properties.spawnLocation}")
if (hasWrapper) {
pkt.player.debug("WrapperID: ${npc.id}, Varbit: ${npc.definition.configFileId}")
}
pkt.player.debug("---------------------------------")
if (InteractionListeners.run(wrapperChild.id, IntType.NPC,option.name,pkt.player,npc))
return
if (PluginInteractionManager.handle(pkt.player, wrapperChild, option))
return
npc.interaction.handle(pkt.player, option)
}
private fun processItemAction(pkt: Packet.ItemAction) {
val container = getLikelyContainerForIface(pkt.player, pkt.iface) ?: return
if (pkt.slot !in 0 until container.capacity())
return
val item = container.get(pkt.slot) ?: return
if (item.id != pkt.itemId)
return
val option = item.interaction[pkt.optIndex] ?: return
if (pkt.player.locks.isInteractionLocked)
return
item.interaction.handleItemOption(pkt.player, option, container)
pkt.player.debug("[ITEM INTERACT] ID: ${item.id}, Slot: ${pkt.slot}, Opt: ${option.name}")
}
private fun getLikelyContainerForIface(player: Player, iface: Int) : Container? {
return when (iface) {
Components.INVENTORY_149 -> player.inventory
Components.BANK_V2_MAIN_762 -> player.bank
Components.EQUIP_SCREEN2_667 -> player.equipment
else -> null
}
}
private fun sendClearMinimap(player: Player) {
PacketRepository.send(ClearMinimapFlag::class.java, PlayerContext(player))
}
fun switchItem(slot: Int, secondSlot: Int, container: Container?, insert: Boolean, player: Player) {
if (container == null || slot < 0 || slot >= container.toArray().size || secondSlot < 0 || secondSlot >= container.toArray().size) {
return
}
val item = container[slot]
val second = container[secondSlot]
if (player.interfaceManager.hasChatbox() && !getAttribute(player, "close_c_", false)) {
player.interfaceManager.closeChatbox()
switchItem(secondSlot, slot, container, insert, player)
container.refresh()
return
}
if (item == null) {
return
}
if (!insert) {
container.replace(second, slot, false)
container.replace(item, secondSlot, false)
item.index = secondSlot
if (second != null) {
second.index = slot
}
} else {
container.insert(slot, secondSlot, false)
}
container.refresh()
}
}
@@ -0,0 +1,771 @@
package rs09.net.packet.`in`
import core.game.node.entity.player.Player
import core.net.packet.IoBuffer
import core.tools.StringUtils
import rs09.game.system.SystemLogger
import java.io.PrintWriter
import java.io.StringWriter
enum class Decoders530(val opcode: Int) {
/******************************************
* ITEM INTERACTIONS
******************************************/
ITEM_ACTION_1(156) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val slot = buffer.leShortA
val itemId = buffer.shortA
val ifHash = buffer.leInt
val (iface, button) = deHash(ifHash)
return Packet.ItemAction(player, 0, itemId, slot, iface, button)
}
},
ITEM_ACTION_2(55) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val itemId = buffer.leShort
val slot = buffer.shortA
val ifHash = buffer.intA
val (iface, button) = deHash(ifHash)
return Packet.ItemAction(player, 1, itemId, slot, iface, button)
}
},
ITEM_ACTION_3(153) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val ifHash = buffer.leInt
val slot = buffer.leShort
val itemId = buffer.leShort
val (iface, button) = deHash(ifHash)
return Packet.ItemAction(player, 2, itemId, slot, iface, button)
}
},
ITEM_ACTION_4(161) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val ifHash = buffer.leInt
val itemId = buffer.leShortA
val slot = buffer.leShortA
val (iface, button) = deHash(ifHash)
return Packet.ItemAction(player, 3, itemId, slot, iface, button)
}
},
ITEM_ACTION_5(135) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val itemId = buffer.shortA
val slot = buffer.shortA
val ifHash = buffer.intB
val (iface, button) = deHash(ifHash)
return Packet.ItemAction(player, 4, itemId, slot, iface, button)
}
},
/******************************************
* NPC INTERACTIONS
******************************************/
NPC_ACTION_1(78) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val npcIndex = buffer.leShort
return Packet.NpcAction(player, 0, npcIndex)
}
},
NPC_ACTION_2(3) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val npcIndex = buffer.leShortA
return Packet.NpcAction(player, 1, npcIndex)
}
},
NPC_ACTION_3(148) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val npcIndex = buffer.shortA
return Packet.NpcAction(player, 2, npcIndex)
}
},
NPC_ACTION_4(30) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val npcIndex = buffer.short
return Packet.NpcAction(player, 3, npcIndex)
}
},
NPC_ACTION_5(218) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val npcIndex = buffer.leShort
return Packet.NpcAction(player, 4, npcIndex)
}
},
/******************************************
* SCENERY INTERACTIONS
******************************************/
SCENERY_ACTION_1(254) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val x = buffer.leShort
val objId = buffer.shortA and 0xFFFF
val y = buffer.short
return Packet.SceneryAction(player, 0, objId, x, y)
}
},
SCENERY_ACTION_2(194) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val y = buffer.leShortA
val x = buffer.leShort
val objId = buffer.short and 0xFFFF
return Packet.SceneryAction(player, 1, objId, x, y)
}
},
SCENERY_ACTION_3(84) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val objId = buffer.leShortA and 0xFFFF
val y = buffer.leShortA
val x = buffer.leShort
return Packet.SceneryAction(player, 2, objId, x, y)
}
},
SCENERY_ACTION_4(247) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val y = buffer.leShort and 0xFFFF
val x = buffer.leShortA
val objId = buffer.short and 0xFFFF
return Packet.SceneryAction(player, 3, objId, x, y)
}
},
SCENERY_ACTION_5(170) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val objId = buffer.leShortA and 0xFFFF
val x = buffer.leShortA
val y = buffer.leShortA
return Packet.SceneryAction(player, 4, objId, x, y)
}
},
/******************************************
* PLAYER INTERACTIONS
******************************************/
PLAYER_ACTION_1(68) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val pIndex = buffer.leShortA
return Packet.PlayerAction(player, 0, pIndex)
}
},
PLAYER_ACTION_3(71) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val pIndex = buffer.leShortA
return Packet.PlayerAction(player, 2, pIndex)
}
},
PLAYER_ACTION_4(180) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val pIndex = buffer.leShortA
return Packet.PlayerAction(player, 3, pIndex)
}
},
PLAYER_ACTION_7(114) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val index = buffer.leShortA
return Packet.PlayerAction(player, 6, index)
}
},
PLAYER_ACTION_8(175) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val pIndex = buffer.shortA
return Packet.PlayerAction(player, 7, pIndex)
}
},
/******************************************
* OBJSTACK (Ground Item) INTERACTIONS
******************************************/
OBJSTACK_ACTION_1(66) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val x = buffer.leShort
val itemId = buffer.short
val y = buffer.leShortA
return Packet.GroundItemAction(player, 2, itemId, x, y)
}
},
OBJSTACK_ACTION_2(33) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val itemId = buffer.short
val x = buffer.short
val y = buffer.leShort
return Packet.GroundItemAction(player, 3, itemId, x, y)
}
},
/******************************************
* USEWITH INTERACTIONS
******************************************/
USEWITH_NPC(115) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val ifHash = buffer.intB
val slot = buffer.leShort
val npcIndex = buffer.leShort
val itemId = buffer.leShortA
val (iface, _) = deHash(ifHash)
return Packet.UseWithNpc(player, itemId, npcIndex, iface, slot)
}
},
USEWIH_PLAYER(248) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val otherIndex = buffer.leShortA
val itemId = buffer.short
val slot = buffer.short
val ifHash = buffer.intB
val (iface, _) = deHash(ifHash)
return Packet.UseWithPlayer(player, itemId, otherIndex, iface, slot)
}
},
USEWITH_ITEM(27) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val usedSlot = buffer.short
val usedIfHash = buffer.leInt
val usedWithSlot = buffer.leShort
val usedWithIfHash = buffer.leInt
val usedId = buffer.leShortA
val usedWithId = buffer.leShortA
val (usedIface, usedChild) = deHash(usedIfHash)
val (usedWithIface, usedWithChild) = deHash(usedWithIfHash)
return Packet.UseWithItem(
player,
usedId, usedWithId,
usedSlot, usedWithSlot,
usedIface, usedWithIface,
usedChild, usedWithChild
)
}
},
USEWITH_SCENERY(134) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val x = buffer.shortA
val id = buffer.short
val y = buffer.leShort
val slot = buffer.short
buffer.leShort //Suspicious noops? TODO: FIND OUT WHAT THESE ARE
buffer.short
val sceneryId = buffer.shortA
return Packet.UseWithScenery(player, id, slot, sceneryId, x, y)
}
},
USEWITH_GROUNDITEM(101) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val x = buffer.leShortA
val slot = buffer.leShort
val usedId = buffer.leShort
val usedWithId = buffer.leShort
val y = buffer.leShortA
val ifHash = buffer.intB
val (iface,child) = deHash(ifHash)
return Packet.UseWithGroundItem(player, usedId, usedWithId, iface, child, slot, x, y)
}
},
/******************************************
* INTERFACE INTERACTIONS
******************************************/
IF_ACTION_1(155) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val ifHash = buffer.int
val slot = buffer.short
val (iface, button) = deHash(ifHash)
return Packet.IfAction(player, opcode, 0, iface, button, slot)
}
},
IF_ACTION_2(196) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val ifHash = buffer.int
val slot = buffer.short
val (iface, button) = deHash(ifHash)
return Packet.IfAction(player, opcode, 1, iface, button, slot)
}
},
IF_ACTION_3(124) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val ifHash = buffer.int
val slot = buffer.short
val (iface, button) = deHash(ifHash)
return Packet.IfAction(player, opcode, 2, iface, button, slot)
}
},
IF_ACTION_4(199) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val ifHash = buffer.int
val slot = buffer.short
val (iface, button) = deHash(ifHash)
return Packet.IfAction(player, opcode, 3, iface, button, slot)
}
},
IF_ACTION_5(234) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val ifHash = buffer.int
val slot = buffer.short
val (iface, button) = deHash(ifHash)
return Packet.IfAction(player, opcode, 4, iface, button, slot)
}
},
IF_ACTION_6(168) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val ifHash = buffer.int
val slot = buffer.short
val (iface, button) = deHash(ifHash)
return Packet.IfAction(player, opcode, 5, iface, button, slot)
}
},
IF_ACTION_7(166) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val ifHash = buffer.int
val slot = buffer.short
val (iface, button) = deHash(ifHash)
return Packet.IfAction(player, opcode, 6, iface, button, slot)
}
},
IF_ACTION_8(64) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val ifHash = buffer.int
val slot = buffer.short
val (iface, button) = deHash(ifHash)
return Packet.IfAction(player, opcode, 7, iface, button, slot)
}
},
IF_ACTION_9(53) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val ifHash = buffer.int
val slot = buffer.short
val (iface, button) = deHash(ifHash)
return Packet.IfAction(player, opcode, 8, iface, button, slot)
}
},
IF_ACTION_10(9) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val ifHash = buffer.int
val slot = buffer.short
val (iface, button) = deHash(ifHash)
return Packet.IfAction(player, opcode, 9, iface, button, slot)
}
},
IF_ACTION_CS(10) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val ifHash = buffer.int
val (iface, button) = deHash(ifHash)
return Packet.IfAction(player, opcode, -1, iface, button, -1, -1)
}
},
DIALOGUE_OPT(132) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val ifHash = buffer.intA
val slot = buffer.leShort
val (iface, button) = deHash(ifHash)
return Packet.DialogueOption(player, iface, button)
}
},
CLOSE_IFACE(184) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.CloseIface(player)
}
},
IF_GROUNDITEM_ACTION(73) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val child = buffer.short
val iface = buffer.short
val y = buffer.short
val itemId = buffer.leShortA
val x = buffer.leShortA
val slot = buffer.leShort
return Packet.ComponentGroundItemAction(player, iface, child, slot, itemId, x, y)
}
},
IF_PLAYER_ACTION(195) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
buffer.shortA //Arios ignoring more data... nice
val child = buffer.leShort
val iface = buffer.leShort
val otherIndex = buffer.leShortA
return Packet.ComponentPlayerAction(player, otherIndex, iface, child)
}
},
IF_SCENERY_ACTION(233) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val y = buffer.leShortA
val x = buffer.shortA
val itemId = buffer.leShortA //probably misnamed/mislabeled by Arios.
val ifHash = buffer.intA
val (iface, child) = deHash(ifHash)
val objId = buffer.shortA
return Packet.ComponentSceneryAction(player, iface, child, objId, x, y)
}
},
IF_NPC_ACTION(239) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val child = buffer.leShort
val iface = buffer.leShort
buffer.shortA //more ignored data....
val index = buffer.leShortA
return Packet.ComponentNpcAction(player, iface, child, index)
}
},
IF_ITEM_ACTION(253) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val child = buffer.leShort
val iface = buffer.leShort
val itemSlot = buffer.leShortA
val itemId = buffer.shortA
buffer.shortA //more ignored data....
return Packet.ComponentItemAction(player, iface, child, itemId, itemSlot)
}
},
SLOTSWITCH_MULTI(79) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val srcHash = buffer.intB
val destSlot = buffer.leShort
val destHash = buffer.int
val srcSlot = buffer.leShort
val (srcIface, srcChild) = deHash(srcHash)
val (destIface, destChild) = deHash(destHash)
return Packet.SlotSwitchMultiComponent(player, srcIface, srcChild, srcSlot, destIface, destChild, destSlot)
}
},
SLOTSWITCH_SINGLE(231) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val srcSlot = buffer.short
val ifHash = buffer.leInt
val destSlot = buffer.shortA
val isInsert = buffer.get() == 1
val (iface, child) = deHash(ifHash)
return Packet.SlotSwitchSingleComponent(player, iface, child, srcSlot, destSlot, isInsert)
}
},
IF_ITEM_OPT_1(81) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val slot = buffer.shortA
val itemId = buffer.short
val child = buffer.short
val iface = buffer.short
return Packet.IfAction(player, opcode, 0, iface, child, slot, itemId)
}
},
IF_ITEM_OPT_2(206) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val itemId = buffer.shortA
val slot = buffer.leShort
val ifHash = buffer.leInt
val (iface, button) = deHash(ifHash)
return Packet.IfAction(player, opcode, 1, iface, button, slot, itemId)
}
},
/******************************************
* EXAMINE
******************************************/
EXAMINE_SCENERY(94) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.SceneryExamine(player, buffer.leShortA)
}
},
EXAMINE_ITEM(92) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.ItemExamine(player, buffer.leShortA)
}
},
EXAMINE_NPC(72) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.NpcExamine(player, buffer.short)
}
},
/******************************************
* CLANS
******************************************/
CLAN_JOIN(104) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val clanName = StringUtils.longToString(buffer.long)
return Packet.JoinClan(player, clanName)
}
},
CLAN_SETRANK(188) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val rank = buffer.a
val name = StringUtils.longToString(buffer.long)
return Packet.SetClanRank(player, name, rank)
}
},
CLAN_KICK(162) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val name = StringUtils.longToString(buffer.long)
return Packet.KickFromClan(player, name)
}
},
/******************************************
* FRIENDS/IGNORES
******************************************/
ADD_FRIEND(120) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.AddFriend(player, StringUtils.longToString(buffer.long))
}
},
REMOVE_FRIEND(57) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.RemoveFriend(player, StringUtils.longToString(buffer.long))
}
},
ADD_IGNORE(34) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.AddIgnore(player, StringUtils.longToString(buffer.long))
}
},
REMOVE_IGNORE(213) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.RemoveIgnore(player, StringUtils.longToString(buffer.long))
}
},
PRIVATE_MESSAGE(201) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val name = StringUtils.longToString(buffer.long)
val message = StringUtils.decryptPlayerChat(buffer, buffer.get() and 0xFF)
return Packet.PrivateMessage(player, name, message)
}
},
/******************************************
* INPUT TRACKING
******************************************/
FOCUS_CHANGE(22) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.TrackingFocus(player, buffer.get() == 1)
}
},
CAMERA_MOVEMENT(21) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val x = buffer.shortA
val y = buffer.leShort
return Packet.TrackingCameraPos(player, x, y)
}
},
DISPLAY_UPDATE(243) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val windowMode = buffer.get()
val screenWidth = buffer.short
val screenHeight = buffer.short
val displayMode = buffer.get()
return Packet.TrackingDisplayUpdate(player, windowMode, screenWidth, screenHeight, displayMode)
}
},
AFK_TIMEOUT(245) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.TrackingAfkTimeout(player)
}
},
MOUSE_CLICKED(75) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val data = buffer.leShortA
val pos = buffer.intB
val rightClick = ((data shr 15) and 0x1) == 1
val delay = data and 0x7FF
val x = pos shr 16
val y = pos and 0xFFFF
return Packet.TrackingMouseClick(player, x, y, rightClick, delay)
}
},
/******************************************
* WALKING
******************************************/
WORLDSPACE_WALK(215) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val (running, x, y) = decodeWalkInformation(buffer, false)
return Packet.WorldspaceWalk(player, x, y, running)
}
},
MINIMAP_WALK(39) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val (running, x, y) = decodeWalkInformation(buffer, true)
val clickedX = buffer.get()
val clickedY = buffer.get()
val rotation = buffer.short
//Unlabeled data ignored by arios
buffer.get()
buffer.get()
buffer.get()
buffer.get()
buffer.short
buffer.short
buffer.get()
buffer.get()
return Packet.MinimapWalk(player, x, y, clickedX, clickedY, rotation, running)
}
},
INTERACT_WALK(77) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val (running, x, y) = decodeWalkInformation(buffer, false)
return Packet.InteractWalk(player, x, y, running)
}
},
/******************************************
* INPUT PROMPT RESPONSE
******************************************/
INPUT_SHORT_STRING_RESPONSE(244) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.InputPromptResponse(player, StringUtils.longToString(buffer.long))
}
},
INPUT_LONG_STRING_RESPONSE(65) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.InputPromptResponse(player, buffer.string)
}
},
INPUT_INT_RESPONSE(23) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.InputPromptResponse(player, buffer.int)
}
},
/******************************************
* ASSORTED
******************************************/
GE_SET_OFFER_ITEM(111) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val itemId = buffer.short
return Packet.GESetOfferItem(player, itemId)
}
},
COMMAND(44) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
if (buffer.toByteBuffer().remaining() > 1) {
val message = buffer.string.lowercase()
return Packet.Command(player, message)
}
return Packet.NoProcess()
}
},
CHAT_SETTINGS(157) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.ChatSetting(
player,
buffer.get(),
buffer.get(),
buffer.get()
)
}
},
CHAT_MESSAGE(237) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val effects = buffer.short
val numChars = buffer.smart
val message = StringUtils.decryptPlayerChat(buffer, numChars)
return Packet.ChatMessage(player, effects, message)
}
},
MUSIC_TRACK_FINISHED(137) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val trackId = buffer.leShortA
return Packet.TrackFinished(player, trackId)
}
},
REPORT_ABUSE(99) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val target = StringUtils.longToString(buffer.long)
val ruleId = buffer.get()
val modMute = buffer.get() == 1
return Packet.ReportAbuse(player, target, ruleId, modMute)
}
},
UPDATE_PACKET_COUNT(177) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val count = buffer.short
return Packet.PacketCountUpdate(player, count)
}
},
PING(93) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.Ping(player)
}
},
QUICKCHAT(167) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val x = buffer.toByteBuffer()
val packetType = when(x.array().size){
3,4 -> QCPacketType.STANDARD
5 -> QCPacketType.SINGLE
7 -> QCPacketType.DOUBLE
else -> QCPacketType.UNHANDLED.also { SystemLogger.logWarn(this::class.java, "UNHANDLED QC PACKET TYPE Size ${x.array().size}") }
}
val forClan = (buffer.get() and 0xFF) == 1
val multiplier: Int = buffer.get()
val offset: Int = buffer.get()
var selection_a_index = -1
var selection_b_index = -1
when(packetType){
QCPacketType.SINGLE -> {
selection_a_index = buffer.short
}
QCPacketType.DOUBLE -> {
buffer.get() //discard
selection_a_index = buffer.get()
buffer.get() //discard
selection_b_index = buffer.get()
}
QCPacketType.UNHANDLED -> SystemLogger.logWarn(this::class.java, "Unhandled packet type, skipping remaining buffer contents.")
}
return Packet.QuickChat(player, selection_a_index, selection_b_index, forClan, multiplier, offset, packetType)
}
},
MAP_REBUILD_STARTED(20) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.NoProcess()
}
},
MAP_REBUILD_FINISHED(110) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
return Packet.NoProcess()
}
},
PLAYER_PREFS_UPDATE(98) {
override fun decode(player: Player, buffer: IoBuffer): Packet {
val prefs = buffer.int
return Packet.PlayerPrefsUpdate(player, prefs)
}
}
;
abstract fun decode(player: Player, buffer: IoBuffer): Packet
fun deHash(ifHash: Int) : Pair<Int,Int> {
return Pair(ifHash shr 16, ifHash and 0xFFFF)
}
fun decodeWalkInformation(buffer: IoBuffer, isMinimap: Boolean) : Triple<Boolean,Int,Int> {
val isRunning = buffer.a == 1
var x = buffer.short
var y = buffer.shortA
val steps = (buffer.toByteBuffer().remaining() - if (isMinimap) 14 else 0) shr 1
//derive the final destination by poking the last set of values in the packet (client does its own pathfinding and reports it)
for (i in 0 until steps) {
val offsetX = buffer.a
val offsetY = buffer.s
if (i == steps - 1){
x += offsetX
y += offsetY
}
}
return Triple(isRunning, x, y)
}
companion object {
private val opcodeMap = values().associateBy { it.opcode }
@JvmStatic fun process(player: Player, opcode: Int, buffer: IoBuffer) : Packet {
val decoder = opcodeMap[opcode] ?: return Packet.UnhandledOp()
return try {
decoder.decode(player, buffer)
} catch (e: Exception) {
val sw = StringWriter()
val pw = PrintWriter(sw)
e.printStackTrace(pw)
Packet.DecodingError("Error decoding opcode $opcode/${decoder.name}: $sw")
}
}
}
}
@@ -1,62 +0,0 @@
package rs09.net.packet.`in`
import core.game.interaction.DestinationFlag
import core.game.interaction.MovementPulse
import core.game.node.entity.player.Player
import core.game.node.entity.skill.firemaking.FireMakingPulse
import core.game.node.item.GroundItemManager
import core.game.world.map.Location
import core.net.packet.IncomingPacket
import core.net.packet.IoBuffer
import org.rs09.consts.Items
/**
* Handles the Item -> Ground Item packet
* Decided not to include it with the rest of ItemActionPacket because it functions a bit differently from the rest of that
* Will also require its own handlers instead of the normal UseWithHandler. Kind of annoying especially considering there's very few
* Interactions that actually make use of this packet.
* @author Ceikry
*/
class ItemOnGroundItemPacket : IncomingPacket {
override fun decode(player: Player?, opcode: Int, buffer: IoBuffer?) {
buffer ?: return
player ?: return
val x = buffer.leShortA
val slot = buffer.leShort
val usedItemId = buffer.leShort
val usedWithItemId = buffer.leShort
val y = buffer.leShortA
buffer.int //uncertain what the use for this int is. My suspicion was region ID but no variety of the int data type matches up with the region id
val GILocation = Location.create(x,y,player.location.z)
var usedWith = GroundItemManager.get(usedWithItemId, GILocation, null) ?: GroundItemManager.get(usedWithItemId, GILocation, player)
usedWith ?: return
var used = player.inventory.get(slot)
if(used.id != usedItemId) return
/**
* I'm just gonna put the handler for tinderbox -> logs here. Yes I know it's lazy, etc, etc but frankly the number of interactions
* that are actually item -> ground item are so few it just doesn't make sense to make a whole system for it.
*/
player.pulseManager.run(object : MovementPulse(player,GILocation, DestinationFlag.ITEM){
override fun pulse(): Boolean {
if(used.id == Items.TINDERBOX_590 || used.id == Items.GOLDEN_TINDERBOX_2946){
when(usedWithItemId){
Items.LOGS_1511,Items.ACHEY_TREE_LOGS_2862,Items.ARCTIC_PINE_LOGS_10810,Items.MAGIC_LOGS_1513,Items.MAHOGANY_LOGS_6332,Items.MAPLE_LOGS_1517,Items.YEW_LOGS_1515,Items.TEAK_LOGS_6333,Items.OAK_LOGS_1521, Items.WILLOW_LOGS_1519
-> {
player.pulseManager.run(FireMakingPulse(player,usedWith.asItem(),usedWith))
}
else -> player.sendMessage("Nothing interesting happens.")
}
} else {
player.sendMessage("Nothing interesting happens.")
}
return true
}
})
}
}
@@ -0,0 +1,60 @@
package rs09.net.packet.`in`
import core.game.node.entity.player.Player
sealed class Packet {
data class ItemAction(val player: Player, val optIndex: Int, val itemId: Int, val slot: Int, val iface: Int, val child: Int) : Packet()
data class NpcAction(val player: Player, val optIndex: Int, val npcIndex: Int) : Packet()
data class SceneryAction(val player: Player, val optIndex: Int, val id: Int, val x: Int, val y: Int) : Packet()
data class PlayerAction(val player: Player, val optIndex: Int, val otherIndex: Int) : Packet()
data class GroundItemAction(val player: Player, val optIndex: Int, val id: Int, val x: Int, val y: Int) : Packet()
data class ItemExamine(val player: Player, val id: Int) : Packet()
data class SceneryExamine(val player: Player, val id: Int) : Packet()
data class NpcExamine(val player: Player, val id: Int) : Packet()
data class UseWithNpc(val player: Player, val itemId: Int, val npcIndex: Int, val iface: Int, val slot: Int) : Packet()
data class UseWithPlayer(val player: Player, val itemId: Int, val otherIndex: Int, val iface: Int, val slot: Int) : Packet()
data class UseWithItem(val player: Player, val usedId: Int, val usedWithId: Int, val usedSlot: Int, val usedWithSlot: Int, val usedIface: Int, val usedWithIface: Int, val usedChild: Int, val usedWithChild: Int) : Packet()
data class UseWithScenery(val player: Player, val itemId: Int, val slot: Int, val sceneryId: Int, val x: Int, val y: Int) : Packet()
data class UseWithGroundItem(val player: Player, val usedId: Int, val withId: Int, val iface: Int, val child: Int, val slot: Int, val x: Int, val y: Int) : Packet()
data class IfAction(val player: Player, val opcode: Int, val optIndex: Int, val iface: Int, val child: Int, val slot: Int, val itemId: Int = -1) : Packet()
data class DialogueOption(val player: Player, val iface: Int, val child: Int) : Packet()
data class CloseIface(val player: Player) : Packet()
data class JoinClan(val player: Player, val clanName: String) : Packet()
data class SetClanRank(val player: Player, val username: String, val rank: Int) : Packet()
data class KickFromClan(val player: Player, val username: String) : Packet()
data class AddFriend(val player: Player, val username: String) : Packet()
data class RemoveFriend(val player: Player, val username: String) : Packet()
data class AddIgnore(val player: Player, val username: String) : Packet()
data class RemoveIgnore(val player: Player, val username: String) : Packet()
data class TrackingFocus(val player: Player, val isFocused: Boolean) : Packet()
data class TrackingCameraPos(val player: Player, val x: Int, val y: Int) : Packet()
data class TrackingDisplayUpdate(val player: Player, val windowMode: Int, val screenWidth: Int, val screenHeight: Int, val displayMode: Int) : Packet()
data class TrackingAfkTimeout(val player: Player) : Packet()
data class TrackingMouseClick(val player: Player, val x: Int, val y: Int, val isRightClick: Boolean, val delay: Int) : Packet()
data class ComponentPlayerAction(val player: Player, val otherIndex: Int, val iface: Int, val child: Int) : Packet()
data class ComponentItemAction(val player: Player, val iface: Int, val child: Int, val itemId: Int, val slot: Int) : Packet()
data class ComponentNpcAction(val player: Player, val iface: Int, val child: Int, val npcIndex: Int) : Packet()
data class ComponentSceneryAction(val player: Player, val iface: Int, val child: Int, val sceneryId: Int, val x: Int, val y: Int) : Packet()
data class ComponentGroundItemAction(val player: Player, val iface: Int, val child: Int, val slot: Int, val itemId: Int, val x: Int, val y: Int) : Packet()
data class SlotSwitchMultiComponent(val player: Player, val sourceIface: Int, val sourceChild: Int, val sourceSlot: Int, val destIface: Int, val destChild: Int, val destSlot: Int) : Packet()
data class SlotSwitchSingleComponent(val player: Player, val iface: Int, val child: Int, val sourceSlot: Int, val destSlot: Int, val isInsert: Boolean) : Packet()
data class PacketCountUpdate(val player: Player, val count: Int) : Packet()
data class PrivateMessage(val player: Player, val username: String, val message: String) : Packet()
data class ChatMessage(val player: Player, val effects: Int, val message: String) : Packet()
data class ChatSetting(val player: Player, val public: Int, val private: Int, val trade: Int) : Packet()
data class Command(val player: Player, val commandLine: String) : Packet()
data class GESetOfferItem(val player: Player, val itemId: Int) : Packet()
data class TrackFinished(val player: Player, val trackId: Int) : Packet()
data class ReportAbuse(val player: Player, val target: String, val rule: Int, val modMute: Boolean) : Packet()
data class WorldspaceWalk(val player: Player, val destX: Int, val destY: Int, val isRun: Boolean) : Packet()
data class MinimapWalk(val player: Player, val destX: Int, val destY: Int, val clickedX: Int, val clickedY: Int, val rotation: Int, val isRun: Boolean) : Packet()
data class InteractWalk(val player: Player, val destX: Int, val destY: Int, val isRun: Boolean) : Packet()
data class Ping(val player: Player) : Packet()
data class QuickChat(val player: Player, val indexA: Int, val indexB: Int, val forClan: Boolean, val multiplier: Int, val offset: Int, val type: QCPacketType) : Packet()
data class InputPromptResponse(val player: Player, val response: Any) : Packet()
data class PlayerPrefsUpdate(val player: Player, val prefs: Int) : Packet()
class NoProcess : Packet()
class UnhandledOp : Packet()
data class DecodingError(val message: String) : Packet()
}
@@ -0,0 +1,35 @@
package rs09.net.packet.`in`
import api.sendDialogue
import core.game.node.entity.player.Player
/**
* Handles an incoming script execution request packet.
*
* @author vddCore
*/
object RunScript {
fun processInput(player: Player, value: Any, script: ((Any) -> Boolean)) {
if (value is Int && value <= 0) return
var input = value
if (player.getAttribute("parseamount", false)) {
input = value.toString().lowercase()
if (!input.matches(Regex("^(\\d+)(k+|m+)?$"))) {
sendDialogue(player, "That doesn't look right. Please try again.")
return
}
input = input.replace("k", "000").replace("m", "000000")
}
try {
script(input)
} catch (_: NumberFormatException) {
sendDialogue(player, "That number's a bit large, don't you think?")
}
}
}
@@ -1,56 +0,0 @@
package rs09.net.packet.`in`
import api.sendDialogue
import core.game.node.entity.player.Player
import core.net.packet.IncomingPacket
import core.net.packet.IoBuffer
import core.tools.StringUtils
/**
* Handles an incoming script execution request packet.
*
* @author vddCore
*/
class RunScriptPacketHandler : IncomingPacket {
private fun processInput(player: Player, value: Any, script: ((Any) -> Boolean)) {
if (value is Int && value <= 0) return
var input = value
if (player.getAttribute("parseamount", false)) {
input = value.toString().lowercase()
if (!input.matches(Regex("^(\\d+)(k+|m+)?$"))) {
sendDialogue(player, "That doesn't look right. Please try again.")
return
}
input = input.replace("k", "000").replace("m", "000000")
}
try {
script(input)
} catch (_: NumberFormatException) {
sendDialogue(player, "That number's a bit large, don't you think?")
}
}
override fun decode(player: Player, opcode: Int, buffer: IoBuffer) {
val script: ((Any) -> Boolean)? = player.getAttribute("runscript", null)
if (script == null || player.locks.isInteractionLocked)
return
val value: Any = when(opcode) {
244 -> StringUtils.longToString(buffer.long)
65 -> buffer.string
else -> buffer.int // Handles OpCode 23 and other cases.
}
processInput(player, value, script)
player.removeAttribute("parseamount")
player.removeAttribute("runscript")
}
}
@@ -10,6 +10,7 @@ import rs09.game.system.SystemLogger
import rs09.game.world.GameWorld
import rs09.game.world.repository.Repository
import rs09.game.world.update.UpdateSequence
import rs09.net.packet.PacketProcessor
import rs09.tools.stringtools.colorize
import java.lang.Long.max
import java.text.SimpleDateFormat
@@ -79,6 +80,8 @@ class MajorUpdateWorker {
}
fun handleTickActions(skipPulseUpdate: Boolean = false) {
PacketProcessor.processQueue()
if (!skipPulseUpdate) {
GameWorld.Pulser.updateAll()
}