Anti kill steal

Discussion in 'Spigot Plugin Development' started by Exellanix, May 20, 2016.

  1. I am making a combat plugin and I want to make it so players can not kill steal. I have no idea of how I would attempt this, and I am hoping someone can walk me through how I would do this. I want to get the total damage someone did to a player, when the player dies it adds up the total damage of all players that hit them, then, whoever got the most damage, gets the kill.
     
  2. Whenever someone is damaged, keep track of who did it, and once they get killed, just figure out who did the most damage. You'll also have to keep track of the order that the damages happened, because as the person heals the oldest damage records will probably need to be deleted accordingly.

    Edit: if you want more specific details, I would recommend maybe a custom DamageRecord object representing a single damage event that keeps track of amount of damage and player, then use a Java queue to store DamageRecords, and finally, keep those queues in a Map of (player being damaged->queue).
     
    #2 Pangea, May 20, 2016
    Last edited: May 20, 2016
    • Winner Winner x 2
    • Agree Agree x 1
  3. Finding who did the most damage simply won't do, he's looking for the killer which can simply be identified by setting a variable for getEntity().getKiller() in a PlayerDeathEvent.
     
  4. You're wrong. He wants it so when a player dies to another player, it won't necessarily be that player that got the kill, but whoever did the most damage to the player before his death.
     
    • Agree Agree x 3
  5. I think he's not. He is looking for the one that did most damage.
     
    • Agree Agree x 1
  6. Read the main post and re-read your post. Bet you will see the problem.
     
  7. You could just simply use a double HashMap that would look like this HashMap<Player, HashMap<Player, int>> the first Player is the one that gets the damage and the second Player is the Damager. The Integer is simply the damage.
     
  8. Don't store a player, store the name or UUID instead.
     
  9. How i would do it: Create a List for every player. In this you store Objects with the attributes Player (or uuid) and Damage. Every time a player damages another player it gets added to the list. When a player heals, the amount will be subtracted from the first. When a player dies you can simply find out who did the most damage.
     
  10. I would create a class called Damage that would be initialized with a Player and an integer. Then I would make a HashMap that would store a Player and a List<Damage> and once you want to calculate the total damage I would iterate over the damage values, and for each player in the damage objects, I would make a new HashMap with a Player and List<Integer>. Then I would make a for each call and make another hashmap with a player and integer, and for each integer in the hashmap i would add to a list of integers. Then I would sort the list and reverse it. Then get the first value in the list, and there is your top damager!
     
  11. I kind of already solved it. Here:

    Code (Text):
    package io.github.exellanix.advancedcombat.util;

    import org.bukkit.entity.Player;

    import java.util.HashMap;
    import java.util.TreeSet;

    /**
    * Created by Exellanix on 5/19/2016.
    */
    public class DamageTracker {

        private HashMap<Player, Double> damage;

        private int cooldown;

        public DamageTracker() {
            damage = new HashMap<>();
            cooldown = 0;
        }

        public void decrementCooldown() {
            if(cooldown == 0 && !damage.isEmpty()) {
                damage.clear();
            }else if(cooldown > 0) {
                cooldown--;
            }
        }

        public int getCooldown() {
            return cooldown;
        }

        public Player getKiller() {
            TreeSet<DamageValues> damageSet = new TreeSet<>();
            for(Player p : damage.keySet()) {
                damageSet.add(new DamageValues(p, damage.get(p)));
            }
            if(damageSet.size() > 0) {
                return damageSet.last().p;
            }else{
                return null;
            }
        }

        public void takeDamage(Player p, double damageAmount) {
            if(damage.containsKey(p)) {
                damage.put(p, damage.get(p) + damageAmount);
            }else{
                damage.put(p, damageAmount);
            }
            cooldown = 10;
        }

        public void resetCooldown() {
            cooldown = 0;
        }

        private class DamageValues implements Comparable<DamageValues> {

            Player p;
            double d;

            public DamageValues(Player p, double d) {
                this.p = p;
                this.d = d;
            }

            @Override
            public int compareTo(DamageValues o) {
                if(this.d < o.d) {
                    return -1;
                }else if(this.d > o.d) {
                    return 1;
                }else{
                    return 0;
                }
            }
        }
    }
     
    And Here:

    Code (Text):
    package io.github.exellanix.advancedcombat.listeners;

    import io.github.exellanix.advancedcombat.AdvancedCombat;
    import io.github.exellanix.advancedcombat.util.DamageTracker;
    import org.bukkit.Bukkit;
    import org.bukkit.entity.Player;
    import org.bukkit.event.EventHandler;
    import org.bukkit.event.EventPriority;
    import org.bukkit.event.Listener;
    import org.bukkit.event.entity.EntityDamageByEntityEvent;
    import org.bukkit.event.entity.PlayerDeathEvent;
    import org.bukkit.event.player.PlayerJoinEvent;
    import org.bukkit.event.player.PlayerKickEvent;
    import org.bukkit.event.player.PlayerQuitEvent;
    import org.bukkit.scheduler.BukkitRunnable;

    import java.util.HashMap;

    /**
    * Created by Brendan on 5/15/2016.
    */

    public class AntiKS implements Listener {

        private HashMap<Player, DamageTracker> damage = new HashMap<>();

        public AntiKS() {
            AdvancedCombat.getSingleton().getServer().getScheduler().runTaskTimer(AdvancedCombat.getSingleton(), new BukkitRunnable() {
                @Override
                public void run() {
                    for(Player p : Bukkit.getOnlinePlayers()) {
                        damage.get(p).decrementCooldown();
                    }
                }
            }, 0, 20);
        }

        @EventHandler(priority = EventPriority.MONITOR)
        public void onDamage(EntityDamageByEntityEvent event) {
            if(event.getDamager() instanceof Player && event.getEntity() instanceof Player) {
                if(event.getEntity() != event.getDamager()) {
                    if(!event.isCancelled()) {
                        damage.get(event.getEntity()).takeDamage((Player) event.getDamager(), event.getFinalDamage());
                    }
                }
            }
        }

        @EventHandler
        public void onJoin(PlayerJoinEvent event) {
            damage.put(event.getPlayer(), new DamageTracker());
        }

        @EventHandler
        public void onQuit(PlayerQuitEvent event) {
            damage.remove(event.getPlayer());
        }

        @EventHandler
        public void onKick(PlayerKickEvent event) {
            damage.remove(event.getPlayer());
        }

        @EventHandler
        public void onDeath(PlayerDeathEvent event) {
            if(damage.get(event.getEntity()).getCooldown() > 0) {
                Player killer = damage.get(event.getEntity()).getKiller();
                if(killer != null) {
                    //TODO give killer money

                    //TODO make custom death messages in another death event

                }
            }
            damage.get(event.getEntity()).resetCooldown();
        }
    }
     
    I have not tested this yet though.