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;
|
package lol.pyr.znpcsplus.util;
|
||||||
|
|
||||||
public enum VillagerProfession {
|
public enum VillagerProfession {
|
||||||
NONE(0),
|
NONE(0, 0),
|
||||||
ARMORER(1),
|
ARMORER(1, 3),
|
||||||
BUTCHER(2),
|
BUTCHER(2, 4),
|
||||||
CARTOGRAPHER(3),
|
CARTOGRAPHER(3, 1),
|
||||||
CLERIC(4),
|
CLERIC(4, 2),
|
||||||
FARMER(5),
|
FARMER(5, 0),
|
||||||
FISHERMAN(6),
|
FISHERMAN(6, 0),
|
||||||
FLETCHER(7),
|
FLETCHER(7, 0),
|
||||||
LEATHER_WORKER(8),
|
LEATHER_WORKER(8, 4),
|
||||||
LIBRARIAN(9),
|
LIBRARIAN(9, 1),
|
||||||
MASON(10),
|
MASON(10),
|
||||||
NITWIT(11),
|
NITWIT(11, 5),
|
||||||
SHEPHERD(12),
|
SHEPHERD(12, 0),
|
||||||
TOOL_SMITH(13),
|
TOOL_SMITH(13, 3),
|
||||||
WEAPON_SMITH(14);
|
WEAPON_SMITH(14, 3);
|
||||||
|
|
||||||
private final int id;
|
private final int id;
|
||||||
|
private final int legacyId;
|
||||||
|
|
||||||
VillagerProfession(int id) {
|
VillagerProfession(int id) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
|
this.legacyId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
VillagerProfession(int id, int legacyId) {
|
||||||
|
this.id = id;
|
||||||
|
this.legacyId = legacyId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getLegacyId() {
|
||||||
|
return legacyId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -138,7 +138,7 @@ public class ZNpcsPlus {
|
||||||
|
|
||||||
typeRegistry.registerDefault(packetEvents, propertyRegistry);
|
typeRegistry.registerDefault(packetEvents, propertyRegistry);
|
||||||
actionRegistry.registerTypes(scheduler, adventure, textSerializer, bungeeConnector);
|
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);
|
new Metrics(bootstrap, 18244);
|
||||||
pluginManager.registerEvents(new UserListener(userManager), bootstrap);
|
pluginManager.registerEvents(new UserListener(userManager), bootstrap);
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ public class ZNpcsPlus {
|
||||||
pluginManager.registerEvents(new UpdateNotificationListener(this, adventure, updateChecker, scheduler), bootstrap);
|
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 HologramRefreshTask(npcRegistry), 60L, 20L);
|
||||||
scheduler.runDelayedTimerAsync(new SkinCacheCleanTask(skinCache), 1200, 1200);
|
scheduler.runDelayedTimerAsync(new SkinCacheCleanTask(skinCache), 1200, 1200);
|
||||||
pluginManager.registerEvents(new ViewableHideOnLeaveListener(), bootstrap);
|
pluginManager.registerEvents(new ViewableHideOnLeaveListener(), bootstrap);
|
||||||
|
@ -275,6 +275,7 @@ public class ZNpcsPlus {
|
||||||
registerEnumParser(manager, SnifferState.class, incorrectUsageMessage);
|
registerEnumParser(manager, SnifferState.class, incorrectUsageMessage);
|
||||||
registerEnumParser(manager, RabbitType.class, incorrectUsageMessage);
|
registerEnumParser(manager, RabbitType.class, incorrectUsageMessage);
|
||||||
registerEnumParser(manager, AttachDirection.class, incorrectUsageMessage);
|
registerEnumParser(manager, AttachDirection.class, incorrectUsageMessage);
|
||||||
|
registerEnumParser(manager, Sound.class, incorrectUsageMessage);
|
||||||
|
|
||||||
manager.registerCommand("npc", new MultiCommand(bootstrap.loadHelpMessage("root"))
|
manager.registerCommand("npc", new MultiCommand(bootstrap.loadHelpMessage("root"))
|
||||||
.addSubcommand("center", new CenterCommand(npcRegistry))
|
.addSubcommand("center", new CenterCommand(npcRegistry))
|
||||||
|
|
|
@ -2,6 +2,7 @@ package lol.pyr.znpcsplus.conversion;
|
||||||
|
|
||||||
import lol.pyr.znpcsplus.config.ConfigManager;
|
import lol.pyr.znpcsplus.config.ConfigManager;
|
||||||
import lol.pyr.znpcsplus.conversion.citizens.CitizensImporter;
|
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.conversion.znpcs.ZNpcImporter;
|
||||||
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
|
import lol.pyr.znpcsplus.entity.EntityPropertyRegistryImpl;
|
||||||
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
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)));
|
packetFactory, textSerializer, typeRegistry, propertyRegistry, skinCache, new File(pluginsFolder, "ZNPCsPlusLegacy/data.json"), bungeeConnector)));
|
||||||
register("citizens", LazyLoader.of(() -> new CitizensImporter(configManager, adventure, taskScheduler,
|
register("citizens", LazyLoader.of(() -> new CitizensImporter(configManager, adventure, taskScheduler,
|
||||||
packetFactory, textSerializer, typeRegistry, propertyRegistry, skinCache, new File(pluginsFolder, "Citizens/saves.yml"), npcRegistry)));
|
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) {
|
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 net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import org.bukkit.Color;
|
import org.bukkit.Color;
|
||||||
import org.bukkit.DyeColor;
|
import org.bukkit.DyeColor;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -84,6 +85,7 @@ public class EntityPropertyRegistryImpl implements EntityPropertyRegistry {
|
||||||
registerEnumSerializer(SnifferState.class);
|
registerEnumSerializer(SnifferState.class);
|
||||||
registerEnumSerializer(RabbitType.class);
|
registerEnumSerializer(RabbitType.class);
|
||||||
registerEnumSerializer(AttachDirection.class);
|
registerEnumSerializer(AttachDirection.class);
|
||||||
|
registerEnumSerializer(Sound.class);
|
||||||
|
|
||||||
registerPrimitiveSerializers(Integer.class, Boolean.class, Double.class, Float.class, Long.class, Short.class, Byte.class, String.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<>("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 GlowProperty(packetFactory));
|
||||||
register(new BitsetProperty("fire", 0, 0x01));
|
register(new BitsetProperty("fire", 0, 0x01));
|
||||||
register(new BitsetProperty("invisible", 0, 0x20));
|
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_10)) babyIndex = 12;
|
||||||
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) babyIndex = 11;
|
else if (ver.isNewerThanOrEquals(ServerVersion.V_1_9)) babyIndex = 11;
|
||||||
else babyIndex = 12;
|
else babyIndex = 12;
|
||||||
|
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));
|
register(new BooleanProperty("baby", babyIndex, false, legacyBooleans));
|
||||||
|
}
|
||||||
|
|
||||||
// Player
|
// Player
|
||||||
register(new DummyProperty<>("skin", SkinDescriptor.class, false));
|
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 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
|
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
|
// Wolf
|
||||||
int wolfIndex;
|
int wolfIndex;
|
||||||
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) wolfIndex = 19;
|
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())));
|
register(new CustomTypeProperty<>("pose", 6, NpcPose.STANDING, EntityDataTypes.ENTITY_POSE, npcPose -> EntityPose.valueOf(npcPose.name())));
|
||||||
|
|
||||||
// Villager
|
// Villager
|
||||||
final int villagerIndex;
|
|
||||||
if (ver.isNewerThanOrEquals(ServerVersion.V_1_17)) villagerIndex = 18;
|
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_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;
|
else villagerIndex = 16;
|
||||||
register(new VillagerTypeProperty("villager_type", villagerIndex, VillagerType.PLAINS));
|
register(new VillagerTypeProperty("villager_type", villagerIndex, VillagerType.PLAINS));
|
||||||
register(new VillagerProfessionProperty("villager_profession", villagerIndex, VillagerProfession.NONE));
|
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;
|
if (!ver.isNewerThanOrEquals(ServerVersion.V_1_20)) return;
|
||||||
|
|
||||||
// Camel
|
// Camel
|
||||||
register(new BooleanProperty("bashing", 18, false, legacyBooleans));
|
int camelIndex = 18;
|
||||||
|
register(new BooleanProperty("bashing", camelIndex++, false, legacyBooleans));
|
||||||
|
register(new CamelSittingProperty(6, camelIndex));
|
||||||
|
|
||||||
// Sniffer
|
// Sniffer
|
||||||
register(new CustomTypeProperty<>("sniffer_state", 17, SnifferState.IDLING, EntityDataTypes.SNIFFER_STATE, state -> com.github.retrooper.packetevents.protocol.entity.sniffer.SnifferState.valueOf(state.name())));
|
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;
|
import java.util.Optional;
|
||||||
|
|
||||||
public class DinnerboneProperty extends EntityPropertyImpl<Boolean> {
|
public class DinnerboneProperty extends EntityPropertyImpl<Boolean> {
|
||||||
|
private final boolean optional;
|
||||||
private final Object serialized;
|
private final Object serialized;
|
||||||
private final EntityDataType<?> type;
|
private final EntityDataType<?> type;
|
||||||
|
|
||||||
public DinnerboneProperty(boolean legacy, boolean optional) {
|
public DinnerboneProperty(boolean legacy, boolean optional) {
|
||||||
super("dinnerbone", false, Boolean.class);
|
super("dinnerbone", false, Boolean.class);
|
||||||
|
this.optional = optional;
|
||||||
Component name = Component.text("Dinnerbone");
|
Component name = Component.text("Dinnerbone");
|
||||||
Object serialized = legacy ? AdventureSerializer.getLegacyGsonSerializer().serialize(name) :
|
Object serialized = legacy ? AdventureSerializer.getLegacyGsonSerializer().serialize(name) :
|
||||||
optional ? name : LegacyComponentSerializer.legacySection().serialize(name);
|
optional ? name : LegacyComponentSerializer.legacySection().serialize(name);
|
||||||
|
@ -28,6 +30,6 @@ public class DinnerboneProperty extends EntityPropertyImpl<Boolean> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void apply(Player player, PacketEntity entity, boolean isSpawned, Map<Integer, EntityData> properties) {
|
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;
|
package lol.pyr.znpcsplus.interaction;
|
||||||
|
|
||||||
|
import com.github.retrooper.packetevents.PacketEvents;
|
||||||
import com.github.retrooper.packetevents.event.PacketListener;
|
import com.github.retrooper.packetevents.event.PacketListener;
|
||||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
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.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.client.WrapperPlayClientInteractEntity;
|
||||||
|
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityEquipment;
|
||||||
import lol.pyr.znpcsplus.api.event.NpcInteractEvent;
|
import lol.pyr.znpcsplus.api.event.NpcInteractEvent;
|
||||||
import lol.pyr.znpcsplus.api.interaction.InteractionAction;
|
import lol.pyr.znpcsplus.api.interaction.InteractionAction;
|
||||||
import lol.pyr.znpcsplus.api.interaction.InteractionType;
|
import lol.pyr.znpcsplus.api.interaction.InteractionType;
|
||||||
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
import lol.pyr.znpcsplus.npc.NpcEntryImpl;
|
||||||
import lol.pyr.znpcsplus.npc.NpcImpl;
|
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||||
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
||||||
|
import lol.pyr.znpcsplus.npc.NpcTypeRegistryImpl;
|
||||||
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
|
import lol.pyr.znpcsplus.scheduling.TaskScheduler;
|
||||||
import lol.pyr.znpcsplus.user.User;
|
import lol.pyr.znpcsplus.user.User;
|
||||||
import lol.pyr.znpcsplus.user.UserManager;
|
import lol.pyr.znpcsplus.user.UserManager;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
public class InteractionPacketListener implements PacketListener {
|
public class InteractionPacketListener implements PacketListener {
|
||||||
private final UserManager userManager;
|
private final UserManager userManager;
|
||||||
private final NpcRegistryImpl npcRegistry;
|
private final NpcRegistryImpl npcRegistry;
|
||||||
|
private final NpcTypeRegistryImpl typeRegistry;
|
||||||
private final TaskScheduler scheduler;
|
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.userManager = userManager;
|
||||||
this.npcRegistry = npcRegistry;
|
this.npcRegistry = npcRegistry;
|
||||||
|
this.typeRegistry = typeRegistry;
|
||||||
this.scheduler = scheduler;
|
this.scheduler = scheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,14 +44,25 @@ public class InteractionPacketListener implements PacketListener {
|
||||||
if (player == null) return;
|
if (player == null) return;
|
||||||
|
|
||||||
WrapperPlayClientInteractEntity packet = new WrapperPlayClientInteractEntity(event);
|
WrapperPlayClientInteractEntity packet = new WrapperPlayClientInteractEntity(event);
|
||||||
User user = userManager.get(player);
|
|
||||||
if (!user.canInteract()) return;
|
|
||||||
|
|
||||||
NpcEntryImpl entry = npcRegistry.getByEntityId(packet.getEntityId());
|
NpcEntryImpl entry = npcRegistry.getByEntityId(packet.getEntityId());
|
||||||
if (entry == null || !entry.isProcessed()) return;
|
if (entry == null || !entry.isProcessed()) return;
|
||||||
NpcImpl npc = entry.getNpc();
|
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());
|
InteractionType type = wrapClickType(packet.getAction());
|
||||||
|
|
||||||
|
User user = userManager.get(player);
|
||||||
|
if (!user.canInteract()) return;
|
||||||
|
|
||||||
NpcInteractEvent interactEvent = new NpcInteractEvent(player, entry, type);
|
NpcInteractEvent interactEvent = new NpcInteractEvent(player, entry, type);
|
||||||
Bukkit.getPluginManager().callEvent(interactEvent);
|
Bukkit.getPluginManager().callEvent(interactEvent);
|
||||||
if (interactEvent.isCancelled()) return;
|
if (interactEvent.isCancelled()) return;
|
||||||
|
|
|
@ -115,7 +115,10 @@ public class NpcTypeImpl implements NpcType {
|
||||||
public NpcTypeImpl build() {
|
public NpcTypeImpl build() {
|
||||||
ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion();
|
ServerVersion version = PacketEvents.getAPI().getServerManager().getVersion();
|
||||||
addProperties("fire", "invisible", "silent", "look", "look_distance", "view_distance",
|
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");
|
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");
|
||||||
|
|
|
@ -367,7 +367,7 @@ public class NpcTypeRegistryImpl implements NpcTypeRegistry {
|
||||||
|
|
||||||
register(builder(p, "camel", EntityTypes.CAMEL)
|
register(builder(p, "camel", EntityTypes.CAMEL)
|
||||||
.setHologramOffset(0.25)
|
.setHologramOffset(0.25)
|
||||||
.addProperties("bashing"));
|
.addProperties("bashing", "camel_sitting"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<NpcType> getAll() {
|
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.NpcEntryImpl;
|
||||||
import lol.pyr.znpcsplus.npc.NpcImpl;
|
import lol.pyr.znpcsplus.npc.NpcImpl;
|
||||||
import lol.pyr.znpcsplus.npc.NpcRegistryImpl;
|
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.LookType;
|
||||||
import lol.pyr.znpcsplus.util.NpcLocation;
|
import lol.pyr.znpcsplus.util.NpcLocation;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Sound;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
import org.bukkit.util.NumberConversions;
|
import org.bukkit.util.NumberConversions;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
public class NpcProcessorTask extends BukkitRunnable {
|
public class NpcProcessorTask extends BukkitRunnable {
|
||||||
private final NpcRegistryImpl npcRegistry;
|
private final NpcRegistryImpl npcRegistry;
|
||||||
private final EntityPropertyRegistryImpl propertyRegistry;
|
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.npcRegistry = npcRegistry;
|
||||||
this.propertyRegistry = propertyRegistry;
|
this.propertyRegistry = propertyRegistry;
|
||||||
|
this.userManager = userManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
|
@ -28,7 +34,28 @@ public class NpcProcessorTask extends BukkitRunnable {
|
||||||
EntityPropertyImpl<LookType> lookProperty = propertyRegistry.getByName("look", LookType.class);
|
EntityPropertyImpl<LookType> lookProperty = propertyRegistry.getByName("look", LookType.class);
|
||||||
EntityPropertyImpl<Double> lookDistanceProperty = propertyRegistry.getByName("look_distance", Double.class);
|
EntityPropertyImpl<Double> lookDistanceProperty = propertyRegistry.getByName("look_distance", Double.class);
|
||||||
EntityPropertyImpl<Boolean> permissionRequiredProperty = propertyRegistry.getByName("permission_required", Boolean.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;
|
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()) {
|
for (NpcEntryImpl entry : npcRegistry.getProcessable()) {
|
||||||
NpcImpl npc = entry.getNpc();
|
NpcImpl npc = entry.getNpc();
|
||||||
if (!npc.isEnabled()) continue;
|
if (!npc.isEnabled()) continue;
|
||||||
|
@ -37,7 +64,19 @@ public class NpcProcessorTask extends BukkitRunnable {
|
||||||
Player closest = null;
|
Player closest = null;
|
||||||
LookType lookType = npc.getProperty(lookProperty);
|
LookType lookType = npc.getProperty(lookProperty);
|
||||||
lookDistance = NumberConversions.square(npc.getProperty(lookDistanceProperty));
|
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()) {
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
if (!player.getWorld().equals(npc.getWorld())) {
|
if (!player.getWorld().equals(npc.getWorld())) {
|
||||||
if (npc.isVisibleTo(player)) npc.hide(player);
|
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));
|
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());
|
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
|
// look property
|
||||||
|
|
|
@ -50,6 +50,7 @@ public class UpdateChecker extends BukkitRunnable {
|
||||||
int currentPart = Integer.parseInt(currentParts[i]);
|
int currentPart = Integer.parseInt(currentParts[i]);
|
||||||
int newPart = Integer.parseInt(newParts[i]);
|
int newPart = Integer.parseInt(newParts[i]);
|
||||||
if (newPart > currentPart) return Status.UPDATE_NEEDED;
|
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.ordinal() > currentType.ordinal()) return Status.UPDATE_NEEDED;
|
||||||
if (newType == currentType) {
|
if (newType == currentType) {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.util.UUID;
|
||||||
public class User {
|
public class User {
|
||||||
private final UUID uuid;
|
private final UUID uuid;
|
||||||
private long lastNpcInteraction;
|
private long lastNpcInteraction;
|
||||||
|
private long lastNpcKnockback;
|
||||||
private final Map<UUID, Long> actionCooldownMap = new HashMap<>();
|
private final Map<UUID, Long> actionCooldownMap = new HashMap<>();
|
||||||
|
|
||||||
public User(UUID uuid) {
|
public User(UUID uuid) {
|
||||||
|
@ -29,6 +30,14 @@ public class User {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canKnockback(int cooldown) {
|
||||||
|
if (System.currentTimeMillis() - lastNpcKnockback > cooldown) {
|
||||||
|
lastNpcKnockback = System.currentTimeMillis();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public UUID getUuid() {
|
public UUID getUuid() {
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue