Added entity_sitting property to allow player and some other entities to sit
This commit is contained in:
parent
8b1fde3652
commit
a7bf542eb3
6 changed files with 173 additions and 1 deletions
|
@ -0,0 +1,72 @@
|
|||
package lol.pyr.znpcsplus.entity;
|
||||
|
||||
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
|
||||
import lol.pyr.znpcsplus.api.entity.EntityProperty;
|
||||
import lol.pyr.znpcsplus.api.entity.PropertyHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Represents an armor stand vehicle entity.
|
||||
* <p>
|
||||
* This entity is used to make the NPC sit on an invisible armor stand.
|
||||
* </p>
|
||||
*/
|
||||
public class ArmorStandVehicleEntity implements PropertyHolder {
|
||||
|
||||
private final Map<EntityPropertyImpl<?>, Object> propertyMap = new HashMap<>();
|
||||
|
||||
public ArmorStandVehicleEntity(EntityPropertyRegistryImpl propertyRegistry) {
|
||||
setProperty(propertyRegistry.getByName("small", Boolean.class), true);
|
||||
setProperty(propertyRegistry.getByName("invisible", Boolean.class), true);
|
||||
setProperty(propertyRegistry.getByName("base_plate", Boolean.class), false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getProperty(EntityProperty<T> key) {
|
||||
return hasProperty(key) ? (T) propertyMap.get((EntityPropertyImpl<?>) key) : key.getDefaultValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasProperty(EntityProperty<?> key) {
|
||||
return propertyMap.containsKey((EntityPropertyImpl<?>) key);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> void setProperty(EntityProperty<T> key, T value) {
|
||||
Object val = value;
|
||||
if (val instanceof ItemStack) val = SpigotConversionUtil.fromBukkitItemStack((ItemStack) val);
|
||||
|
||||
setProperty((EntityPropertyImpl<T>) key, (T) val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItemProperty(EntityProperty<?> key, ItemStack value) {
|
||||
throw new UnsupportedOperationException("Cannot set item properties on armor stands");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemProperty(EntityProperty<?> key) {
|
||||
throw new UnsupportedOperationException("Cannot get item properties on armor stands");
|
||||
}
|
||||
|
||||
public <T> void setProperty(EntityPropertyImpl<T> key, T value) {
|
||||
if (key == null) return;
|
||||
if (value == null || value.equals(key.getDefaultValue())) propertyMap.remove(key);
|
||||
else propertyMap.put(key, value);
|
||||
}
|
||||
|
||||
public Set<EntityProperty<?>> getAllProperties() {
|
||||
return Collections.unmodifiableSet(propertyMap.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<EntityProperty<?>> getAppliedProperties() {
|
||||
return Collections.unmodifiableSet(propertyMap.keySet());
|
||||
}
|
||||
}
|
|
@ -182,6 +182,8 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
register(new BooleanProperty("baby", babyIndex, false, legacyBooleans));
|
||||
}
|
||||
|
||||
register(new EntitySittingProperty(packetFactory, this));
|
||||
|
||||
// Player
|
||||
register(new DummyProperty<>("skin", SkinDescriptor.class, false));
|
||||
final int skinLayersIndex;
|
||||
|
|
|
@ -4,6 +4,7 @@ import com.github.retrooper.packetevents.PacketEvents;
|
|||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||
import lol.pyr.znpcsplus.ZNpcsPlusBootstrap;
|
||||
import lol.pyr.znpcsplus.api.entity.EntityProperty;
|
||||
import lol.pyr.znpcsplus.api.entity.PropertyHolder;
|
||||
import lol.pyr.znpcsplus.packets.PacketFactory;
|
||||
|
@ -13,6 +14,7 @@ import org.bukkit.entity.Player;
|
|||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -26,6 +28,8 @@ public class PacketEntity implements PropertyHolder {
|
|||
private final EntityType type;
|
||||
private NpcLocation location;
|
||||
|
||||
private final HashMap<String, Object> metadata = new HashMap<>();
|
||||
|
||||
public PacketEntity(PacketFactory packetFactory, PropertyHolder properties, EntityType type, NpcLocation location) {
|
||||
this.packetFactory = packetFactory;
|
||||
this.properties = properties;
|
||||
|
@ -67,6 +71,15 @@ public class PacketEntity implements PropertyHolder {
|
|||
|
||||
public void despawn(Player player) {
|
||||
packetFactory.destroyEntity(player, this, properties);
|
||||
if (hasMetadata("ridingVehicle")) {
|
||||
try {
|
||||
PacketEntity armorStand = (PacketEntity) getMetadata("ridingVehicle");
|
||||
armorStand.despawn(player);
|
||||
} catch (Exception e) {
|
||||
//noinspection CallToPrintStackTrace
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshMeta(Player player) {
|
||||
|
@ -116,4 +129,32 @@ public class PacketEntity implements PropertyHolder {
|
|||
public Set<EntityProperty<?>> getAppliedProperties() {
|
||||
return properties.getAppliedProperties();
|
||||
}
|
||||
|
||||
public void setMetadata(String key, Object value) {
|
||||
metadata.put(key, value);
|
||||
}
|
||||
|
||||
public Object getMetadata(String key) {
|
||||
return metadata.get(key);
|
||||
}
|
||||
|
||||
public <T> T getMetadata(String key, Class<T> type) {
|
||||
try {
|
||||
return type.cast(metadata.get(key));
|
||||
} catch (ClassCastException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeMetadata(String key) {
|
||||
metadata.remove(key);
|
||||
}
|
||||
|
||||
public boolean hasMetadata(String key) {
|
||||
return metadata.containsKey(key);
|
||||
}
|
||||
|
||||
public void clearMetadata() {
|
||||
metadata.clear();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package lol.pyr.znpcsplus.entity.properties;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSetPassengers;
|
||||
import lol.pyr.znpcsplus.entity.ArmorStandVehicleEntity;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
|
||||
import lol.pyr.znpcsplus.entity.PacketEntity;
|
||||
import lol.pyr.znpcsplus.packets.PacketFactory;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class EntitySittingProperty extends EntityPropertyImpl<Boolean> {
|
||||
private final PacketFactory packetFactory;
|
||||
private final EntityPropertyRegistryImpl propertyRegistry;
|
||||
|
||||
public EntitySittingProperty(PacketFactory packetFactory, EntityPropertyRegistryImpl propertyRegistry) {
|
||||
super("entity_sitting", false, Boolean.class);
|
||||
this.packetFactory = packetFactory;
|
||||
this.propertyRegistry = propertyRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
|
||||
boolean sitting = entity.getProperty(this);
|
||||
if (sitting) {
|
||||
ArmorStandVehicleEntity vehicleEntity = new ArmorStandVehicleEntity(propertyRegistry);
|
||||
PacketEntity vehiclePacketEntity = new PacketEntity(packetFactory, vehicleEntity, EntityTypes.ARMOR_STAND, entity.getLocation().withY(entity.getLocation().getY() - 0.9));
|
||||
vehiclePacketEntity.spawn(player);
|
||||
entity.setMetadata("ridingVehicle", vehiclePacketEntity);
|
||||
PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerSetPassengers(
|
||||
vehiclePacketEntity.getEntityId(),
|
||||
new int[]{entity.getEntityId()}
|
||||
));
|
||||
} else {
|
||||
if (entity.hasMetadata("ridingVehicle")) {
|
||||
PacketEntity vehicleEntity = (PacketEntity) entity.getMetadata("ridingVehicle");
|
||||
PacketEvents.getAPI().getPlayerManager().sendPacket(player, new WrapperPlayServerSetPassengers(
|
||||
vehicleEntity.getEntityId(),
|
||||
new int[]{}
|
||||
));
|
||||
vehicleEntity.despawn(player);
|
||||
entity.removeMetadata("ridingVehicle");
|
||||
// Send a packet to reset the npc's position
|
||||
packetFactory.teleportEntity(player, entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -86,6 +86,10 @@ public class NpcImpl extends Viewable implements Npc {
|
|||
public void setLocation(NpcLocation location) {
|
||||
this.location = location;
|
||||
entity.setLocation(location, getViewers());
|
||||
if (entity.hasMetadata("ridingVehicle")) {
|
||||
PacketEntity armorStand = (PacketEntity) entity.getMetadata("ridingVehicle");
|
||||
armorStand.setLocation(location.withY(location.getY() - 0.9), getViewers());
|
||||
}
|
||||
hologram.setLocation(location.withY(location.getY() + type.getHologramOffset()));
|
||||
}
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ public class NpcTypeImpl implements NpcType {
|
|||
"potion_color", "potion_ambient", "display_name", "permission_required",
|
||||
"player_knockback", "player_knockback_exempt_permission", "player_knockback_distance", "player_knockback_vertical",
|
||||
"player_knockback_horizontal", "player_knockback_cooldown", "player_knockback_sound", "player_knockback_sound_name",
|
||||
"player_knockback_sound_volume", "player_knockback_sound_pitch");
|
||||
"player_knockback_sound_volume", "player_knockback_sound_pitch", "entity_sitting");
|
||||
if (!type.equals(EntityTypes.PLAYER)) addProperties("dinnerbone");
|
||||
// TODO: make this look nicer after completing the rest of the properties
|
||||
if (version.isNewerThanOrEquals(ServerVersion.V_1_9)) addProperties("glow");
|
||||
|
|
Loading…
Reference in a new issue