Towards vehicles with multiple passengers.

This commit is contained in:
asofold 2017-04-02 18:42:52 +02:00
parent f7a11bbc95
commit 30c3a40622
9 changed files with 204 additions and 99 deletions

View File

@ -0,0 +1,24 @@
package fr.neatmonster.nocheatplus.compat.bukkit;
import java.util.List;
import org.bukkit.entity.Entity;
import fr.neatmonster.nocheatplus.components.entity.IEntityAccessVehicle;
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
public class EntityAccessVehicleMultiPassenger implements IEntityAccessVehicle {
public EntityAccessVehicleMultiPassenger() {
// TODO: List<Entity>
if (ReflectionUtil.getMethodNoArgs(Entity.class, "getPassengers", List.class) == null) {
throw new RuntimeException("Not supported.");
}
}
@Override
public List<Entity> getEntityPassengers(final Entity entity) {
return entity.getPassengers();
}
}

View File

@ -50,6 +50,8 @@ import fr.neatmonster.nocheatplus.checks.combined.Combined;
import fr.neatmonster.nocheatplus.checks.combined.Improbable;
import fr.neatmonster.nocheatplus.compat.Bridge1_9;
import fr.neatmonster.nocheatplus.compat.BridgeHealth;
import fr.neatmonster.nocheatplus.components.entity.IEntityAccessVehicle;
import fr.neatmonster.nocheatplus.components.registry.event.IGenericInstanceHandle;
import fr.neatmonster.nocheatplus.components.registry.feature.JoinLeaveListener;
import fr.neatmonster.nocheatplus.stats.Counters;
import fr.neatmonster.nocheatplus.utilities.InventoryUtil;
@ -85,6 +87,8 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen
private final int idIllegalItem = counters.registerKey("illegalitem");
private final int idEggOnEntity = counters.registerKey("eggonentity");
private final IGenericInstanceHandle<IEntityAccessVehicle> handleVehicles = NCPAPIProvider.getNoCheatPlusAPI().getGenericInstanceHandle(IEntityAccessVehicle.class);
public InventoryListener() {
super(CheckType.INVENTORY);
}
@ -414,10 +418,18 @@ public class InventoryListener extends CheckListener implements JoinLeaveListen
@EventHandler(priority = EventPriority.MONITOR)
public void onEntityPortal(final EntityPortalEnterEvent event) {
final Player player = InventoryUtil.getPlayerPassengerRecursively(event.getEntity());
if (player != null) {
// Note: ignore cancelother setting.
open.check(player);
// Check passengers flat for now.
final Entity entity = event.getEntity();
if (entity instanceof Player) {
open.check((Player) entity);
}
else {
for (final Entity passenger : handleVehicles.getHandle().getEntityPassengers(entity)) {
if (passenger instanceof Player) {
// Note: ignore cancelother setting.
open.check((Player) passenger);
}
}
}
}

View File

@ -0,0 +1,24 @@
package fr.neatmonster.nocheatplus.compat.bukkit;
import java.util.Arrays;
import java.util.List;
import org.bukkit.entity.Entity;
import fr.neatmonster.nocheatplus.components.entity.IEntityAccessVehicle;
/**
* Legacy access to vehicle entities (single passenger only).
*
* @author asofold
*
*/
public class EntityAccessVehicleLegacy implements IEntityAccessVehicle {
@SuppressWarnings("deprecation")
@Override
public List<Entity> getEntityPassengers(final Entity entity) {
return Arrays.asList(entity.getPassenger());
}
}

View File

@ -0,0 +1,23 @@
package fr.neatmonster.nocheatplus.components.entity;
import java.util.List;
import org.bukkit.entity.Entity;
/**
* Vehicle specific access to entities.
*
* @author asofold
*
*/
public interface IEntityAccessVehicle {
/**
* Get the current passengers for a vehicle (entity).
*
* @param entity
* @return
*/
public List<Entity> getEntityPassengers(Entity entity);
}

View File

@ -15,7 +15,6 @@
package fr.neatmonster.nocheatplus.utilities;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
@ -32,26 +31,26 @@ import fr.neatmonster.nocheatplus.utilities.map.BlockProperties;
*
*/
public class InventoryUtil {
/**
/**
* Does not account for special slots like armor.
*
* @param inventory
* the inventory
* @return the free slots
*/
public static int getFreeSlots(final Inventory inventory) {
final ItemStack[] contents = inventory.getContents();
int count = 0;
for (int i = 0; i < contents.length; i++) {
if (BlockProperties.isAir(contents[i])) {
count ++;
}
}
return count;
}
public static int getFreeSlots(final Inventory inventory) {
final ItemStack[] contents = inventory.getContents();
int count = 0;
for (int i = 0; i < contents.length; i++) {
if (BlockProperties.isAir(contents[i])) {
count ++;
}
}
return count;
}
/**
/**
* Count slots with type-id and data (enchantments and other meta data are
* ignored at present).
*
@ -61,26 +60,26 @@ public class InventoryUtil {
* the reference
* @return the stack count
*/
public static int getStackCount(final Inventory inventory, final ItemStack reference) {
if (inventory == null) return 0;
if (reference == null) return getFreeSlots(inventory);
final Material mat = reference.getType();
final int durability = reference.getDurability();
final ItemStack[] contents = inventory.getContents();
int count = 0;
for (int i = 0; i < contents.length; i++) {
final ItemStack stack = contents[i];
if (stack == null) {
continue;
}
else if (stack.getType() == mat && stack.getDurability() == durability) {
count ++;
}
}
return count;
}
public static int getStackCount(final Inventory inventory, final ItemStack reference) {
if (inventory == null) return 0;
if (reference == null) return getFreeSlots(inventory);
final Material mat = reference.getType();
final int durability = reference.getDurability();
final ItemStack[] contents = inventory.getContents();
int count = 0;
for (int i = 0; i < contents.length; i++) {
final ItemStack stack = contents[i];
if (stack == null) {
continue;
}
else if (stack.getType() == mat && stack.getDurability() == durability) {
count ++;
}
}
return count;
}
/**
/**
* Sum of bottom + top inventory slots with item type / data, see:
* getStackCount(Inventory, reference).
*
@ -90,55 +89,29 @@ public class InventoryUtil {
* the reference
* @return the stack count
*/
public static int getStackCount(final InventoryView view, final ItemStack reference) {
return getStackCount(view.getBottomInventory(), reference) + getStackCount(view.getTopInventory(), reference);
}
/**
* Search for players / passengers (broken by name: closes the inventory of
* first player found including entity and passengers recursively).
*
* @param entity
* the entity
* @return true, if successful
*/
public static boolean closePlayerInventoryRecursively(Entity entity) {
// Find a player.
final Player player = getPlayerPassengerRecursively(entity);
if (player != null && closeOpenInventory((Player) entity)) {
return true;
} else {
return false;
}
}
/**
* Get a player from an entity. This will return the first player found
* amongst the entity itself and passengers checked recursively.
*
* @param entity
* the entity
* @return the player passenger recursively
*/
public static Player getPlayerPassengerRecursively(Entity entity) {
while (entity != null) {
if (entity instanceof Player) {
// Scrap the case of players riding players for the moment.
return (Player) entity;
}
final Entity passenger = entity.getPassenger();
if (entity.equals(passenger)) {
// Just in case :9.
break;
}
else {
entity = passenger;
}
}
return null;
}
public static int getStackCount(final InventoryView view, final ItemStack reference) {
return getStackCount(view.getBottomInventory(), reference) + getStackCount(view.getTopInventory(), reference);
}
/**
// /**
// * Search for players / passengers (broken by name: closes the inventory of
// * first player found including entity and passengers recursively).
// *
// * @param entity
// * the entity
// * @return true, if successful
// */
// public static boolean closePlayerInventoryRecursively(Entity entity) {
// // Find a player.
// final Player player = PassengerUtil.getFirstPlayerIncludingPassengersRecursively(entity);
// if (player != null && closeOpenInventory((Player) entity)) {
// return true;
// } else {
// return false;
// }
// }
/**
* Close one players inventory, if open. This might ignore
* InventoryType.CRAFTING (see: hasInventoryOpen).
*
@ -146,16 +119,16 @@ public class InventoryUtil {
* the player
* @return If closed.
*/
public static boolean closeOpenInventory(final Player player) {
if (hasInventoryOpen(player)) {
player.closeInventory();
return true;
} else {
return true;
}
}
/**
public static boolean closeOpenInventory(final Player player) {
if (hasInventoryOpen(player)) {
player.closeInventory();
return true;
} else {
return true;
}
}
/**
* Check if the players inventory is open. This might ignore
* InventoryType.CRAFTING.
*
@ -163,10 +136,10 @@ public class InventoryUtil {
* the player
* @return true, if successful
*/
public static boolean hasInventoryOpen(final Player player) {
final InventoryView view = player.getOpenInventory();
return view != null && view.getType() != InventoryType.CRAFTING;
}
public static boolean hasInventoryOpen(final Player player) {
final InventoryView view = player.getOpenInventory();
return view != null && view.getType() != InventoryType.CRAFTING;
}
/**
* Return the first consumable item found, checking main hand first and then

View File

@ -58,6 +58,7 @@ public class TeleportUtil {
// TODO: Account for nested passengers and inconsistencies.
final MovingData data = MovingData.getData(player);
data.isVehicleSetBack = true;
// TODO: Adjust to multiple passengers.
final Entity passenger = vehicle.getPassenger();
boolean vehicleTeleported = false;
final boolean playerIsPassenger = player.equals(passenger);

View File

@ -84,4 +84,30 @@ public class PassengerUtil {
return vehicle;
}
// /**
// * Get a player from an entity. This will return the first player found
// * amongst the entity itself and passengers checked recursively.
// *
// * @param entity
// * the entity
// * @return the player passenger recursively
// */
// public static Player getFirstPlayerIncludingPassengersRecursively(Entity entity) {
// while (entity != null) {
// if (entity instanceof Player) {
// // Scrap the case of players riding players for the moment.
// return (Player) entity;
// }
// final Entity passenger = entity.getPassenger();
// if (entity.equals(passenger)) {
// // Just in case :9.
// break;
// }
// else {
// entity = passenger;
// }
// }
// return null;
// }
}

View File

@ -16,6 +16,7 @@ package fr.neatmonster.nocheatplus.compat.registry;
import fr.neatmonster.nocheatplus.compat.MCAccess;
import fr.neatmonster.nocheatplus.components.entity.IEntityAccessLastPositionAndLook;
import fr.neatmonster.nocheatplus.components.entity.IEntityAccessVehicle;
/**
* Set up more fine grained entity access providers, registered as generic
@ -39,6 +40,8 @@ public class EntityAccessFactory {
* @param config
*/
public void setupEntityAccess(final MCAccess mcAccess, final MCAccessConfig config) {
// IEntityAccessLastPositionAndLook
RegistryHelper.setupGenericInstance(new String[] {
"fr.neatmonster.nocheatplus.compat.cbdev.EntityAccessLastPositionAndLook",
"fr.neatmonster.nocheatplus.compat.spigotcb1_10_R1.EntityAccessLastPositionAndLook",
@ -47,6 +50,12 @@ public class EntityAccessFactory {
}, new String[] {
"fr.neatmonster.nocheatplus.compat.cbreflect.reflect.ReflectEntityLastPositionAndLook",
}, IEntityAccessLastPositionAndLook.class, config, false);
// IEntityAccessVehicle
RegistryHelper.registerFirstAvailable(new String[] {
"fr.neatmonster.nocheatplus.compat.bukkit.EntityAccessVehicleMultiPassenger",
"fr.neatmonster.nocheatplus.compat.bukkit.EntityAccessVehicleLegacy",
}, IEntityAccessVehicle.class, false);
}
}

View File

@ -162,4 +162,17 @@ public class RegistryHelper {
return result;
}
/**
* Auxiliary method to register the first available class, using the default
* constructor, logging registration state (and debug if desired).
*
* @param classNames
* @param registerFor
* @param logDebug
* @return
*/
public static <T> T registerFirstAvailable(String[] classNames, Class<T> registerFor, boolean logDebug) {
return registerGenericInstance(registerFor, getFirstAvailable(classNames, registerFor, logDebug));
}
}