Skip to content

Commit

Permalink
Prevent mobs targeting mobs in their friends group.
Browse files Browse the repository at this point in the history
New/changed mob type properties:

 * Comma- or space-separated lists of tag strings are now merged
   into sorted sets with case-insensitive string comparison, for
   properties `tags`, `groups` (new) and `friend-groups` (new).
 * `groups` is the set of groups a mob type belongs to.
 * `friend-groups` is the set of groups that the mob type
   refuses to target.
  • Loading branch information
totemo committed Apr 17, 2020
1 parent 6108197 commit af4010f
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 16 deletions.
41 changes: 41 additions & 0 deletions src/nu/nerd/beastmaster/BeastMaster.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package nu.nerd.beastmaster;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.bukkit.Bukkit;
Expand Down Expand Up @@ -29,6 +31,7 @@
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
import org.bukkit.event.entity.EntityTeleportEvent;
import org.bukkit.event.entity.ProjectileHitEvent;
import org.bukkit.event.entity.ProjectileLaunchEvent;
Expand Down Expand Up @@ -742,6 +745,44 @@ protected void onEntityDeath(EntityDeathEvent event) {

} // onEntityDeath

// ------------------------------------------------------------------------
/**
* Prevent a mob from targeting any other mob whose "groups" set includes a
* name that is in the targeting mob's "friend-groups".
*/
@SuppressWarnings("unchecked")
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
protected void onEntityTargetLivingEntity(EntityTargetLivingEntityEvent event) {
Entity targetter = event.getEntity();
LivingEntity target = event.getTarget();
if (!(targetter instanceof LivingEntity)) {
return;
}

// If the targeting mob is not friendly to any groups, no action needed.
MobType mobType = getMobType(targetter);
if (mobType == null) {
return;
}
Set<String> friendGroups = (Set<String>) mobType.getDerivedProperty("friend-groups").getValue();
if (friendGroups == null || friendGroups.isEmpty()) {
return;
}

// Targeted mob.
MobType targetType = getMobType(target);
Set<String> targetGroups = targetType == null ? Collections.EMPTY_SET
: (Set<String>) targetType.getDerivedProperty("groups").getValue();

// If the targeted mob is a friend, don't target.
for (String friend : friendGroups) {
if (targetGroups.contains(friend)) {
event.setCancelled(true);
return;
}
}
}

// ------------------------------------------------------------------------
/**
* Play the teleport-sound, if configured for the mob.
Expand Down
28 changes: 17 additions & 11 deletions src/nu/nerd/beastmaster/mobs/DataType.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;

import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
Expand Down Expand Up @@ -103,17 +107,15 @@ public int compare(Object o1, Object o2) {

// ------------------------------------------------------------------------
/**
* Comma separated list of Strings assumed to be scoreboard tags.
* Comma separated ordered set of case-insensitive Strings.
*
* Spaces are treated as equivalent to commas.
*
* Tags are compared case-sensitively. I assume that it might occasionally
* matter for scoreboard tags.
*/
public static final IDataType TAG_LIST = new IDataType() {
public static final IDataType TAG_SET = new IDataType() {
@SuppressWarnings("unchecked")
@Override
public String format(Object value) {
return String.join(",", (String[]) value);
return ((Set<String>) value).stream().collect(Collectors.joining(","));
}

@Override
Expand All @@ -128,15 +130,19 @@ public String serialise(Object value) {

@Override
public Object deserialise(String value) throws IllegalArgumentException {
// Sort to account for hand-edited configs.
String[] tags = value.split(",");
Arrays.sort(tags);
return tags;
Set<String> set = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
// Handle input like: "," by removing empty tags.
List<String> tags = Arrays.asList(value.split(",")).stream()
.filter(tag -> !tag.isEmpty())
.sorted(String.CASE_INSENSITIVE_ORDER)
.collect(Collectors.toList());
set.addAll(tags);
return set;
}

@Override
public int compare(Object o1, Object o2) {
return serialise(o1).compareTo(serialise(o2));
return serialise(o1).compareToIgnoreCase(serialise(o2));
}
};

Expand Down
13 changes: 8 additions & 5 deletions src/nu/nerd/beastmaster/mobs/MobType.java
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,14 @@ protected void addProperties() {

// Behaviour ----------------------------------------------------------

addProperty(new MobProperty("groups", DataType.TAG_SET, null));
addProperty(new MobProperty("friend-groups", DataType.TAG_SET, null));
addProperty(new MobProperty("tags", DataType.TAG_SET, (mob, logger) -> {
@SuppressWarnings("unchecked")
Set<String> tags = (Set<String>) getDerivedProperty("tags").getValue();
mob.getScoreboardTags().addAll(tags);
}));

addProperty(new MobProperty("anger-ticks", DataType.INTEGER, (mob, logger) -> {
int ticks = (Integer) getDerivedProperty("anger-ticks").getValue();
if (mob instanceof Bee) {
Expand All @@ -641,11 +649,6 @@ protected void addProperties() {
boolean canDespawn = (Boolean) getDerivedProperty("can-despawn").getValue();
mob.setRemoveWhenFarAway(canDespawn);
}));
addProperty(new MobProperty("tags", DataType.TAG_LIST, (mob, logger) -> {
String[] tags = (String[]) getDerivedProperty("tags").getValue();
mob.getScoreboardTags().addAll(Arrays.asList(tags));
}));

// projectile-... properties are enforced in ProjectileLaunchEvent and
// ProectileHitEvent handlers.
addProperty(new MobProperty("projectile-mobs", DataType.LOOT_OR_MOB, null));
Expand Down

0 comments on commit af4010f

Please sign in to comment.