diff --git a/data/plugins/player-action/login.rb b/data/plugins/player-action/login.rb
new file mode 100644
index 00000000..ee2c78d3
--- /dev/null
+++ b/data/plugins/player-action/login.rb
@@ -0,0 +1,6 @@
+java_import 'org.apollo.game.model.entity.Player'
+
+on :login do |event, player|
+ show_action(player, TRADE_ACTION)
+ show_action(player, FOLLOW_ACTION)
+end
\ No newline at end of file
diff --git a/data/plugins/player-action/player-action.rb b/data/plugins/player-action/player-action.rb
new file mode 100644
index 00000000..46144a49
--- /dev/null
+++ b/data/plugins/player-action/player-action.rb
@@ -0,0 +1,59 @@
+require 'java'
+
+java_import 'org.apollo.game.message.impl.SetPlayerActionMessage'
+java_import 'org.apollo.game.model.entity.Player'
+
+class PlayerAction
+ attr_reader :slot, :primary, :name
+
+ def initialize(slot, primary, name)
+ index = [ :first, :second, :third, :fourth, :fifth ].find_index(slot)
+ raise "Unsupport action slot #{slot}." if index.nil?
+
+ @slot = index
+ @primary = primary
+ @name = name
+ end
+
+end
+
+ATTACK_ACTION = PlayerAction.new(:third, true, 'Attack')
+CHALLENGE_ACTION = PlayerAction.new(:third, true, 'Challenge')
+TRADE_ACTION = PlayerAction.new(:fourth, true, 'Trade with')
+FOLLOW_ACTION = PlayerAction.new(:fifth, true, 'Follow')
+
+# Shows multiple context menu action for the specified player
+def show_actions(player, *actions)
+ raise 'Must specify at least one action to show' if actions.nil?
+
+ actions.each do |action|
+ player.add_action(action)
+ player.send(SetPlayerActionMessage.new(action.name, action.slot, action.primary))
+ end
+end
+
+# Shows a single context menu action for the specified player
+def show_action(player, action)
+ show_actions(player, action)
+end
+
+# Hides a context menu action for the specified player
+def hide_action(player, action)
+ show_action(player, PlayerAction.new('null', action.slot, action.primary))
+end
+
+class Player
+
+ def actions
+ @actions ||= {}
+ end
+
+ def add_action(action)
+ actions[action.slot] = action.name
+ end
+
+ def has_action(action)
+ return actions[action.slot] == action.name
+ end
+
+end
\ No newline at end of file
diff --git a/data/plugins/player-action/plugin.xml b/data/plugins/player-action/plugin.xml
new file mode 100644
index 00000000..82a7d15f
--- /dev/null
+++ b/data/plugins/player-action/plugin.xml
@@ -0,0 +1,15 @@
+
+
+ player-action
+ 1
+ Player actions
+ Manages player right click actions
+
+ Ryley
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/org/apollo/net/codec/game/GamePacketDecoder.java b/src/org/apollo/net/codec/game/GamePacketDecoder.java
index 5434ce1e..947cd87f 100644
--- a/src/org/apollo/net/codec/game/GamePacketDecoder.java
+++ b/src/org/apollo/net/codec/game/GamePacketDecoder.java
@@ -4,7 +4,6 @@ import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
-import java.io.IOException;
import java.util.List;
import net.burtleburtle.bob.rand.IsaacRandom;
@@ -61,7 +60,7 @@ public final class GamePacketDecoder extends StatefulFrameDecoder out, GameDecoderState state) throws IOException {
+ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List