mirror of
https://github.com/EngineHub/WorldGuard.git
synced 2024-11-27 13:07:29 +01:00
Track cause through targets.
Fixes WORLDGUARD-3314.
This commit is contained in:
parent
66a8bfd5b1
commit
451b679323
@ -20,23 +20,17 @@
|
|||||||
package com.sk89q.worldguard.bukkit.cause;
|
package com.sk89q.worldguard.bukkit.cause;
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import com.sk89q.worldguard.bukkit.internal.WGMetadata;
|
import com.sk89q.worldguard.bukkit.internal.WGMetadata;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.*;
|
||||||
import org.bukkit.entity.EntityType;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.entity.Projectile;
|
|
||||||
import org.bukkit.entity.TNTPrimed;
|
|
||||||
import org.bukkit.entity.Tameable;
|
|
||||||
import org.bukkit.entity.Vehicle;
|
|
||||||
import org.bukkit.metadata.Metadatable;
|
import org.bukkit.metadata.Metadatable;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.Set;
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
@ -49,23 +43,36 @@
|
|||||||
* is the initiator, while the arrow is merely controlled by the player to
|
* is the initiator, while the arrow is merely controlled by the player to
|
||||||
* hit the item frame.</p>
|
* hit the item frame.</p>
|
||||||
*/
|
*/
|
||||||
public class Cause {
|
public final class Cause {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(Cause.class.getCanonicalName());
|
|
||||||
private static final String CAUSE_KEY = "worldguard.cause";
|
private static final String CAUSE_KEY = "worldguard.cause";
|
||||||
private static final Cause UNKNOWN = new Cause(Collections.emptyList());
|
private static final Cause UNKNOWN = new Cause(Collections.emptyList(), false);
|
||||||
private static final int MAX_CAUSE_LENGTH = 40;
|
|
||||||
|
|
||||||
private final List<Object> causes;
|
private final List<Object> causes;
|
||||||
|
private final boolean indirect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new instance.
|
* Create a new instance.
|
||||||
*
|
*
|
||||||
* @param causes a list of causes
|
* @param causes a list of causes
|
||||||
|
* @param indirect whether the cause is indirect
|
||||||
*/
|
*/
|
||||||
private Cause(List<Object> causes) {
|
private Cause(List<Object> causes, boolean indirect) {
|
||||||
checkNotNull(causes);
|
checkNotNull(causes);
|
||||||
this.causes = causes;
|
this.causes = causes;
|
||||||
|
this.indirect = indirect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the traced cause is indirect.
|
||||||
|
*
|
||||||
|
* <p>If the cause is indirect, then the root cause may not be notified,
|
||||||
|
* for example.</p>
|
||||||
|
*
|
||||||
|
* @return true if the cause is indirect
|
||||||
|
*/
|
||||||
|
public boolean isIndirect() {
|
||||||
|
return indirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -159,51 +166,6 @@ public String toString() {
|
|||||||
return Joiner.on(" | ").join(causes);
|
return Joiner.on(" | ").join(causes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Expand an cause object.
|
|
||||||
*
|
|
||||||
* @param list the list to add elements to
|
|
||||||
* @param element an array of objects
|
|
||||||
*/
|
|
||||||
private static void expand(List<Object> list, @Nullable Object ... element) {
|
|
||||||
if (list.size() >= MAX_CAUSE_LENGTH) {
|
|
||||||
log.log(Level.WARNING, "While discovering the true cause of an event, the chain of " +
|
|
||||||
"causes exceeded the limit (" + MAX_CAUSE_LENGTH + "). This could be " +
|
|
||||||
"caused by a circular cause (arrow's shooter = arrow).", new RuntimeException());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element != null) {
|
|
||||||
for (Object o : element) {
|
|
||||||
if (o == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (o instanceof TNTPrimed) {
|
|
||||||
expand(list, ((TNTPrimed) o).getSource());
|
|
||||||
} else if (o instanceof Projectile) {
|
|
||||||
expand(list, ((Projectile) o).getShooter());
|
|
||||||
} else if (o instanceof Vehicle) {
|
|
||||||
expand(list, ((Vehicle) o).getPassenger());
|
|
||||||
} else if (o instanceof Tameable) {
|
|
||||||
expand(list, ((Tameable) o).getOwner());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add manually tracked parent causes
|
|
||||||
Object source = o;
|
|
||||||
int index = list.size();
|
|
||||||
while (source instanceof Metadatable && !(source instanceof Block)) {
|
|
||||||
source = WGMetadata.getIfPresent((Metadatable) source, CAUSE_KEY, Object.class);
|
|
||||||
if (source != null) {
|
|
||||||
list.add(index, source);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
list.add(o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new instance with the given objects as the cause,
|
* Create a new instance with the given objects as the cause,
|
||||||
* where the first-most object is the initial initiator and those
|
* where the first-most object is the initial initiator and those
|
||||||
@ -212,11 +174,11 @@ private static void expand(List<Object> list, @Nullable Object ... element) {
|
|||||||
* @param cause an array of causing objects
|
* @param cause an array of causing objects
|
||||||
* @return a cause
|
* @return a cause
|
||||||
*/
|
*/
|
||||||
public static Cause create(@Nullable Object ... cause) {
|
public static Cause create(@Nullable Object... cause) {
|
||||||
if (cause != null) {
|
if (cause != null) {
|
||||||
List<Object> causes = new ArrayList<Object>(cause.length);
|
Builder builder = new Builder(cause.length);
|
||||||
expand(causes, cause);
|
builder.addAll(cause);
|
||||||
return new Cause(causes);
|
return builder.build();
|
||||||
} else {
|
} else {
|
||||||
return UNKNOWN;
|
return UNKNOWN;
|
||||||
}
|
}
|
||||||
@ -251,4 +213,60 @@ public static void trackParentCause(Metadatable target, Object parent) {
|
|||||||
WGMetadata.put(target, CAUSE_KEY, parent);
|
WGMetadata.put(target, CAUSE_KEY, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds causes.
|
||||||
|
*/
|
||||||
|
private static final class Builder {
|
||||||
|
private final List<Object> causes;
|
||||||
|
private final Set<Object> seen = Sets.newHashSet();
|
||||||
|
private boolean indirect;
|
||||||
|
|
||||||
|
private Builder(int expectedSize) {
|
||||||
|
this.causes = new ArrayList<Object>(expectedSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addAll(@Nullable Object... element) {
|
||||||
|
if (element != null) {
|
||||||
|
for (Object o : element) {
|
||||||
|
if (o == null || seen.contains(o)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
seen.add(o);
|
||||||
|
|
||||||
|
if (o instanceof TNTPrimed) {
|
||||||
|
addAll(((TNTPrimed) o).getSource());
|
||||||
|
} else if (o instanceof Projectile) {
|
||||||
|
addAll(((Projectile) o).getShooter());
|
||||||
|
} else if (o instanceof Vehicle) {
|
||||||
|
addAll(((Vehicle) o).getPassenger());
|
||||||
|
} else if (o instanceof Creature && ((Creature) o).getTarget() != null) {
|
||||||
|
indirect = true;
|
||||||
|
addAll(((Creature) o).getTarget());
|
||||||
|
} else if (o instanceof Tameable) {
|
||||||
|
indirect = true;
|
||||||
|
addAll(((Tameable) o).getOwner());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add manually tracked parent causes
|
||||||
|
Object source = o;
|
||||||
|
int index = causes.size();
|
||||||
|
while (source instanceof Metadatable && !(source instanceof Block)) {
|
||||||
|
source = WGMetadata.getIfPresent((Metadatable) source, CAUSE_KEY, Object.class);
|
||||||
|
if (source != null) {
|
||||||
|
causes.add(index, source);
|
||||||
|
seen.add(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
causes.add(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cause build() {
|
||||||
|
return new Cause(causes, indirect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ public RegionProtectionListener(WorldGuardPlugin plugin) {
|
|||||||
* @param what what was done
|
* @param what what was done
|
||||||
*/
|
*/
|
||||||
private void tellErrorMessage(DelegateEvent event, Cause cause, Location location, String what) {
|
private void tellErrorMessage(DelegateEvent event, Cause cause, Location location, String what) {
|
||||||
if (event.isSilent()) {
|
if (event.isSilent() || cause.isIndirect()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user