Introduction/Discussing the problem: In Devolution 7, on most sources - you will find that the Friends list and Ignore list aren't configured. In other words, the methods aren't declared in the classes, and it has nowhere to load from.
I am also
IP on Moparscape - which I hardly check anymore, if you are wondering if I completely leeched his thread. It is me..
We are going to fix this.
Assumed Knowledge: Reading/Comprehending
Difficulty: 5/10 - Shouldn't be that hard if know how to follow along/modify the correct things.
Tested on: Rune-Legacy, which is a Devolution 7 based source. Although, in theory - this should work on
any source if you know how to correctly modify the methods, and know where to place the new ones.
Classes modified: Client class, Player class
Open your player class.
Search for the following.
Code:
public abstract void initialize();
You should see:
Code:
public abstract void initialize();
// PM Stuff
public void kick() {
isKicked = true;
}
Add the following under // PM Stuff
Code:
public abstract boolean isinpm(long l);
public abstract void loadpm(long l, int world);
public abstract void pmupdate(int pmid, int world);
So your final method should appear as:
Code:
public abstract void initialize();
// PM Stuff
public abstract boolean isinpm(long l);
public abstract void loadpm(long l, int world);
public abstract void pmupdate(int pmid, int world);
public void kick() {
isKicked = true;
}
Close your player class.
Open your client class.
Declare the following:
You
may or
may not have to add these but if you do here you go:
Code:
public int friendslot = 0;
public long friend64 = 0;
Code:
public int GetWorld(int PlayerID) {
try {
/* String Server = PlayerHandler.players[PlayerID].playerServer;
if (Server.equals("this doesn't matter")) {
return 1;
} else if (Server.equals("this doesn't matter.")) {
return 2;
} else {
//println_debug("Invalid Server: "+Server);
return -5;
}*/
return 1;
} catch (Exception e) {
System.out.println("Getworld error");
println_debug(e.toString());
return 1;
}
}
public void pmstatus(int status) { // status: loading = 0 connecting = 1 fine = 2
outStream.createFrame(221);
outStream.writeByte(status);
}
public boolean isinpm(long l) {
for (int i = 0; i < friends.length; i++) {
if (friends[i] != 0) {
if (l == friends[i]) {
return true;
}
}
}
return false;
}
public void pmupdate(int pmid, int world) {
long l = misc.playerNameToInt64(handler.players[pmid].playerName);
if (handler.players[pmid].Privatechat == 0) {
for (int i = 0; i < friends.length; i++) {
if (friends[i] != 0) {
if (l == friends[i]) {
loadpm(l, world);
return;
}
}
}
} else if (handler.players[pmid].Privatechat == 1) {
for (int i1 = 0; i1 < friends.length; i1++) {
if (friends[i] != 0) {
if (l == friends[i1]) {
if (handler.players[pmid].isinpm(
misc.playerNameToInt64(playerName))
&& playerRights > 2) {
loadpm(l, world);
return;
} else {
loadpm(l, 0);
return;
}
}
}
}
} else if (handler.players[pmid].Privatechat == 2) {
for (int i2 = 0; i2 < friends.length; i2++) {
if (friends[i] != 0) {
if (l == friends[i2] && playerRights < 2) {
loadpm(l, 0);
return;
}
}
}
}
}
public void sendpm(long name, int rights, byte[] chatmessage, int messagesize) {
outStream.createFrameVarSize(196);
outStream.writeQWord(name);
outStream.writeDWord(handler.lastchatid++); // must be different for each message
outStream.writeByte(rights);
outStream.writeBytes(chatmessage, messagesize, 0);
outStream.endFrameVarSize();
BufferedWriter bw = null;
String chatmessagegot = misc.textUnpack(chatmessage, messagesize);
String target = misc.longToPlayerName(name);
try {
bw = new BufferedWriter(new FileWriter("logs/pmlogs.txt", true));
bw.write(target + " -> " + playerName + ": " + chatmessagegot);
bw.newLine();
bw.flush();
} catch (IOException ioe) {
ioe.printStackTrace();
} finally {
if (bw != null) {
try {
bw.close();
} catch (IOException ioe2) {
sendMessage("Error logging chat!");
}
}
}
}
public void loadpm(long name, int world) {
if (world != 0) {
world += 9;
} else if (world == 0) {
world += 1;
}
outStream.createFrame(50);
outStream.writeQWord(name);
outStream.writeByte(world);
}
You may already have some of these methods, if you do: replace the ones you have with the ones shown above.
Search for:
Code:
handler.updatePlayer(this, outStream);
You should see something like this.
Code:
handler.updatePlayer(this, outStream);
handler.updateNPC(this, outStream);
setEquipment(playerEquipment[playerHat], playerEquipmentN[playerHat], playerHat);
setEquipment(playerEquipment[playerCape], playerEquipmentN[playerCape], playerCape);
setEquipment(playerEquipment[playerAmulet], playerEquipmentN[playerAmulet], playerAmulet);
setEquipment(playerEquipment[playerArrows], playerEquipmentN[playerArrows], playerArrows);
setEquipment(playerEquipment[playerChest], playerEquipmentN[playerChest], playerChest);
setEquipment(playerEquipment[playerShield], playerEquipmentN[playerShield], playerShield);
setEquipment(playerEquipment[playerLegs], playerEquipmentN[playerLegs], playerLegs);
setEquipment(playerEquipment[playerHands], playerEquipmentN[playerHands], playerHands);
setEquipment(playerEquipment[playerFeet], playerEquipmentN[playerFeet], playerFeet);
setEquipment(playerEquipment[playerRing], playerEquipmentN[playerRing], playerRing);
setEquipment(playerEquipment[playerWeapon], playerEquipmentN[playerWeapon], playerWeapon);
resetItems(3214);
resetBank();
GetBonus();
WriteBonus();
Below the WriteBonus(); - add the following.
Code:
pmstatus(2);
boolean pmloaded = false;
for (long element : friends) {
if (element != 0) {
for (int i2 = 1; i2 < handler.maxPlayers; i2++) {
if ((handler.players[i2] != null)
&& handler.players[i2].isActive
&& (misc
.playerNameToInt64(handler.players[i2].playerName) == element)) {
if ((playerRights >= 2)
|| (handler.players[i2].Privatechat == 0)
|| ((handler.players[i2].Privatechat == 1) && handler.players[i2]
.isinpm(misc
.playerNameToInt64(playerName)))) {
pmloaded = true;
}
break;
}
}
if (!pmloaded) {
loadpm(element, 0);
}
pmloaded = false;
}
}
for (int i1 = 1; i1 < handler.maxPlayers; i1++) {
if ((handler.players[i1] != null)
&& (handler.players[i1].isActive == true)) {
handler.players[i1].pmupdate(playerId, GetWorld(playerId));
}
}
Search for case 8: and you should see the following:
Code:
if (token.equals("character-friend")) {
Change that whole case to:
Code:
case 8:
if (token.equals("character-friend")) {
friends[Integer.parseInt(token3[0])] = Long.parseLong(
token3[1]);
friendslot = Integer.parseInt(token3[0]);
friend64 = Long.parseLong(token3[1]);
// System.out.println("Friends: "+friends);
// System.out.println("Loaded: "+Long.parseLong(token3[1]));
// System.out.println("Loaded: "+Integer.parseInt(token3[0]));
}
break;
Below that you should see case 9, which begins with
if (token.equals("character-ignore")) {
Change that case to the following:
Code:
case 9:
if (token.equals("character-ignore")) {
ignores[Integer.parseInt(token3[0])] = Long.parseLong(
token3[1]);
}
break;
Your going to want to make sure that below those cases you see:
Code:
else if (line.equals("[FRIENDS]"))
ReadMode = 8;
else if (line.equals("[IGNORES]"))
ReadMode = 9;
If it isn't that, modify the case 8 and 9 to what the ReadMode is. Example: If my ReadMode for Friends is 4, and my ReadMode for Ignores is 5, I would change my case 8: to case 4: and my case 9: to case 5:.
Step 2: Modifying the cases.
Search for:
which is the PM messaging case.
Change that
whole case to the following:
Code:
case 126:
// pm message
long friendtosend = inStream.readQWord();
byte pmchatText[] = new byte[100];
int pmchatTextSize = (byte) (packetSize - 8);
inStream.readBytes(pmchatText, pmchatTextSize, 0);
if(muted){
sendMessage("You are muted. Your message was not delivered.");
break;
}
for (long element : friends) {
if (element == friendtosend) {
boolean pmsent = false;
for (int i2 = 1; i2 < handler.maxPlayers; i2++) {
if ((handler.players[i2] != null)
&& handler.players[i2].isActive
&& (misc
.playerNameToInt64(handler.players[i2].playerName) == friendtosend)) {
if ((playerRights >= 2)
|| (handler.players[i2].Privatechat == 0)
|| ((handler.players[i2].Privatechat == 1) && handler.players[i2]
.isinpm(misc
.playerNameToInt64(playerName)))) {
handler.players[i2].sendpm(misc
.playerNameToInt64(playerName),
playerRights, pmchatText,
pmchatTextSize);
pmsent = true;
}
break;
}
}
if (!pmsent) {
sendMessage("Player currently not available");
break;
}
}
}
break;
Next, search for case 188: - which is the Adding friends case.
Change that whole case to
Code:
case 188:
// add friend
friendUpdate = true;
long friendtoadd = inStream.readQWord();
boolean CanAdd = true;
for (long element : friends) {
if ((element != 0) && (element == friendtoadd)) {
CanAdd = false;
sendMessage("This player is already on your friends list.");
}
}
if (CanAdd == true) {
for (int i1 = 0; i1 < friends.length; i1++) {
if (friends[i1] == 0) {
friends[i1] = friendtoadd;
for (int i2 = 1; i2 < handler.maxPlayers; i2++) {
if ((handler.players[i2] != null)
&& handler.players[i2].isActive
&& (misc
.playerNameToInt64(handler.players[i2].playerName) == friendtoadd)) {
if ((playerRights >= 2)
|| (handler.players[i2].Privatechat == 0)
|| ((handler.players[i2].Privatechat == 1) && handler.players[i2]
.isinpm(misc
.playerNameToInt64(playerName)))) {
loadpm(friendtoadd, GetWorld(i2));
break;
}
}
}
break;
}
}
}
break;
Next, search for case 215: - which is the removing friends case.
Change the whole case to:
Code:
case 215:
// remove friend
friendUpdate = true;
long friendtorem = inStream.readQWord();
for (int i1 = 0; i1 < friends.length; i1++) {
if (friends[i1] == friendtorem) {
friends[i1] = 0;
break;
}
}
break;
Search for case 133: - which is the Adding Ignore case.
Change that whole case to:
Code:
case 133:
// add ignore
friendUpdate = true;
long igtoadd = inStream.readQWord();
for (int i10 = 0; i10 < ignores.length; i10++) {
if (ignores[i10] == 0) {
ignores[i10] = igtoadd;
break;
}
}
break;
Search for case 74: - which is the Remove ignore case.
Change that whole case to:
Code:
case 74:
// remove ignore
friendUpdate = true;
long igtorem = inStream.readQWord();
for (int i11 = 0; i11 < ignores.length; i11++) {
if (ignores[i11] == igtorem) {
ignores[i11] = 0;
break;
}
}
break;
Search for:
Code:
characterfile.write("[FRIENDS]", 0, 9);
Change that whole section to:
Code:
characterfile.write("[FRIENDS]", 0, 9);
characterfile.newLine();
for (int i = 0; i < friends.length; i++) {
if (friends[i] >= 0) {
characterfile.write("character-friend = ", 0, 19);
characterfile.write(Integer.toString(i), 0,
Integer.toString(i).length());
characterfile.write(" ", 0, 1);
characterfile.write(Long.toString(friends[i]), 0,
Long.toString(friends[i]).length());
characterfile.newLine();
}
}
Below that you should see:
Code:
characterfile.write("[IGNORES]", 0, 9);
Change that whole section to:
Code:
characterfile.write("[IGNORES]", 0, 9);
characterfile.newLine();
for (int i = 0; i < ignores.length; i++) {
if (ignores[i] > 0) {
characterfile.write("character-ignore = ", 0, 19);
characterfile.write(Integer.toString(i), 0,
Integer.toString(i).length());
characterfile.write(" ", 0, 1);
characterfile.write(Long.toString(ignores[i]), 0,
Long.toString(ignores[i]).length());
characterfile.newLine();
}
}
Finally, declare:
Code:
public void setChatOptions(int publicChat, int privateChat, int tradeBlock) {
outStream.createFrame(206);
outStream.writeByte(publicChat); // On = 0, Friends = 1, Off = 2,
// Hide = 3
outStream.writeByte(privateChat); // On = 0, Friends = 1, Off = 2
outStream.writeByte(tradeBlock); // On = 0, Friends = 1, Off = 2
}
If you already have the setChatOptions method, just replace the one you have with the one shown above.
Note: This should work with any source, but it was tested and working on Devolution 7.
Also note that the loading process does have some bugs. The most common bug appears as follows:
If a player is online, and you are adding them for the
first time, it will have them appear online as your friends list. If you then log out, it will save to your friends list. If you are logging on to the server
again and one or more of the friends you have
added already on your list are online, it won't show them on your list. This is common throughout other servers and I am working on a fix for this. Please just bear with me.
Rep is appreciated. Please post your thoughts and feedback. Thanks
- Grey.
Credits - 90% me - rewriting whole tutorial.
- 10% whoever posted these methods before. I couldn't find a tutorial so I was forced to rip them from sources that had a working friends list on my computer.
This took time to find all the correct methods, and to actually get it working - so please be nice
.