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 BooleanProperty("baby", babyIndex, false, legacyBooleans));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
register(new EntitySittingProperty(packetFactory, this));
|
||||||
|
|
||||||
// Player
|
// Player
|
||||||
register(new DummyProperty<>("skin", SkinDescriptor.class, false));
|
register(new DummyProperty<>("skin", SkinDescriptor.class, false));
|
||||||
final int skinLayersIndex;
|
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.manager.server.ServerVersion;
|
||||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
|
import com.github.retrooper.packetevents.protocol.entity.type.EntityType;
|
||||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
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.EntityProperty;
|
||||||
import lol.pyr.znpcsplus.api.entity.PropertyHolder;
|
import lol.pyr.znpcsplus.api.entity.PropertyHolder;
|
||||||
import lol.pyr.znpcsplus.packets.PacketFactory;
|
import lol.pyr.znpcsplus.packets.PacketFactory;
|
||||||
|
@ -13,6 +14,7 @@ import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@ -26,6 +28,8 @@ public class PacketEntity implements PropertyHolder {
|
||||||
private final EntityType type;
|
private final EntityType type;
|
||||||
private NpcLocation location;
|
private NpcLocation location;
|
||||||
|
|
||||||
|
private final HashMap<String, Object> metadata = new HashMap<>();
|
||||||
|
|
||||||
public PacketEntity(PacketFactory packetFactory, PropertyHolder properties, EntityType type, NpcLocation location) {
|
public PacketEntity(PacketFactory packetFactory, PropertyHolder properties, EntityType type, NpcLocation location) {
|
||||||
this.packetFactory = packetFactory;
|
this.packetFactory = packetFactory;
|
||||||
this.properties = properties;
|
this.properties = properties;
|
||||||
|
@ -67,6 +71,15 @@ public class PacketEntity implements PropertyHolder {
|
||||||
|
|
||||||
public void despawn(Player player) {
|
public void despawn(Player player) {
|
||||||
packetFactory.destroyEntity(player, this, properties);
|
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) {
|
public void refreshMeta(Player player) {
|
||||||
|
@ -116,4 +129,32 @@ public class PacketEntity implements PropertyHolder {
|
||||||
public Set<EntityProperty<?>> getAppliedProperties() {
|
public Set<EntityProperty<?>> getAppliedProperties() {
|
||||||
return properties.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) {
|
public void setLocation(NpcLocation location) {
|
||||||
this.location = location;
|
this.location = location;
|
||||||
entity.setLocation(location, getViewers());
|
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()));
|
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",
|
"potion_color", "potion_ambient", "display_name", "permission_required",
|
||||||
"player_knockback", "player_knockback_exempt_permission", "player_knockback_distance", "player_knockback_vertical",
|
"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_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");
|
if (!type.equals(EntityTypes.PLAYER)) addProperties("dinnerbone");
|
||||||
// TODO: make this look nicer after completing the rest of the properties
|
// TODO: make this look nicer after completing the rest of the properties
|
||||||
if (version.isNewerThanOrEquals(ServerVersion.V_1_9)) addProperties("glow");
|
if (version.isNewerThanOrEquals(ServerVersion.V_1_9)) addProperties("glow");
|
||||||
|
|
Loading…
Reference in a new issue