[19.1]QuickBox - Tutorial and FAQ

Posts 1–15 of 23 · Page 1 of 2
[19.1]QuickBox - Tutorial and FAQ
Helleeeeooooowww,
first of all, this is not a set-up guide. This tutorial is for unconventional uses of QuickBox.
This Tutorial is written for version Beta 1 of QuickBox. There is a very high chance of me changing a lot of things in the future, so the information in this post could be outdated if you are using versions after Beta 1.

I. Master - RR Communication

(Almost) Every time the master moves, he is sending a PLAYERSHOOT packet to RR. To identify, that this packet is not a regular packet, it has the time set to 42. The x and y position of the master are then equal to the startingPos. Do with it whatever you want.
Code:
function onClientPacket(event) {
    var packet = event.getPacket();
    switch (packet.id()){
        case ID_PLAYERSHOOT: {
            if(packet.time == 42){
                masterx = packet.startingPos.x;
                mastery = packet.startingPos.y;
            
                event.cancel();
            }
            break;
        }
    }
}
Important: Make sure to cancel the event. CANCEL THE EVENT!

II. RR - Slave Communication
To tell the slave where it should move, simply send an AOE packet to the client with the following information:
effect: has to be 42
radius: the X position where to go
duration: the Y position where to go
The location of the AOE packet will be disregarded, it doesn't matter what values you put in there.

Code:
function sendMasterPacket(){
    masterLocPacket = $.createPacket(ID_AOE);
    masterLocPacket.effect = 42;
    masterLocPacket.radius = masterx;
    masterLocPacket.duration = mastery;

    // Doesn't matter:
        locDummy = $.createLocation();
    locDummy.x = 0;
    locDummy.y = 0;
    masterLocPacket.pos = locDummy;
    masterLocPacket.damage = 0;
    masterLocPacket.origType = 0;

    $.sendToClient(masterLocPacket);
}
Once sent, the slave will automatically walk to that position. This doesn't have to be a master position. It can be anything you want. Do with it whatever you want. I'm not giving you any ideas, I'm sure you got some yourself

FAQ
Q: Why using AOE packets? You crazy?
A: Yeah I was just experimenting, but once it worked, I was too lazy to change it again. I'll change the whole system in a future version, but for now, this'll do

Q: How does RR knows the difference between master and slave?
A: Once RR receives a PLAYERSHOOT packet with the time of 42, it marks this client as master. All others will be slaves to RR

Q: Can I add paladin or warrior buffs?
A: Sure! Check if the client is a slave. Check if the client is a paladin/warrior and has the 2nd slot item equipped. Check if the one you want to buff is in range. Do it depending on time intervals or other conditions (e.g. mana). I'm doing all these steps already for priests and healing (not properly at some points, but you'll get the idea). If you need more help, just ask!

Q: How are the slaves moving? Are you faking MOVE packets?
A: I simulate keyboard input. That's also why they only move in 45° angles at the moment. 059 gave me some ideas how to improve on that

Q: Why even making a client for the master and not getting the position from the MOVE packet instead?
A: The client only sends MOVE packets every tick - not fast enough for multiboxing!

Q: I'm experimenting with this, but I'm getting Protocol error! What do I do wrong?
A: Don't send AOE packets to the master or other clients than slaves. Make sure you follow the rules in section II.

I hope this answers most of the questions. If there are still others, just ask

greetz,
Quick
Cool stuff man. Have you considered making this into a mod selector mod so we could customize our clients?
Quote Originally Posted by 059 View Post
Cool stuff man. Have you considered making this into a mod selector mod so we could customize our clients?
Yep. Modselector mods will come with the first non-beta release!
Quote Originally Posted by QuickNick View Post
Yep. Modselector mods will come with the first non-beta release!
Oh awesome, I'm psyched, can't wait.
Now I see this:

The clients won't load. Any tips?
Would love to see this as a modselector. RR is having a lot of troubles for me.
Quote Originally Posted by Limit67 View Post
Would love to see this as a modselector. RR is having a lot of troubles for me.
Sorry, you misunderstood my post there. Even if released as a modselector mod, it will require RR (or maybe some other proxy in the future). I will not code a direct connection between clients.. never.

The benefit from making this a modselector mod is, that you can decide on your own what other mods your master/slaves will have.
Quote Originally Posted by QuickNick View Post
Sorry, you misunderstood my post there. Even if released as a modselector mod, it will require RR (or maybe some other proxy in the future). I will not code a direct connection between clients.. never.

The benefit from making this a modselector mod is, that you can decide on your own what other mods your master/slaves will have.
What about using your client as the default "client.swf"?
Im trying to download the quickbox beta1 release, but since i am on way to slow connection i get networks errors and the download disconnects.

I want to a look and get a quickstart on groking how it works, until i get a better net and am able to test it and hack properly again.

I was wondering if any of you kind RR hackers could post me just the realmrelay scripts that comes with the release?

Thanks!
Quote Originally Posted by fuckyoutwo View Post
Im trying to download the quickbox beta1 release, but since i am on way to slow connection i get networks errors and the download disconnects.

I want to a look and get a quickstart on groking how it works, until i get a better net and am able to test it and hack properly again.

I was wondering if any of you kind RR hackers could post me just the realmrelay scripts that comes with the release?

Thanks!
Sure

 
quickbox.js
Code:
// quickbox.js
// Made by QuickNick - MPGH.net


var ID_PLAYERSHOOT = $.findPacketId("PLAYERSHOOT");
var ID_MOVE = $.findPacketId("MOVE");
var ID_CREATE_SUCCESS = $.findPacketId("CREATE_SUCCESS");
var ID_AOE = $.findPacketId("AOE");
var ID_TELEPORT = $.findPacketId("TELEPORT");
var ID_UPDATE = $.findPacketId("UPDATE");
var ID_NEW_TICK = $.findPacketId("NEW_TICK");
var ID_USEITEM = $.findPacketId("USEITEM");
var ID_USEPORTAL = $.findPacketId("USEPORTAL");


var masterx = 0;
var mastery = 0
var masterid = 0;
var isMaster = false;
var playerLocation = -1;
var playerId = 0;
var players = new Object();
var playersHP = new Object();
var playersMaxHP = new Object();
var playersMana = new Object();
var playersMaxMana = new Object();
var playersLocations = new Object();
var masterPortal = 0;
var isHealer = false;
var healingTome = 0;
var lastTp = 0;


var STATS_HP = 1;
var STATS_MANA = 4;


var clientTime = 0;




function onClientPacket(event) {
    var packet = event.getPacket();
    if (packet.time && packet.time != 42)
    {
        clientTime = packet.time;
    }
    switch (packet.id()){
        case ID_PLAYERSHOOT: {
            if(packet.time == 42){
            
                if(!isMaster && playerId > 0){
                    isMaster = true;
                    masterid = playerId;
                    $.setGlobal("masterid", masterid);
                }
                
                masterx = packet.startingPos.x;
                mastery = packet.startingPos.y;
                $.setGlobal("masterx", masterx);
                $.setGlobal("mastery", mastery);
                
                
                
                sendMasterPacket();
            
                event.cancel();
            }
            break;
        }
        case ID_MOVE: {
            playerLocation = packet.newPosition;
            break;
        }
        case ID_USEPORTAL: {
            $.setGlobal("masterPortal", packet.objectId);
            break;
        }
    }
    
    if(masterx != $.getGlobal("masterx") || mastery != $.getGlobal("mastery")){
        sendMasterPacket();
    }
}


function onServerPacket(event) {
    if(!isMaster && $.getGlobal("masterid") > 0 && playerLocation != -1){
        checkForTp();
    }
    var packet = event.getPacket();
    if(masterx != $.getGlobal("masterx") || mastery != $.getGlobal("mastery")){
        sendMasterPacket();
    }
    switch (packet.id()){
        case ID_CREATE_SUCCESS: {
            playerId = packet.objectId;
            $.setGlobal("masterPortal", 0);
            break;
        }
        case ID_UPDATE: {
            var newObjs = packet.newObjs;
            
            // Find playerids
            for (var i in newObjs){
                var type = newObjs[i].objectType;
                if(type == 768 || type == 775 || type == 782 || type == 784 || (type >= 797 && type <= 806)){
                    var data = newObjs[i].status.data;
                    var objId = newObjs[i].status.objectId;
                    for (var j in data){
                        if (data[j].obf0 == 31){
                            var objName = data[j].obf2.toLowerCase();
                            players[objName] = objId;
                        }                    
                        if (data[j].obf0 == 9 && (data[j].obf1 == 2609 || data[j].obf1 == 2775 || data[j].obf1 == 2610 || data[j].obf1 == 2776 || data[j].obf1 == 2611 || data[j].obf1 == 2651 || data[j].obf1 == 2853 || data[j].obf1 == 3081 || data[j].obf1 == 3102) && objId == playerId){ 
                            isHealer = true;
                            healingTome = data[j].obf1;
                        }
                    }
                }
            }
            break;
        }
        case ID_NEW_TICK: {
            var statuses = packet.statuses;
            for (var i in statuses){
                for (var name in players){
                    var id = players[name];
                    if (statuses[i].objectId == id){
                        var data = statuses[i].data;
                        playersLocations[id] = statuses[i].pos;
                        for (var j in data){
                            if (data[j].obf0 == STATS_HP){
                                playersHP[id] = data[j].obf1;
                                if(playersMaxHP[id] == undefined || playersHP[id] > playersMaxHP[id]){
                                    playersMaxHP[id] = playersHP[id];
                                }
                            }
                            if (data[j].obf0 == STATS_MANA){
                                playersMana[id] = data[j].obf1;
                                if(playersMaxMana[id] == undefined || playersHP[id] > playersMaxMana[id]){
                                    playersMaxMana[id] = playersMana[id];
                                }
                            }
                        }
                    }
                }
            }
        
            checkForHeal();
            break;
        }
    }
}


function checkForTp(){
    if ((Math.abs(masterx - playerLocation.x) > 5 || Math.abs(mastery - playerLocation.y) > 5) && clientTime - lastTp > 10000) {
        var tpPacket = $.createPacket(ID_TELEPORT);
        tpPacket.objectId = $.getGlobal("masterid");
        $.sendToServer(tpPacket);
        lastTp = clientTime;
    }
    if ($.getGlobal("masterPortal") != 0){
        var usePortalPacket = $.createPacket(ID_USEPORTAL);
        usePortalPacket.objectId = $.getGlobal("masterPortal");
        $.sendToServer(usePortalPacket);
    }
}


function checkForHeal(){
    for (var name in players) {
        var id = players[name];
        if (playersHP[id] < playersMaxHP[id] * 0.65 && playersMana[playerId] >= 80 && isHealer){
            var distance = playerLocation.distanceTo(playersLocations[id]);
            if (distance < 6){
                heal();
            }
        }
    }
}


function heal(){
    var slotObj = $.createSlotObject();
    slotObj.objectId = playerId;
    slotObj.slotId = 1;
    slotObj.objectType = healingTome;
    
    var useItemPacket = $.createPacket(ID_USEITEM);
    useItemPacket.time = clientTime;
    useItemPacket.slotObject = slotObj;
    useItemPacket.itemUsePos = playerLocation;
    useItemPacket.useType = 1;
    
    $.sendToServer(useItemPacket);
}


function sendMasterPacket(){
    masterx = $.getGlobal("masterx");
    mastery = $.getGlobal("mastery");


    masterLocPacket = $.createPacket(ID_AOE);
    masterLocPacket.effect = 42;
    masterLocPacket.radius = masterx;
    masterLocPacket.duration = mastery;
    
    locDummy = $.createLocation();
    locDummy.x = 0;
    locDummy.y = 0;
    masterLocPacket.pos = locDummy;
    masterLocPacket.damage = 0;
    masterLocPacket.origType = 0;
    $.sendToClient(masterLocPacket);
}
instead of aoe packets you could send a playershoot with a time of 43 or something, instead of sending and receiving useless data such as the location with the aoe packet

might make things a tiny bit faster
Quote Originally Posted by 059 View Post
instead of aoe packets you could send a playershoot with a time of 43 or something, instead of sending and receiving useless data such as the location with the aoe packet

might make things a tiny bit faster
Nope can't do. Playershoot is a client packet, but I need a server packet here. But even if it would work, there wouldn't be any noticable difference. To add just these few bytes doesn't even take a millisec. Best packet would be a GOTO packet (only id and location), but I was too lazy to access another member (location.x / location.y instead of just radius and duration)
Thanks for posting the code!

Its a bit hard to follow sometimes, but its short enough that that doesnt matter. Important thing is it works, right? =)

I am a bit puzzled some things though, some are just sloppy which are OK for a beta... But starting on line 134 you have:
Code:
                            if (data[j].obf0 == STATS_HP){
                                playersHP[id] = data[j].obf1;
                                if(playersMaxHP[id] == undefined || playersHP[id] > playersMaxHP[id]){
                                    playersMaxHP[id] = playersHP[id];
                                }
                            }
                            if (data[j].obf0 == STATS_MANA){
                                playersMana[id] = data[j].obf1;
                                if(playersMaxMana[id] == undefined || playersHP[id] > playersMaxMana[id]){
                                    playersMaxMana[id] = playersMana[id];
                                }
                            }
That is just gross :P

Why dont you use a check against data[j].obf0 == 0 (0 being maxhealth) and whatever the obf0 is for maxmana? (probably 3 or possibly 5)

Yeah, you really should use a GOTO packet, it makes way more sense; also, maybe a negative packet.time might make more sense then 42, as 42 can happen naturally. Checking the client-generated packets I cant find anyone which makes sence, but AEOACK seems like a better fit then PLAYERSHOOT.... That is, if custom packets are out of the window...?

I have quite a few ideas for uses other then multi-boxing... I am a decent coder with knowdledge of halv a dozen popular programming languages and another dozen obscure ones. Would you like to work together on quickbox?
Quote Originally Posted by fuckyoutwo View Post
maybe a negative packet.time might make more sense then 42, as 42 can happen naturally.
What.. the..
You can't be serious! What blasphemy. Sorry... You can have coding knowledge of more languages than C3PO can speak, but after that sentence, you are not worthy to work with me!
Posts 1–15 of 23 · Page 1 of 2
This thread is closed for replies.

Similar Threads

Tags for this Thread

None

Need help?