here's how i did it
1. i created a custom class for nearby monsters (ID,Model) and i called it Monster
2. a Dictionary for continuous<ContinuousID uint,UID uint> damage (skills,burn etc) and i called it _continuousdmg
3. i created another custom class for each player & the damage he done to a specific monster (PlayerID (UniqueID) uint,Damage uint) and called it PDmg
4. a custom class (Mob) & list for each nearby monster (Monster mob,List<PDmg> players) called it _dmg
- mob1 spawns
- player1 attacks mob1
- filter checks if mob1 is in the list of nearby monsters
- filter checks if player1 has attacked mob1 before
- filter adds player1 to the Players list if not exists
- filter adds damage done to mob1 to player1 in the PDmg list
- filter checks if mob1 is dead (if yes i used linq to get the highest dmg done to it along with the playerID and save it in the database)
Packet (0xB070) (Alot of actions but we're using it for Basic attacks,and skill damage):
Code:
if(pck.readbyte() == 1 && pck.readbyte() == 2 && pck.readbyte() == 0x30)
{
uint SID = pck.readuint(); // Skill ID... probably
uint uID = pck.readuint(); // Player UniqueID
uint CID = pck.readuint(); // Continuous skill ID (random)
uint Target = pck.readuint(); // Target monster / player
if(Target == 0)
return;
if(!_dmg.Any(i=>i.Monster.ID == Target)) // Monster doesn't exist in the list
_dmg.Add(new Mob() {
Monster = _nearbyMobs.FirstOrDefault(i=>i.ID==Target), // Monster from the nearby monsters list (use groupspawn & single spawn and parse them to get a list of mobs)
players = new List<PDmg>(),
});
/* Continue Parsing */
byte isSkill = pck.readbyte(); // Player is casting a skill
if(isSkill == 0) // idk why but 0 == casting a skill LOL
{
_continuousdmg.Add(CID,uID);
return;
}
byte numofattacks = pck.readbyte(); // for multi hits skills (salamanderblow, bow's knockback etc)
byte targets = pck.readbyte(); // targets hit by this skill
bool dead = false; // mob bb?
Dictionary<uint,bool> _targets = new Dictionary<uint,bool>();
for(int i = 1; i<=targets;++i){
uint targetID = pck.readuint();
byte status = pck.readbyte(); // Status 128 = dead, 133 = demolished (not sure)
_targets.Add(targetID,status == 128 || status == 133);
dead = _targets[targetID];
if(!_dmg.Any(i=>i.Monster.ID == targetID)) // Monster doesn't exist in the list (copied hh)
_dmg.Add(new Mob() {
Monster = _nearbyMobs.FirstOrDefault(i=>i.ID==targetID), // Monster from the nearby monsters list (use groupspawn & single spawn and parse them to get a list of mobs)
players = new List<PDmg>(),
});
for (byte z = 1; z <= numofattacks; z++)
{
if (pck.Remain > 1) // idk but sometimes it's empty doesn't hurt to do a lil check
{
byte crit = pck.ReadByte(); // crit hit (hh)
uint dmg = pck.ReadUInt(); // damage done
pck.ReadByte(); // idk
pck.ReadUShort(); // i still dont know
_dmg.First(i=>i.Monster.ID==targetID)?.players?.Add(new PDmg(){
PlayerID = uID,
Damage = 0
});
_dmg.First(i=>i.Monster.ID==targetID)?.players.Find(i=>i.PlayerID==uID).Damage += dmg;
}
}
}
}
NOTE: missing the 0xB071 packet for continuous damage. i'll add it later
i used to play grindroad (Emulator server) back in 2011-2012
they had a system that i liked ever since.
it goes like this
1- unique spawns
2- a bunch of players attack the unique
3- unique dies
4- a message that contains top 4 players (order by damage desc) is sent to all nearby players (same region) in academy chat