Skip to content

Commit

Permalink
Add damage history tracking and assist logic
Browse files Browse the repository at this point in the history
Signed-off-by: Pugzy <[email protected]>
  • Loading branch information
Pugzy committed May 20, 2024
1 parent 3bffdeb commit 8cfe113
Show file tree
Hide file tree
Showing 11 changed files with 360 additions and 2 deletions.
9 changes: 9 additions & 0 deletions core/src/main/java/tc/oc/pgm/PGMConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static tc.oc.pgm.util.text.TextParser.parseComponentLegacy;
import static tc.oc.pgm.util.text.TextParser.parseDuration;
import static tc.oc.pgm.util.text.TextParser.parseEnum;
import static tc.oc.pgm.util.text.TextParser.parseFloat;
import static tc.oc.pgm.util.text.TextParser.parseInteger;
import static tc.oc.pgm.util.text.TextParser.parseLogLevel;
import static tc.oc.pgm.util.text.TextParser.parseUri;
Expand Down Expand Up @@ -78,6 +79,7 @@ public final class PGMConfig implements Config {
// gameplay.*
private final boolean woolRefill;
private final int griefScore;
private final float assistPercent;

// join.*
private final long minPlayers;
Expand Down Expand Up @@ -175,6 +177,8 @@ public final class PGMConfig implements Config {
this.woolRefill = parseBoolean(config.getString("gameplay.refill-wool", "true"));
this.griefScore =
parseInteger(config.getString("gameplay.grief-score", "-10"), Range.atMost(0));
this.assistPercent =
parseFloat(config.getString("gameplay.assist-percent", "0.3"), Range.openClosed(0f, 1f));

this.minPlayers = parseInteger(config.getString("join.min-players", "1"));
this.limitJoin = parseBoolean(config.getString("join.limit", "true"));
Expand Down Expand Up @@ -552,6 +556,11 @@ public int getGriefScore() {
return griefScore;
}

@Override
public float getAssistPercent() {
return assistPercent;
}

@Override
public boolean showSideBar() {
return showSideBar;
Expand Down
7 changes: 7 additions & 0 deletions core/src/main/java/tc/oc/pgm/api/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,13 @@ public interface Config {
*/
int getGriefScore();

/**
* Gets the percentage of damage needed on a player to get an assist
*
* @return The percentage of damage required
*/
float getAssistPercent();

/**
* Gets a group of players, used for prefixes and player sorting.
*
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/java/tc/oc/pgm/api/Modules.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import tc.oc.pgm.damage.DamageModule;
import tc.oc.pgm.damage.DisableDamageMatchModule;
import tc.oc.pgm.damage.DisableDamageModule;
import tc.oc.pgm.damagehistory.DamageHistoryMatchModule;
import tc.oc.pgm.death.DeathMessageMatchModule;
import tc.oc.pgm.destroyable.DestroyableMatchModule;
import tc.oc.pgm.destroyable.DestroyableModule;
Expand Down Expand Up @@ -220,6 +221,7 @@ void registerAll() {
register(TNTRenderMatchModule.class, TNTRenderMatchModule::new);
register(PlayerTimeMatchModule.class, PlayerTimeMatchModule::new);
register(SpectateMatchModule.class, SpectateMatchModule::new);
register(DamageHistoryMatchModule.class, DamageHistoryMatchModule::new);

// FIXME: Disabled due to lag - look into future optimization
// register(ProjectileTrailMatchModule.class, ProjectileTrailMatchModule::new);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,19 @@ public class MatchPlayerDeathEvent extends MatchPlayerEvent {
private final PlayerDeathEvent parent;
private final DamageInfo damageInfo;
private final boolean predicted;
private @Nullable final ParticipantState assister;

public MatchPlayerDeathEvent(
PlayerDeathEvent parent, MatchPlayer victim, DamageInfo damageInfo, boolean predicted) {
PlayerDeathEvent parent,
MatchPlayer victim,
DamageInfo damageInfo,
boolean predicted,
@Nullable ParticipantState assister) {
super(assertNotNull(victim));
this.parent = assertNotNull(parent);
this.damageInfo = assertNotNull(damageInfo);
this.predicted = predicted;
this.assister = assister;
}

/**
Expand Down Expand Up @@ -70,6 +76,15 @@ public final boolean isPredicted() {
return predicted;
}

/**
* Get the {@link ParticipantState} of the assisting killer.
*
* @return The assister {@link ParticipantState}, or {@code null} if no killer.
*/
public @Nullable ParticipantState getAssister() {
return assister;
}

/**
* Get whether the given {@link MatchPlayer} is the victim.
*
Expand Down
33 changes: 33 additions & 0 deletions core/src/main/java/tc/oc/pgm/damagehistory/DamageEntry.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package tc.oc.pgm.damagehistory;

import org.jetbrains.annotations.Nullable;
import tc.oc.pgm.api.player.ParticipantState;

public class DamageEntry {

@Nullable private ParticipantState damager;
private double damage;

public DamageEntry(@Nullable ParticipantState damager, double damage) {
this.damager = damager;
this.damage = damage;
}

@Nullable
public ParticipantState getDamager() {
return damager;
}

public double getDamage() {
return damage;
}

public void addDamage(@Nullable ParticipantState damager, double damage) {
this.damager = damager;
this.damage += damage;
}

public void removeDamage(double damage) {
this.damage -= damage;
}
}
64 changes: 64 additions & 0 deletions core/src/main/java/tc/oc/pgm/damagehistory/DamageHistory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package tc.oc.pgm.damagehistory;

import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.UUID;
import org.jetbrains.annotations.Nullable;
import tc.oc.pgm.api.player.MatchPlayer;
import tc.oc.pgm.api.player.ParticipantState;

public class DamageHistory {

public static final double EPSILON = 0.00001;

private final Map<UUID, Deque<DamageEntry>> allPlayerDamage = new HashMap<>();

public DamageHistory() {}

public Deque<DamageEntry> getPlayerHistory(UUID uuid) {
return allPlayerDamage.computeIfAbsent(uuid, item -> new LinkedList<>());
}

public void addDamage(
MatchPlayer target, double damageAmount, @Nullable ParticipantState attacker) {
Deque<DamageEntry> playerHistory = getPlayerHistory(target.getId());

// Update existing if same player causing damage
if (!playerHistory.isEmpty()) {
DamageEntry last = playerHistory.getLast();
if (shouldMergeParticipants(last.getDamager(), attacker)) {
last.addDamage(attacker, damageAmount);
return;
}
}

playerHistory.addLast(new DamageEntry(attacker, damageAmount));
}

public void removeDamage(MatchPlayer target, double damageAmount) {
Deque<DamageEntry> playerHistory = getPlayerHistory(target.getId());
if (playerHistory.isEmpty()) return;

double subtractAmount = damageAmount;
while (!playerHistory.isEmpty() && subtractAmount > 0) {
DamageEntry first = playerHistory.getFirst();
if (first.getDamage() < subtractAmount + EPSILON) {
subtractAmount -= first.getDamage();
playerHistory.removeFirst();
} else {
first.removeDamage(subtractAmount);
break;
}
}
}

public boolean shouldMergeParticipants(ParticipantState firstItem, ParticipantState secondItem) {
if (firstItem == null || secondItem == null) return firstItem == secondItem;

// Only allow if they share the same UUID and party
if (!firstItem.getId().equals(secondItem.getId())) return false;
return (firstItem.getParty().equals(secondItem.getParty()));
}
}
49 changes: 49 additions & 0 deletions core/src/main/java/tc/oc/pgm/damagehistory/DamageHistoryKey.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package tc.oc.pgm.damagehistory;

import static tc.oc.pgm.util.Assert.assertNotNull;

import java.util.Objects;
import java.util.UUID;
import tc.oc.pgm.api.party.Competitor;
import tc.oc.pgm.api.player.ParticipantState;

public class DamageHistoryKey {

private final ParticipantState state;

public DamageHistoryKey(ParticipantState state) {
this.state = state;
}

public static DamageHistoryKey from(DamageEntry damageEntry) {
ParticipantState damager = damageEntry.getDamager();
assertNotNull(damager);
return new DamageHistoryKey(damager);
}

public ParticipantState getState() {
return state;
}

public UUID getPlayer() {
return state.getId();
}

public Competitor getParty() {
return state.getParty();
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DamageHistoryKey that = (DamageHistoryKey) o;
return Objects.equals(getPlayer(), that.getPlayer())
&& Objects.equals(getParty(), that.getParty());
}

@Override
public int hashCode() {
return Objects.hash(getPlayer(), getParty());
}
}
Loading

0 comments on commit 8cfe113

Please sign in to comment.