|
Basically what we are doing here is modifying the client to send every button click packet with the parent interface id, and we're installing a system to control how buttons are processed. This will also prevent players from faking clicks/item actions on any interface they aren't actually viewing. You will need to track sidebars too, but I'll leave that to you.
The base is: http://www.rune-server.org/runescape...8-14-13-a.html, but can adapted.
Server sided
First we add this class:
then this class:Code:package org.model.actor.player.inter; import org.model.actor.player.Player; /** * Processes interface clicking. * * @author Michael Sasse * */ public interface InterfaceAction { /** * Actions to take when a button is clicked * @param p * the (@Player) * @param id * the button id */ public void click(Player p, int id); /** * Do an item action on an interface */ public void doItemAction(Player p, int slot, int id, int amount); }
then this class:Code:package org.model.actor.player.inter; import org.model.actor.player.inter.impl.*; import java.util.HashMap; import java.util.Map; /** * Constants for user interfaces * * @author Michael Sasse * */ public class InterfaceConstants { /** * A map of (@InterfaceAction)s */ private static final Map<Integer, InterfaceAction> actions = new HashMap<Integer, InterfaceAction>(); /** * The default interface manager. */ public static final DefaultInterfaceAction DEFAULT_ACTIONS = new DefaultInterfaceAction(); /** * The bank interface id */ public static final int BANK = 5292; /** * Sets the interface actions */ static { actions.put(BANK, new BankInterfaceAction()); } /** * Gets the (@InterfaceButton) for the id */ public static final InterfaceAction getInterfaceManager(int id) { return actions.get(id); } }
and here's two implementations for reference:Code:package org.model.actor.player.inter; import static org.model.actor.player.inter.InterfaceConstants.*; import org.RuntimeConstants; import org.model.actor.player.Player; /** * Controls client actions based on the current user interface. * This could be adapted to work with the cache later, for further verification of client actions. * * @author Michael Sasse * */ ///TODO: using items with these interfaces adapted to this public class Interfaces { /** * The current interface id */ private int current = -1; /** * The current sub-interface id */ private int sub = -1; /** * Item actions on an interface */ public void onItemAction(Player p, int slot, int id, int amount, int inter) { if (inter == current || inter == sub) { InterfaceAction manager = getInterfaceManager(inter); if (manager != null) manager.doItemAction(p, slot, id, amount); } else { DEFAULT_ACTIONS.doItemAction(p, slot, id, amount); } if (RuntimeConstants.DEBUG) p.getActionSender().sendMessage("item action interface: " + inter); } /** * Actions to do when clicking a button * * @param id * the button id * @param inter * the interface id */ public void onButton(Player p, int id, int inter) { if (inter == current || inter == sub) { InterfaceAction manager = getInterfaceManager(inter); if (manager != null) manager.click(p, id); } else { DEFAULT_ACTIONS.click(p, id); } if (RuntimeConstants.DEBUG) { p.getActionSender().sendMessage("button: " + id + ", interface: " + inter); } } /** * Sets the current interface id */ public void setCurrent(int current, int sub) { this.current = current; this.sub = sub; } /** * Resets the current interface to none */ public void reset() { current = -1; sub = -1; } }
Code:package org.model.actor.player.inter.impl; import org.model.actor.player.Player; import org.model.actor.player.inter.InterfaceAction; /** * Bank interface actions. * * @author Michael Sasse * */ public class BankInterfaceAction implements InterfaceAction { /* * (non-Javadoc) * @see org.model.actor.player.inter.InterfaceButton#click(org.model.actor.player.Player, int) */ @Override public void click(Player p, int id) { } /* * (non-Javadoc) * @see org.model.actor.player.inter.InterfaceAction#doItemAction(org.model.actor.player.Player, int, int, int) */ @Override public void doItemAction(Player p, int slot, int id, int amount) {} }Now you will have to adapt your send interface packet to set the current interface id like so:Code:package org.model.actor.player.inter.impl; import org.model.actor.player.Player; import org.model.actor.player.inter.InterfaceAction; /** * Actions that are either always executable or undefined. * * @author Michael Sasse * */ public class DefaultInterfaceAction implements InterfaceAction { /* * (non-Javadoc) * @see org.model.actor.player.inter.InterfaceButton#click(org.model.actor.player.Player, int) */ @Override public void click(Player p, int id) { switch (id) { case 9154: p.logout(); break; case 153: p.getMovement().setRun(true); break; case 152: p.getMovement().setRun(false); break; } } /* * (non-Javadoc) * @see org.model.actor.player.inter.InterfaceAction#doItemAction(org.model.actor.player.Player, int, int, int) */ @Override public void doItemAction(Player p, int slot, int id, int amount) { } }
And when you send interfaces that also display an interact-able inventory:Code:client.getPlayer().getInterfaces().setCurrent(id, -1);
And this is how you decode the button:Code:client.getPlayer().getInterfaces().setCurrent(id, inventoryId);
The final thing you need to do is make the packet size for opcode 185 4 bytes long:Code:player.getInterfaces().onButton(player, NetConstants.hexToInt(in.readBytes(2)), in.readShort(StreamBuffer.ValueType.A));
Client sidedCode:/** * Lengths for the various packets. */ public static final int PACKET_LENGTHS[] = { 0, 0, 0, 1, -1, 0, 0, 0, 0, 0, // 0 0, 0, 0, 0, 8, 0, 6, 2, 2, 0, // 10 0, 2, 0, 6, 0, 12, 0, 0, 0, 0, // 20 0, 0, 0, 0, 0, 8, 4, 0, 0, 2, // 30 2, 6, 0, 6, 0, -1, 0, 0, 0, 0, // 40 0, 0, 0, 12, 0, 0, 0, 0, 8, 0, // 50 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, // 60 6, 0, 2, 2, 8, 6, 0, -1, 0, 6, // 70 0, 0, 0, 0, 0, 1, 4, 6, 0, 0, // 80 0, 0, 0, 0, 0, 3, 0, 0, -1, 0, // 90 0, 13, 0, -1, 0, 0, 0, 0, 0, 0,// 100 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, // 110 1, 0, 6, 0, 0, 0, -1, 0, 2, 6, // 120 0, 4, 6, 8, 0, 6, 0, 0, 0, 2, // 130 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, // 140 0, 0, 1, 2, 0, 2, 6, 0, 0, 0, // 150 0, 0, 0, 0, -1, -1, 0, 0, 0, 0,// 160 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 170 0, 8, 0, 3, 0, 4, 0, 0, 8, 1, // 180 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, // 190 2, 0, 0, 0, 0, 0, 0, 0, 4, 0, // 200 4, 0, 0, 0, 7, 8, 0, 0, 10, 0, // 210 0, 0, 0, 0, 0, 0, -1, 0, 6, 0, // 220 1, 0, 0, 0, 6, 0, 6, 8, 1, 0, // 230 0, 4, 0, 0, 0, 0, -1, 0, -1, 4,// 240 0, 0, 6, 6, 0, 0, 0 // 250 };
replace the button sending packets (should be 2) with this:
And finally enjoy. I hope someone actually uses this.Code:clientOutputStream.createFrame(185); clientOutputStream.writeWord(k); clientOutputStream.method432(RSInterface.interfaceCache[k].parentID);
Not bad, gj.
Great work on this. Innovative too.
Convert it to PI
then i might use it..
u know u could load the interface data server-sided and check the parentid?? - if u do it client-sided some1 could just edit the info being sent.
Cache definitions of interfaces contain the entire parent > child hierarchy, no need to send information that is already in the server's possession (if you load those definitions, that is).
Actually, it doesn't take much (I understand your point though). Using the parent id that is loaded from the cache, you can simply check whether or not the player currently has that interface opened. Remember that everything has its unique interface id, including buttons, inventories, etcetera. Nearly all of them have a parent id that is directly linked to an "openable" interface (e.g. the buttons within the bank window have the id of the bank window itself as their parent:
That's a simple outline of how it can be done (Apollo).Code:InterfaceDefinition def = InterfaceDefinition.forId(event.getInterfaceId()); if (!player.getInterfaceSet().isOpened(def.getParentId()) { ctx.breakHandlerChain(); return; }
I implemented a system like that for my server a few days ago. The only problem I ran into was custom interfaces, since most idiots just put the parent id as the id of whatever they're currently building (buttons, sprites, etc). But I did get it working for every action and it should prevent cheating on interfaces entirely (when I fix the parent IDs for custom interfaces).
« Previous Thread | Next Thread » |
Thread Information |
Users Browsing this ThreadThere are currently 1 users browsing this thread. (0 members and 1 guests) |