Compare commits
8 commits
82f30b8f07
...
2813a92062
Author | SHA1 | Date | |
---|---|---|---|
|
2813a92062 | ||
|
64d6fc900b | ||
|
7607541583 | ||
|
cc73738ac1 | ||
|
0dd8284f31 | ||
|
bde20e57ef | ||
|
cb96dd90cd | ||
|
a56459b69e |
13 changed files with 378 additions and 30 deletions
|
@ -1,29 +1,40 @@
|
|||
package lol.pyr.znpcsplus.util;
|
||||
|
||||
public enum VillagerProfession {
|
||||
NONE(0),
|
||||
ARMORER(1),
|
||||
BUTCHER(2),
|
||||
CARTOGRAPHER(3),
|
||||
CLERIC(4),
|
||||
FARMER(5),
|
||||
FISHERMAN(6),
|
||||
FLETCHER(7),
|
||||
LEATHER_WORKER(8),
|
||||
LIBRARIAN(9),
|
||||
NONE(0, 0),
|
||||
ARMORER(1, 3),
|
||||
BUTCHER(2, 4),
|
||||
CARTOGRAPHER(3, 1),
|
||||
CLERIC(4, 2),
|
||||
FARMER(5, 0),
|
||||
FISHERMAN(6, 0),
|
||||
FLETCHER(7, 0),
|
||||
LEATHER_WORKER(8, 4),
|
||||
LIBRARIAN(9, 1),
|
||||
MASON(10),
|
||||
NITWIT(11),
|
||||
SHEPHERD(12),
|
||||
TOOL_SMITH(13),
|
||||
WEAPON_SMITH(14);
|
||||
NITWIT(11, 5),
|
||||
SHEPHERD(12, 0),
|
||||
TOOL_SMITH(13, 3),
|
||||
WEAPON_SMITH(14, 3);
|
||||
|
||||
private final int id;
|
||||
private final int legacyId;
|
||||
|
||||
VillagerProfession(int id) {
|
||||
this.id = id;
|
||||
this.legacyId = 0;
|
||||
}
|
||||
|
||||
VillagerProfession(int id, int legacyId) {
|
||||
this.id = id;
|
||||
this.legacyId = legacyId;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public int getLegacyId() {
|
||||
return legacyId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,7 +138,7 @@ public class ZNpcsPlus {
|
|||
|
||||
typeRegistry.registerDefault(packetEvents, propertyRegistry);
|
||||
actionRegistry.registerTypes(scheduler, adventure, textSerializer, bungeeConnector);
|
||||
packetEvents.getEventManager().registerListener(new InteractionPacketListener(userManager, npcRegistry, scheduler), PacketListenerPriority.MONITOR);
|
||||
packetEvents.getEventManager().registerListener(new InteractionPacketListener(userManager, npcRegistry, typeRegistry, scheduler), PacketListenerPriority.MONITOR);
|
||||
new Metrics(bootstrap, 18244);
|
||||
pluginManager.registerEvents(new UserListener(userManager), bootstrap);
|
||||
|
||||
|
@ -152,7 +152,7 @@ public class ZNpcsPlus {
|
|||
pluginManager.registerEvents(new UpdateNotificationListener(this, adventure, updateChecker, scheduler), bootstrap);
|
||||
}
|
||||
|
||||
scheduler.runDelayedTimerAsync(new NpcProcessorTask(npcRegistry, propertyRegistry), 60L, 3L);
|
||||
scheduler.runDelayedTimerAsync(new NpcProcessorTask(npcRegistry, propertyRegistry, userManager), 60L, 3L);
|
||||
scheduler.runDelayedTimerAsync(new HologramRefreshTask(npcRegistry), 60L, 20L);
|
||||
scheduler.runDelayedTimerAsync(new SkinCacheCleanTask(skinCache), 1200, 1200);
|
||||
pluginManager.registerEvents(new ViewableHideOnLeaveListener(), bootstrap);
|
||||
|
@ -275,6 +275,7 @@ public class ZNpcsPlus {
|
|||
registerEnumParser(manager, SnifferState.class, incorrectUsageMessage);
|
||||
registerEnumParser(manager, RabbitType.class, incorrectUsageMessage);
|
||||
registerEnumParser(manager, AttachDirection.class, incorrectUsageMessage);
|
||||
registerEnumParser(manager, Sound.class, incorrectUsageMessage);
|
||||
|
||||
manager.registerCommand("npc", new MultiCommand(bootstrap.loadHelpMessage("root"))
|
||||
.addSubcommand("center", new CenterCommand(npcRegistry))
|
||||
|
|
|
@ -2,6 +2,7 @@ package lol.pyr.znpcsplus.conversion;
|
|||
|
||||
import lol.pyr.znpcsplus.config.ConfigManager;
|
||||
import lol.pyr.znpcsplus.conversion.citizens.CitizensImporter;
|
||||
import lol.pyr.znpcsplus.conversion.fancynpcs.FancyNpcsImporter;
|
||||
import lol.pyr.znpcsplus.conversion.znpcs.ZNpcImporter;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||
|
@ -34,6 +35,8 @@ public class DataImporterRegistry {
|
|||
packetFactory, textSerializer, typeRegistry, propertyRegistry, skinCache, new File(pluginsFolder, "ZNPCsPlusLegacy/data.json"), bungeeConnector)));
|
||||
register("citizens", LazyLoader.of(() -> new CitizensImporter(configManager, adventure, taskScheduler,
|
||||
packetFactory, textSerializer, typeRegistry, propertyRegistry, skinCache, new File(pluginsFolder, "Citizens/saves.yml"), npcRegistry)));
|
||||
register("fancynpcs", LazyLoader.of(() -> new FancyNpcsImporter(configManager, adventure, taskScheduler,
|
||||
packetFactory, textSerializer, typeRegistry, propertyRegistry, skinCache, new File(pluginsFolder, "FancyNpcs/npcs.yml"), npcRegistry)));
|
||||
}
|
||||
|
||||
private void register(String id, LazyLoader<DataImporter> loader) {
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
package lol.pyr.znpcsplus.conversion.fancynpcs;
|
||||
|
||||
import io.github.retrooper.packetevents.util.SpigotConversionUtil;
|
||||
import lol.pyr.znpcsplus.api.interaction.InteractionType;
|
||||
import lol.pyr.znpcsplus.api.skin.SkinDescriptor;
|
||||
import lol.pyr.znpcsplus.config.ConfigManager;
|
||||
import lol.pyr.znpcsplus.conversion.DataImporter;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
|
||||
import lol.pyr.znpcsplus.interaction.consolecommand.ConsoleCommandAction;
|
||||
import lol.pyr.znpcsplus.interaction.message.MessageAction;
|
||||
import lol.pyr.znpcsplus.interaction.playercommand.PlayerCommandAction;
|
||||
import lol.pyr.znpcsplus.npc.*;
|
||||
import lol.pyr.znpcsplus.packets.PacketFactory;
|
||||
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
|
||||
import lol.pyr.znpcsplus.skin.SkinImpl;
|
||||
import lol.pyr.znpcsplus.skin.cache.MojangSkinCache;
|
||||
import lol.pyr.znpcsplus.skin.descriptor.MirrorDescriptor;
|
||||
import lol.pyr.znpcsplus.skin.descriptor.PrefetchedDescriptor;
|
||||
import lol.pyr.znpcsplus.util.LookType;
|
||||
import lol.pyr.znpcsplus.util.NamedColor;
|
||||
import lol.pyr.znpcsplus.util.NpcLocation;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
public class FancyNpcsImporter implements DataImporter {
|
||||
private final ConfigManager configManager;
|
||||
private final BukkitAudiences adventure;
|
||||
private final TaskScheduler scheduler;
|
||||
private final PacketFactory packetFactory;
|
||||
private final LegacyComponentSerializer textSerializer;
|
||||
private final NpcTypeRegistryImpl typeRegistry;
|
||||
private final EntityPropertyRegistryImpl propertyRegistry;
|
||||
private final MojangSkinCache skinCache;
|
||||
private final File dataFile;
|
||||
private final NpcRegistryImpl npcRegistry;
|
||||
|
||||
public FancyNpcsImporter(ConfigManager configManager, BukkitAudiences adventure,
|
||||
TaskScheduler taskScheduler, PacketFactory packetFactory, LegacyComponentSerializer textSerializer,
|
||||
NpcTypeRegistryImpl typeRegistry, EntityPropertyRegistryImpl propertyRegistry, MojangSkinCache skinCache,
|
||||
File dataFile, NpcRegistryImpl npcRegistry) {
|
||||
this.configManager = configManager;
|
||||
this.adventure = adventure;
|
||||
this.scheduler = taskScheduler;
|
||||
this.packetFactory = packetFactory;
|
||||
this.textSerializer = textSerializer;
|
||||
this.typeRegistry = typeRegistry;
|
||||
this.propertyRegistry = propertyRegistry;
|
||||
this.skinCache = skinCache;
|
||||
this.dataFile = dataFile;
|
||||
this.npcRegistry = npcRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<NpcEntryImpl> importData() {
|
||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(dataFile);
|
||||
ConfigurationSection npcsSection = config.getConfigurationSection("npcs");
|
||||
if (npcsSection == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
ArrayList<NpcEntryImpl> entries = new ArrayList<>();
|
||||
npcsSection.getKeys(false).forEach(key -> {
|
||||
ConfigurationSection npcSection = npcsSection.getConfigurationSection(key);
|
||||
if (npcSection == null) {
|
||||
return;
|
||||
}
|
||||
String name = npcSection.getString("name", "FancyNPC");
|
||||
UUID uuid = UUID.fromString(key);
|
||||
String world = npcSection.getString("location.world");
|
||||
if (world == null) {
|
||||
world = Bukkit.getWorlds().get(0).getName();
|
||||
}
|
||||
NpcLocation location = new NpcLocation(
|
||||
npcSection.getDouble("location.x"),
|
||||
npcSection.getDouble("location.y"),
|
||||
npcSection.getDouble("location.z"),
|
||||
(float) npcSection.getDouble("location.yaw"),
|
||||
(float) npcSection.getDouble("location.pitch")
|
||||
);
|
||||
String typeString = npcSection.getString("type");
|
||||
NpcTypeImpl type = typeRegistry.getByName(typeString);
|
||||
if (type == null) {
|
||||
type = typeRegistry.getByName("player");
|
||||
}
|
||||
NpcImpl npc = new NpcImpl(uuid, propertyRegistry, configManager, packetFactory, textSerializer, world, type, location);
|
||||
npc.getType().applyDefaultProperties(npc);
|
||||
|
||||
npc.getHologram().addTextLineComponent(textSerializer.deserialize(name));
|
||||
boolean glowing = npcSection.getBoolean("glowing", false);
|
||||
if (glowing) {
|
||||
NamedColor color;
|
||||
try {
|
||||
color = NamedColor.valueOf(npcSection.getString("glowingColor", "white"));
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
color = NamedColor.WHITE;
|
||||
}
|
||||
EntityPropertyImpl<NamedColor> property = propertyRegistry.getByName("glow", NamedColor.class);
|
||||
npc.setProperty(property, color);
|
||||
}
|
||||
if (npcSection.getBoolean("turnToPlayer", false)) {
|
||||
EntityPropertyImpl<LookType> property = propertyRegistry.getByName("look", LookType.class);
|
||||
npc.setProperty(property, LookType.CLOSEST_PLAYER);
|
||||
}
|
||||
if (npcSection.isConfigurationSection("skin")) {
|
||||
ConfigurationSection skinSection = npcSection.getConfigurationSection("skin");
|
||||
String texture = skinSection.getString("value");
|
||||
String signature = skinSection.getString("signature");
|
||||
npc.setProperty(propertyRegistry.getByName("skin", SkinDescriptor.class), new PrefetchedDescriptor(new SkinImpl(texture, signature)));
|
||||
}
|
||||
if (npcSection.isConfigurationSection("equipment")) {
|
||||
ConfigurationSection equipmentSection = npcSection.getConfigurationSection("equipment");
|
||||
for (String slot : equipmentSection.getKeys(false)) {
|
||||
ItemStack item = equipmentSection.getItemStack(slot);
|
||||
if (item != null) {
|
||||
npc.setProperty(propertyRegistry.getByName(getEquipmentPropertyName(slot),
|
||||
com.github.retrooper.packetevents.protocol.item.ItemStack.class), SpigotConversionUtil.fromBukkitItemStack(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (npcSection.getBoolean("mirrorSkin")) {
|
||||
npc.setProperty(propertyRegistry.getByName("skin", SkinDescriptor.class), new MirrorDescriptor(skinCache));
|
||||
}
|
||||
List<String> playerCommands = npcSection.getStringList("playerCommands");
|
||||
if (!playerCommands.isEmpty()) {
|
||||
long cooldown = npcSection.getLong("interactionCooldown", 0);
|
||||
for (String command : playerCommands) {
|
||||
npc.addAction(new PlayerCommandAction(scheduler, command, InteractionType.ANY_CLICK, cooldown, 0));
|
||||
}
|
||||
}
|
||||
String serverCommand = npcSection.getString("serverCommand");
|
||||
if (serverCommand != null) {
|
||||
long cooldown = npcSection.getLong("interactionCooldown", 0);
|
||||
npc.addAction(new ConsoleCommandAction(scheduler, serverCommand, InteractionType.ANY_CLICK, cooldown, 0));
|
||||
}
|
||||
List<String> messages = npcSection.getStringList("messages");
|
||||
if (!messages.isEmpty()) {
|
||||
long cooldown = npcSection.getLong("interactionCooldown", 0);
|
||||
for (String message : messages) {
|
||||
npc.addAction(new MessageAction(adventure, message, InteractionType.ANY_CLICK, textSerializer, cooldown, 0));
|
||||
}
|
||||
}
|
||||
String id = npcSection.getString("name");
|
||||
while (npcRegistry.getById(id) != null) {
|
||||
id += "_";
|
||||
}
|
||||
NpcEntryImpl entry = new NpcEntryImpl(id, npc);
|
||||
entry.enableEverything();
|
||||
entries.add(entry);
|
||||
});
|
||||
return entries;
|
||||
}
|
||||
|
||||
private String getEquipmentPropertyName(String slot) {
|
||||
switch (slot) {
|
||||
case "MAINHAND":
|
||||
return "hand";
|
||||
case "OFFHAND":
|
||||
return "offhand";
|
||||
case "FEET":
|
||||
return "boots";
|
||||
case "LEGS":
|
||||
return "leggings";
|
||||
case "CHEST":
|
||||
return "chestplate";
|
||||
case "HEAD":
|
||||
return "helmet";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return dataFile.isFile();
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ import lol.pyr.znpcsplus.util.*;
|
|||
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||
import org.bukkit.Color;
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.Sound;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -84,6 +85,7 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
registerEnumSerializer(SnifferState.class);
|
||||
registerEnumSerializer(RabbitType.class);
|
||||
registerEnumSerializer(AttachDirection.class);
|
||||
registerEnumSerializer(Sound.class);
|
||||
|
||||
registerPrimitiveSerializers(Integer.class, Boolean.class, Double.class, Float.class, Long.class, Short.class, Byte.class, String.class);
|
||||
|
||||
|
@ -122,6 +124,20 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
|
||||
register(new DummyProperty<>("permission_required", false));
|
||||
|
||||
register(new DummyProperty<>("player_knockback", false));
|
||||
register(new DummyProperty<>("player_knockback_exempt_permission", String.class));
|
||||
register(new DummyProperty<>("player_knockback_distance", 0.4));
|
||||
register(new DummyProperty<>("player_knockback_vertical", 0.4));
|
||||
register(new DummyProperty<>("player_knockback_horizontal", 0.9));
|
||||
register(new DummyProperty<>("player_knockback_cooldown", 1500));
|
||||
register(new DummyProperty<>("player_knockback_sound", false));
|
||||
register(new DummyProperty<>("player_knockback_sound_volume", 1.0f));
|
||||
register(new DummyProperty<>("player_knockback_sound_pitch", 1.0f));
|
||||
register(new DummyProperty<>("player_knockback_sound_name", Sound.valueOf(
|
||||
PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_9) ?
|
||||
"VILLAGER_NO" : "ENTITY_VILLAGER_NO"
|
||||
)));
|
||||
|
||||
register(new GlowProperty(packetFactory));
|
||||
register(new BitsetProperty("fire", 0, 0x01));
|
||||
register(new BitsetProperty("invisible", 0, 0x20));
|
||||
|
@ -154,7 +170,11 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) babyIndex = 12;
|
||||
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) babyIndex = 11;
|
||||
else babyIndex = 12;
|
||||
register(new BooleanProperty("baby", babyIndex, false, legacyBooleans));
|
||||
if (ver.isOlderThan(ServerVersion.V_1_9)) {
|
||||
register(new EncodedByteProperty<>("baby", false, babyIndex, obj -> (byte) (obj ? -1 : 0)));
|
||||
} else {
|
||||
register(new BooleanProperty("baby", babyIndex, false, legacyBooleans));
|
||||
}
|
||||
|
||||
// Player
|
||||
register(new DummyProperty<>("skin", SkinDescriptor.class, false));
|
||||
|
@ -369,6 +389,15 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
register(new EncodedByteProperty<>("sheep_color", DyeColor.WHITE, sheepIndex, DyeColor::getWoolData));
|
||||
register(new BitsetProperty("sheep_sheared", sheepIndex, 0x10, false, legacyBooleans)); // no need to link because sheep_sheared is only visible when sheep_color is WHITE
|
||||
|
||||
// Villager
|
||||
int villagerIndex;
|
||||
if (ver.isOlderThan(ServerVersion.V_1_14)) {
|
||||
if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) villagerIndex = 13;
|
||||
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) villagerIndex = 12;
|
||||
else villagerIndex = 16;
|
||||
register(new EncodedIntegerProperty<>("villager_profession", VillagerProfession.NONE, villagerIndex, VillagerProfession::getLegacyId));
|
||||
}
|
||||
|
||||
// Wolf
|
||||
int wolfIndex;
|
||||
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) wolfIndex = 19;
|
||||
|
@ -497,12 +526,8 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
register(new CustomTypeProperty<>("pose", 6, NpcPose.STANDING, EntityDataTypes.ENTITY_POSE, npcPose -> EntityPose.valueOf(npcPose.name())));
|
||||
|
||||
// Villager
|
||||
final int villagerIndex;
|
||||
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) villagerIndex = 18;
|
||||
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_15)) villagerIndex = 17;
|
||||
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_14)) villagerIndex = 16;
|
||||
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_10)) villagerIndex = 13;
|
||||
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) villagerIndex = 12;
|
||||
else villagerIndex = 16;
|
||||
register(new VillagerTypeProperty("villager_type", villagerIndex, VillagerType.PLAINS));
|
||||
register(new VillagerProfessionProperty("villager_profession", villagerIndex, VillagerProfession.NONE));
|
||||
|
@ -612,7 +637,9 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
|||
if (!ver.isNewerThanOrEquals(ServerVersion.V_1_20)) return;
|
||||
|
||||
// Camel
|
||||
register(new BooleanProperty("bashing", 18, false, legacyBooleans));
|
||||
int camelIndex = 18;
|
||||
register(new BooleanProperty("bashing", camelIndex++, false, legacyBooleans));
|
||||
register(new CamelSittingProperty(6, camelIndex));
|
||||
|
||||
// Sniffer
|
||||
register(new CustomTypeProperty<>("sniffer_state", 17, SnifferState.IDLING, EntityDataTypes.SNIFFER_STATE, state -> com.github.retrooper.packetevents.protocol.entity.sniffer.SnifferState.valueOf(state.name())));
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package lol.pyr.znpcsplus.entity.properties;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityData;
|
||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
|
||||
import com.github.retrooper.packetevents.protocol.entity.pose.EntityPose;
|
||||
import lol.pyr.znpcsplus.entity.EntityPropertyImpl;
|
||||
import lol.pyr.znpcsplus.entity.PacketEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class CamelSittingProperty extends EntityPropertyImpl<Boolean> {
|
||||
private final int poseIndex;
|
||||
private final int lastPoseTickIndex;
|
||||
|
||||
public CamelSittingProperty(int poseIndex, int lastPoseTickIndex) {
|
||||
super("camel_sitting", false, Boolean.class);
|
||||
this.poseIndex = poseIndex;
|
||||
this.lastPoseTickIndex = lastPoseTickIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
|
||||
boolean value = entity.getProperty(this);
|
||||
if (value) {
|
||||
properties.put(poseIndex, newEntityData(poseIndex, EntityDataTypes.ENTITY_POSE, EntityPose.SITTING));
|
||||
properties.put(lastPoseTickIndex, newEntityData(lastPoseTickIndex, EntityDataTypes.LONG, -1L));
|
||||
} else {
|
||||
properties.put(poseIndex, newEntityData(poseIndex, EntityDataTypes.ENTITY_POSE, EntityPose.STANDING));
|
||||
properties.put(lastPoseTickIndex, newEntityData(lastPoseTickIndex, EntityDataTypes.LONG, 0L));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,11 +14,13 @@ import java.util.Map;
|
|||
import java.util.Optional;
|
||||
|
||||
public class DinnerboneProperty extends EntityPropertyImpl<Boolean> {
|
||||
private final boolean optional;
|
||||
private final Object serialized;
|
||||
private final EntityDataType<?> type;
|
||||
|
||||
public DinnerboneProperty(boolean legacy, boolean optional) {
|
||||
super("dinnerbone", false, Boolean.class);
|
||||
this.optional = optional;
|
||||
Component name = Component.text("Dinnerbone");
|
||||
Object serialized = legacy ? AdventureSerializer.getLegacyGsonSerializer().serialize(name) :
|
||||
optional ? name : LegacyComponentSerializer.legacySection().serialize(name);
|
||||
|
@ -28,6 +30,6 @@ public class DinnerboneProperty extends EntityPropertyImpl<Boolean> {
|
|||
|
||||
@Override
|
||||
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
|
||||
properties.put(2, new EntityData(2, type, entity.getProperty(this) ? serialized : null));
|
||||
properties.put(2, new EntityData(2, type, entity.getProperty(this) ? serialized : optional ? null : ""));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,39 @@
|
|||
package lol.pyr.znpcsplus.interaction;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketListener;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.protocol.item.ItemStack;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.Equipment;
|
||||
import com.github.retrooper.packetevents.protocol.player.EquipmentSlot;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientInteractEntity;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEquipment;
|
||||
import lol.pyr.znpcsplus.api.event.NpcInteractEvent;
|
||||
import lol.pyr.znpcsplus.api.interaction.InteractionAction;
|
||||
import lol.pyr.znpcsplus.api.interaction.InteractionType;
|
||||
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl;
|
||||
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
|
||||
import lol.pyr.znpcsplus.user.User;
|
||||
import lol.pyr.znpcsplus.user.UserManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
public class InteractionPacketListener implements PacketListener {
|
||||
private final UserManager userManager;
|
||||
private final NpcRegistryImpl npcRegistry;
|
||||
private final NpcTypeRegistryImpl typeRegistry;
|
||||
private final TaskScheduler scheduler;
|
||||
|
||||
public InteractionPacketListener(UserManager userManager, NpcRegistryImpl npcRegistry, TaskScheduler scheduler) {
|
||||
public InteractionPacketListener(UserManager userManager, NpcRegistryImpl npcRegistry, NpcTypeRegistryImpl typeRegistry, TaskScheduler scheduler) {
|
||||
this.userManager = userManager;
|
||||
this.npcRegistry = npcRegistry;
|
||||
this.typeRegistry = typeRegistry;
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
|
@ -34,14 +44,25 @@ public class InteractionPacketListener implements PacketListener {
|
|||
if (player == null) return;
|
||||
|
||||
WrapperPlayClientInteractEntity packet = new WrapperPlayClientInteractEntity(event);
|
||||
User user = userManager.get(player);
|
||||
if (!user.canInteract()) return;
|
||||
|
||||
NpcEntryImpl entry = npcRegistry.getByEntityId(packet.getEntityId());
|
||||
if (entry == null || !entry.isProcessed()) return;
|
||||
NpcImpl npc = entry.getNpc();
|
||||
|
||||
if ((packet.getAction().equals(WrapperPlayClientInteractEntity.InteractAction.INTERACT)
|
||||
|| packet.getAction().equals(WrapperPlayClientInteractEntity.InteractAction.INTERACT_AT))
|
||||
&& npc.getType().equals(typeRegistry.getByName("allay"))) {
|
||||
PacketEvents.getAPI().getPlayerManager().sendPacket(player,
|
||||
new WrapperPlayServerEntityEquipment(packet.getEntityId(), Collections.singletonList(
|
||||
new Equipment(EquipmentSlot.MAIN_HAND, ItemStack.EMPTY))));
|
||||
player.updateInventory();
|
||||
}
|
||||
|
||||
InteractionType type = wrapClickType(packet.getAction());
|
||||
|
||||
User user = userManager.get(player);
|
||||
if (!user.canInteract()) return;
|
||||
|
||||
NpcInteractEvent interactEvent = new NpcInteractEvent(player, entry, type);
|
||||
Bukkit.getPluginManager().callEvent(interactEvent);
|
||||
if (interactEvent.isCancelled()) return;
|
||||
|
|
|
@ -115,7 +115,10 @@ public class NpcTypeImpl implements NpcType {
|
|||
public NpcTypeImpl build() {
|
||||
ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion();
|
||||
addProperties("fire", "invisible", "silent", "look", "look_distance", "view_distance",
|
||||
"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_horizontal", "player_knockback_cooldown", "player_knockback_sound", "player_knockback_sound_name",
|
||||
"player_knockback_sound_volume", "player_knockback_sound_pitch");
|
||||
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");
|
||||
|
|
|
@ -367,7 +367,7 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
|
|||
|
||||
register(builder(p, "camel", EntityTypes.CAMEL)
|
||||
.setHologramOffset(0.25)
|
||||
.addProperties("bashing"));
|
||||
.addProperties("bashing", "camel_sitting"));
|
||||
}
|
||||
|
||||
public Collection<NpcType> getAll() {
|
||||
|
|
|
@ -7,20 +7,26 @@ import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
|
|||
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||
import lol.pyr.znpcsplus.user.User;
|
||||
import lol.pyr.znpcsplus.user.UserManager;
|
||||
import lol.pyr.znpcsplus.util.LookType;
|
||||
import lol.pyr.znpcsplus.util.NpcLocation;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.NumberConversions;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class NpcProcessorTask extends BukkitRunnable {
|
||||
private final NpcRegistryImpl npcRegistry;
|
||||
private final EntityPropertyRegistryImpl propertyRegistry;
|
||||
private final UserManager userManager;
|
||||
|
||||
public NpcProcessorTask(NpcRegistryImpl npcRegistry, EntityPropertyRegistryImpl propertyRegistry) {
|
||||
public NpcProcessorTask(NpcRegistryImpl npcRegistry, EntityPropertyRegistryImpl propertyRegistry,UserManager userManager) {
|
||||
this.npcRegistry = npcRegistry;
|
||||
this.propertyRegistry = propertyRegistry;
|
||||
this.userManager = userManager;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
|
@ -28,7 +34,28 @@ public class NpcProcessorTask extends BukkitRunnable {
|
|||
EntityPropertyImpl<LookType> lookProperty = propertyRegistry.getByName("look", LookType.class);
|
||||
EntityPropertyImpl<Double> lookDistanceProperty = propertyRegistry.getByName("look_distance", Double.class);
|
||||
EntityPropertyImpl<Boolean> permissionRequiredProperty = propertyRegistry.getByName("permission_required", Boolean.class);
|
||||
EntityPropertyImpl<Boolean> playerKnockbackProperty = propertyRegistry.getByName("player_knockback", Boolean.class);
|
||||
EntityPropertyImpl<String> playerKnockbackExemptPermissionProperty = propertyRegistry.getByName("player_knockback_exempt_permission", String.class);
|
||||
EntityPropertyImpl<Double> playerKnockbackDistanceProperty = propertyRegistry.getByName("player_knockback_distance", Double.class);
|
||||
EntityPropertyImpl<Double> playerKnockbackVerticalProperty = propertyRegistry.getByName("player_knockback_vertical", Double.class);
|
||||
EntityPropertyImpl<Double> playerKnockbackHorizontalProperty = propertyRegistry.getByName("player_knockback_horizontal", Double.class);
|
||||
EntityPropertyImpl<Integer> playerKnockbackCooldownProperty = propertyRegistry.getByName("player_knockback_cooldown", Integer.class);
|
||||
EntityPropertyImpl<Boolean> playerKnockbackSoundProperty = propertyRegistry.getByName("player_knockback_sound", Boolean.class);
|
||||
EntityPropertyImpl<Sound> playerKnockbackSoundNameProperty = propertyRegistry.getByName("player_knockback_sound_name", Sound.class);
|
||||
EntityPropertyImpl<Float> playerKnockbackSoundVolumeProperty = propertyRegistry.getByName("player_knockback_sound_volume", Float.class);
|
||||
EntityPropertyImpl<Float> playerKnockbackSoundPitchProperty = propertyRegistry.getByName("player_knockback_sound_pitch", Float.class);
|
||||
double lookDistance;
|
||||
boolean permissionRequired;
|
||||
boolean playerKnockback;
|
||||
String playerKnockbackExemptPermission = null;
|
||||
double playerKnockbackDistance = 0;
|
||||
double playerKnockbackVertical = 0;
|
||||
double playerKnockbackHorizontal = 0;
|
||||
int playerKnockbackCooldown = 0;
|
||||
boolean playerKnockbackSound = false;
|
||||
Sound playerKnockbackSoundName = null;
|
||||
float playerKnockbackSoundVolume = 0;
|
||||
float playerKnockbackSoundPitch = 0;
|
||||
for (NpcEntryImpl entry : npcRegistry.getProcessable()) {
|
||||
NpcImpl npc = entry.getNpc();
|
||||
if (!npc.isEnabled()) continue;
|
||||
|
@ -37,7 +64,19 @@ public class NpcProcessorTask extends BukkitRunnable {
|
|||
Player closest = null;
|
||||
LookType lookType = npc.getProperty(lookProperty);
|
||||
lookDistance = NumberConversions.square(npc.getProperty(lookDistanceProperty));
|
||||
boolean permissionRequired = npc.getProperty(permissionRequiredProperty);
|
||||
permissionRequired = npc.getProperty(permissionRequiredProperty);
|
||||
playerKnockback = npc.getProperty(playerKnockbackProperty);
|
||||
if (playerKnockback) {
|
||||
playerKnockbackExemptPermission = npc.getProperty(playerKnockbackExemptPermissionProperty);
|
||||
playerKnockbackDistance = NumberConversions.square(npc.getProperty(playerKnockbackDistanceProperty));
|
||||
playerKnockbackVertical = npc.getProperty(playerKnockbackVerticalProperty);
|
||||
playerKnockbackHorizontal = npc.getProperty(playerKnockbackHorizontalProperty);
|
||||
playerKnockbackCooldown = npc.getProperty(playerKnockbackCooldownProperty);
|
||||
playerKnockbackSound = npc.getProperty(playerKnockbackSoundProperty);
|
||||
playerKnockbackSoundName = npc.getProperty(playerKnockbackSoundNameProperty);
|
||||
playerKnockbackSoundVolume = npc.getProperty(playerKnockbackSoundVolumeProperty);
|
||||
playerKnockbackSoundPitch = npc.getProperty(playerKnockbackSoundPitchProperty);
|
||||
}
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (!player.getWorld().equals(npc.getWorld())) {
|
||||
if (npc.isVisibleTo(player)) npc.hide(player);
|
||||
|
@ -71,6 +110,21 @@ public class NpcProcessorTask extends BukkitRunnable {
|
|||
NpcLocation expected = npc.getLocation().lookingAt(player.getLocation().add(0, -npc.getType().getHologramOffset(), 0));
|
||||
if (!expected.equals(npc.getLocation())) npc.setHeadRotation(player, expected.getYaw(), expected.getPitch());
|
||||
}
|
||||
|
||||
// player knockback
|
||||
User user = userManager.get(player.getUniqueId());
|
||||
if (playerKnockbackExemptPermission == null || !player.hasPermission(playerKnockbackExemptPermission)) {
|
||||
if (playerKnockback && distance <= playerKnockbackDistance && user.canKnockback(playerKnockbackCooldown)) {
|
||||
double x = npc.getLocation().getX() - player.getLocation().getX();
|
||||
double z = npc.getLocation().getZ() - player.getLocation().getZ();
|
||||
double angle = Math.atan2(z, x);
|
||||
double knockbackX = -Math.cos(angle) * playerKnockbackHorizontal;
|
||||
double knockbackZ = -Math.sin(angle) * playerKnockbackHorizontal;
|
||||
player.setVelocity(player.getVelocity().add(new Vector(knockbackX, playerKnockbackVertical, knockbackZ)));
|
||||
if (playerKnockbackSound)
|
||||
player.playSound(player.getLocation(), playerKnockbackSoundName, playerKnockbackSoundVolume, playerKnockbackSoundPitch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// look property
|
||||
|
|
|
@ -50,6 +50,7 @@ public class UpdateChecker extends BukkitRunnable {
|
|||
int currentPart = Integer.parseInt(currentParts[i]);
|
||||
int newPart = Integer.parseInt(newParts[i]);
|
||||
if (newPart > currentPart) return Status.UPDATE_NEEDED;
|
||||
if (newPart < currentPart) return Status.LATEST_VERSION;
|
||||
}
|
||||
if (newType.ordinal() > currentType.ordinal()) return Status.UPDATE_NEEDED;
|
||||
if (newType == currentType) {
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.UUID;
|
|||
public class User {
|
||||
private final UUID uuid;
|
||||
private long lastNpcInteraction;
|
||||
private long lastNpcKnockback;
|
||||
private final Map<UUID, Long> actionCooldownMap = new HashMap<>();
|
||||
|
||||
public User(UUID uuid) {
|
||||
|
@ -29,6 +30,14 @@ public class User {
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean canKnockback(int cooldown) {
|
||||
if (System.currentTimeMillis() - lastNpcKnockback > cooldown) {
|
||||
lastNpcKnockback = System.currentTimeMillis();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue