Skip to content

Commit

Permalink
Added an OnPvP compatability event (#356)
Browse files Browse the repository at this point in the history
* Added an OnPvP compatability event

See Issue #338:
#338

* Fixed duplicate LivingAttackEvents

Alleviate the Forge bug causing duplicate posts of the
LivingAttackEvent. Forge posts this event twice, once in EntityPlayer,
and once in EntityLivingBase, so this tells if an EntityPlayer got hurt
but the event was posted as an EntityLivingBase, then immediately
returns, so nothing important gets run twice.

* Review 1: Added an OnPvP compatability event

* Improved pvpadmin command

`pvpadmin resetCooldown <player>`
and
`pvpadmin spy <player> [on|off]`

* Review 2: Added an OnPvP compatability event

Co-Authored-By: Mahtaran <[email protected]>

Update src/main/java/pvpmode/api/server/compatibility/events/OnPvPEvent.java

Co-Authored-By: Mahtaran <[email protected]>
  • Loading branch information
2 people authored and CraftedMods committed Aug 26, 2019
1 parent f5547f5 commit 8787a62
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 41 deletions.
31 changes: 31 additions & 0 deletions src/main/java/pvpmode/api/common/utils/PvPCommonUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@

import org.apache.commons.io.IOUtils;

import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.event.entity.living.LivingAttackEvent;
import pvpmode.PvPMode;
import pvpmode.api.common.SimpleLogger;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;

public class PvPCommonUtils
{
Expand Down Expand Up @@ -426,6 +430,33 @@ public static <T> Collection<T> createInstances (
return createInstances (classes, null, null);
}

/**
* Returns whether this is a bugged duplicate post of the LivingAttackEvent.
* Forge posts this event twice, once in EntityPlayer, and once in
* EntityLivingBase, so this will tell if an EntityPlayer got hurt but the
* event was posted as an EntityLivingBase. This should only be called from
* an {@link SubscribeEvent @SubscribeEvent} method with the event type of
* {@link LivingAttackEvent}.
*
* @param event
* The event to be checked
* @return If an EntityPlayer got hurt but the event was posted as an
* EntityLivingBase
*/
@SuppressWarnings("deprecation")
@CallerSensitive
public static boolean isCurrentAttackDuplicate (LivingAttackEvent event)
{
if (! (event.entityLiving instanceof EntityPlayer))
return false;
for (StackTraceElement element : Thread.currentThread ().getStackTrace ())
{
if (Reflection.getCallerClass (7) == EntityLivingBase.class)
return true;
}
return false;
}

/**
* Returns a {@link SimpleLogger} instance assigned to the specified name.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package pvpmode.api.server.compatibility.events;

import cpw.mods.fml.common.eventhandler.*;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.DamageSource;
import pvpmode.api.common.EnumPvPMode;

/**
* Fired when a player attacks another player.
*
* @author Vinyarion
*
*/
@Cancelable
public class OnPvPEvent extends Event
{

private final EntityPlayer attacker;
private final EnumPvPMode attackerMode;
private final EntityPlayer victim;
private final EnumPvPMode victimMode;
private final float damageAmount;
private final DamageSource source;

public OnPvPEvent (EntityPlayer attacker, EnumPvPMode attackerMode, EntityPlayer victim, EnumPvPMode victimMode, float damageAmount, DamageSource source)
{
this.attacker = attacker;
this.attackerMode = attackerMode;
this.victim = victim;
this.victimMode = victimMode;
this.damageAmount = damageAmount;
this.source = source;
}

/**
* Returns the attacker
*/
public EntityPlayer getAttacker ()
{
return attacker;
}

/**
* Returns the attacker's mode
*/
public EnumPvPMode getAttackerMode ()
{
return attackerMode;
}

/**
* Returns the victim
*/
public EntityPlayer getVictim ()
{
return victim;
}

/**
* Returns the victim's mode
*/
public EnumPvPMode getVictimMode ()
{
return victimMode;
}

/**
* Returns the amount of damage to be dealt
*/
public float getDamageAmount ()
{
return damageAmount;
}

/**
* Returns the damage source
*/
public DamageSource getSource ()
{
return source;
}

}
83 changes: 42 additions & 41 deletions src/main/java/pvpmode/internal/server/PvPServerEventHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import net.minecraftforge.event.entity.player.PlayerDropsEvent;
import pvpmode.PvPMode;
import pvpmode.api.common.EnumPvPMode;
import pvpmode.api.common.utils.PvPCommonUtils;
import pvpmode.api.common.version.*;
import pvpmode.api.server.PvPData;
import pvpmode.api.server.compatibility.events.*;
Expand All @@ -43,11 +44,17 @@ public PvPServerEventHandler ()

/**
* Cancels combat events associated with PvP-disabled players. Note that this
* function will be invoked twice per attack - this is because of a Forge bug.
* function will be invoked twice per attack - this is because of a Forge bug,
* but the {@link PvPCommonUtils#isCurrentAttackDuplicate()} call checks and
* returns if this call is a duplicate
*/
@SubscribeEvent
public void interceptPvP (LivingAttackEvent event)
{
// This alleviates duplicate entries.
if (PvPCommonUtils.isCurrentAttackDuplicate (event))
return;

EntityPlayerMP attacker = PvPServerUtils.getMaster (event.source.getEntity ());
EntityPlayerMP victim = PvPServerUtils.getMaster (event.entity);

Expand All @@ -57,7 +64,12 @@ public void interceptPvP (LivingAttackEvent event)
EnumPvPMode attackerMode = PvPServerUtils.getPvPMode (attacker);
EnumPvPMode victimMode = PvPServerUtils.getPvPMode (victim);

boolean cancel = false;
if (MinecraftForge.EVENT_BUS
.post (new OnPvPEvent (attacker, attackerMode, victim, victimMode, event.ammount, event.source)))
{
event.setCanceled (true);
return;
}

if (attackerMode != EnumPvPMode.ON)
{
Expand All @@ -76,11 +88,6 @@ else if (PvPServerUtils.canFly (attacker))
ServerChatUtils.red (attacker, "You have PvP disabled");
}
}
cancel = true;
}

if (cancel)
{// For performance reasons
event.setCanceled (true);
return;
}
Expand All @@ -91,56 +98,50 @@ else if (PvPServerUtils.canFly (attacker))
{
ServerChatUtils.red (attacker, "This player/unit has PvP disabled");
}
cancel = true;
}

if (cancel)
{
event.setCanceled (true);
return;
}
else

if (attacker == event.source.getEntity () && victim == event.entity)
{
if (attacker == event.source.getEntity () && victim == event.entity)
{
// Both involved entities are players which can attack each other
// Both involved entities are players which can attack each other

long time = PvPServerUtils.getTime ();
long time = PvPServerUtils.getTime ();

PvPData attackerData = PvPServerUtils.getPvPData (attacker);
PvPData victimData = PvPServerUtils.getPvPData (victim);
PvPData attackerData = PvPServerUtils.getPvPData (attacker);
PvPData victimData = PvPServerUtils.getPvPData (victim);

if (attackerData.getPvPTimer () == 0)
{
ServerChatUtils.yellow (attacker, "You're now in PvP combat");
}
if (attackerData.getPvPTimer () == 0)
{
ServerChatUtils.yellow (attacker, "You're now in PvP combat");
}

if (victimData.getPvPTimer () == 0)
{
ServerChatUtils.yellow (victim, "You're now in PvP combat");
}
if (victimData.getPvPTimer () == 0)
{
ServerChatUtils.yellow (victim, "You're now in PvP combat");
}

attackerData.setPvPTimer (time + config.getPvPTimer ());
victimData.setPvPTimer (time + config.getPvPTimer ());
attackerData.setPvPTimer (time + config.getPvPTimer ());
victimData.setPvPTimer (time + config.getPvPTimer ());

if (attackerData.getPvPWarmup () != 0)
{
attackerData.setPvPWarmup (0);
ServerChatUtils.yellow (attacker, "Your warmup timer was canceled because you started an attack");
}
if (attackerData.getPvPWarmup () != 0)
{
attackerData.setPvPWarmup (0);
ServerChatUtils.yellow (attacker, "Your warmup timer was canceled because you started an attack");
}

if (victimData.getPvPWarmup () != 0)
{
victimData.setPvPWarmup (0);
ServerChatUtils.yellow (victim, "Your warmup timer was canceled because you were attacked");
}
if (victimData.getPvPWarmup () != 0)
{
victimData.setPvPWarmup (0);
ServerChatUtils.yellow (victim, "Your warmup timer was canceled because you were attacked");
}
}

}

/*
* We need to log here because the LivingAttackEvent will be fired twice per
* attack.
* We need to log here because the damage in the LivingAttackEvent can change
* from the attack to the actual application of the damage.
*/
@SubscribeEvent
public void onLivingHurt (LivingHurtEvent event)
Expand Down

0 comments on commit 8787a62

Please sign in to comment.