Add simple /npc drops GUI and add NPC selection to /npc follow

This commit is contained in:
fullwall 2021-02-07 18:45:10 +08:00
parent 65d02398fb
commit 9bbe9ae3c4
4 changed files with 187 additions and 21 deletions

View File

@ -93,6 +93,7 @@ import net.citizensnpcs.trait.CommandTrait.ItemRequirementGUI;
import net.citizensnpcs.trait.CommandTrait.NPCCommandBuilder;
import net.citizensnpcs.trait.Controllable;
import net.citizensnpcs.trait.CurrentLocation;
import net.citizensnpcs.trait.DropsTrait;
import net.citizensnpcs.trait.EndermanTrait;
import net.citizensnpcs.trait.FollowTrait;
import net.citizensnpcs.trait.GameModeTrait;
@ -310,7 +311,6 @@ public class NPCCommands {
Messaging.sendTr(sender,
npc.data().<Boolean> get(NPC.COLLIDABLE_METADATA) ? Messages.COLLIDABLE_SET : Messages.COLLIDABLE_UNSET,
npc.getName());
}
@Command(
@ -604,6 +604,20 @@ public class NPCCommands {
}
}
@Command(
aliases = { "npc" },
usage = "drops",
desc = "Edit an NPC's drops",
modifiers = { "drops" },
min = 1,
max = 1,
permission = "citizens.npc.drops")
@Requirements(ownership = true, selected = true)
public void drops(CommandContext args, Player sender, NPC npc) throws CommandException {
DropsTrait trait = npc.getOrAddTrait(DropsTrait.class);
trait.displayEditor(sender);
}
@Command(
aliases = { "npc" },
usage = "enderman -a[ngry]",
@ -644,7 +658,7 @@ public class NPCCommands {
@Command(
aliases = { "npc" },
usage = "follow (player name) (-p[rotect])",
usage = "follow (player name|NPC id) (-p[rotect])",
desc = "Toggles NPC following you",
flags = "p",
modifiers = { "follow" },
@ -657,9 +671,30 @@ public class NPCCommands {
if (args.argsLength() > 1) {
name = args.getString(1);
}
OfflinePlayer player = Bukkit.getOfflinePlayer(name);
if (player == null) {
throw new CommandException();
NPCCommandSelector.Callback callback = new NPCCommandSelector.Callback() {
@Override
public void run(NPC followingNPC) throws CommandException {
if (followingNPC == null)
throw new CommandException(Messages.COMMAND_MUST_HAVE_SELECTED);
if (!(sender instanceof ConsoleCommandSender)
&& !followingNPC.getOrAddTrait(Owner.class).isOwnedBy(sender))
throw new CommandException(Messages.COMMAND_MUST_BE_OWNER);
if (followingNPC.getEntity() instanceof Player) {
boolean following = followingNPC.getOrAddTrait(FollowTrait.class)
.toggle((Player) followingNPC.getEntity(), protect);
Messaging.sendTr(sender, following ? Messages.FOLLOW_SET : Messages.FOLLOW_UNSET, npc.getName(),
followingNPC.getName());
} else {
throw new CommandException();
}
}
};
NPCCommandSelector.startWithCallback(callback, CitizensAPI.getNPCRegistry(), sender, args,
args.getString(1));
return;
}
boolean following = npc.getOrAddTrait(FollowTrait.class).toggle(player, protect);
Messaging.sendTr(sender, following ? Messages.FOLLOW_SET : Messages.FOLLOW_UNSET, npc.getName(),

View File

@ -28,6 +28,7 @@ import net.citizensnpcs.trait.ClickRedirectTrait;
import net.citizensnpcs.trait.CommandTrait;
import net.citizensnpcs.trait.Controllable;
import net.citizensnpcs.trait.CurrentLocation;
import net.citizensnpcs.trait.DropsTrait;
import net.citizensnpcs.trait.EndermanTrait;
import net.citizensnpcs.trait.FollowTrait;
import net.citizensnpcs.trait.GameModeTrait;
@ -66,6 +67,7 @@ public class CitizensTraitFactory implements TraitFactory {
registerTrait(TraitInfo.create(CommandTrait.class));
registerTrait(TraitInfo.create(Controllable.class));
registerTrait(TraitInfo.create(CurrentLocation.class));
registerTrait(TraitInfo.create(DropsTrait.class));
registerTrait(TraitInfo.create(EndermanTrait.class));
registerTrait(TraitInfo.create(Equipment.class));
registerTrait(TraitInfo.create(FollowTrait.class));

View File

@ -37,7 +37,6 @@ import net.citizensnpcs.api.gui.MenuContext;
import net.citizensnpcs.api.npc.NPC;
import net.citizensnpcs.api.persistence.DelegatePersistence;
import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.persistence.PersistenceLoader;
import net.citizensnpcs.api.persistence.Persister;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
@ -55,8 +54,7 @@ public class CommandTrait extends Trait {
@Persist
@DelegatePersistence(NPCCommandPersister.class)
private final Map<String, NPCCommand> commands = Maps.newHashMap();
@Persist
@DelegatePersistence(PlayerNPCCommandPersister.class)
@Persist(reify = true)
private final Map<String, PlayerNPCCommand> cooldowns = Maps.newHashMap();
@Persist
private double cost = -1;
@ -599,19 +597,4 @@ public class CommandTrait extends Trait {
return command.cooldown > 0 || command.n > 0 || (command.perms != null && command.perms.size() > 0);
}
}
private static class PlayerNPCCommandPersister implements Persister<PlayerNPCCommand> {
public PlayerNPCCommandPersister() {
}
@Override
public PlayerNPCCommand create(DataKey root) {
return PersistenceLoader.load(PlayerNPCCommand.class, root);
}
@Override
public void save(PlayerNPCCommand instance, DataKey root) {
PersistenceLoader.save(instance, root);
}
}
}

View File

@ -0,0 +1,146 @@
package net.citizensnpcs.trait;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.event.NPCDeathEvent;
import net.citizensnpcs.api.gui.InventoryMenu;
import net.citizensnpcs.api.gui.InventoryMenuPage;
import net.citizensnpcs.api.gui.InventoryMenuSlot;
import net.citizensnpcs.api.gui.Menu;
import net.citizensnpcs.api.gui.MenuContext;
import net.citizensnpcs.api.gui.PercentageSlotHandler;
import net.citizensnpcs.api.persistence.Persist;
import net.citizensnpcs.api.trait.Trait;
import net.citizensnpcs.api.trait.TraitName;
import net.citizensnpcs.util.Util;
@TraitName("dropstrait")
public class DropsTrait extends Trait {
@Persist(reify = true)
private List<ItemDrop> drops = Lists.newArrayList();
public DropsTrait() {
super("dropstrait");
}
public void displayEditor(Player sender) {
InventoryMenu.createSelfRegistered(new DropsGUI(this)).present(sender);
}
@EventHandler
public void onNPCDeath(NPCDeathEvent event) {
if (!event.getNPC().equals(npc))
return;
Random random = Util.getFastRandom();
for (ItemDrop drop : drops) {
if (random.nextDouble() < drop.chance) {
event.getDrops().add(drop.drop);
}
}
}
@Menu(title = "Add items for drops", type = InventoryType.CHEST, dimensions = { 5, 9 })
public static class DropsGUI extends InventoryMenuPage {
private final Map<Integer, Double> chances = Maps.newHashMap();
private Inventory inventory;
private int taskId;
private DropsTrait trait;
private DropsGUI() {
throw new UnsupportedOperationException();
}
public DropsGUI(DropsTrait trait) {
this.trait = trait;
}
@Override
public void initialise(MenuContext ctx) {
this.taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(CitizensAPI.getPlugin(), this, 0, 1);
this.inventory = ctx.getInventory();
int k = 0;
for (int i = 1; i < 5; i += 2) {
for (int j = 0; j < 9; j++) {
int islot = (i - 1) * 9 + j;
ItemDrop drop;
int chance = 100;
if (k < trait.drops.size()) {
drop = trait.drops.get(k++);
chance = (int) Math.floor(drop.chance * 100.0);
chances.put(islot, drop.chance);
ctx.getInventory().setItem(islot, drop.drop.clone());
}
InventoryMenuSlot slot = ctx.getSlot(i * 9 + j);
slot.setItemStack(new ItemStack(Material.GLASS_PANE), "Drop chance <e>" + chance + "%");
slot.addClickHandler(new PercentageSlotHandler((pct) -> {
if (chances.containsKey(islot)) {
chances.put(islot, pct / 100.0);
}
return "Drop chance <e>" + pct + "%";
}, chance));
}
}
}
@Override
public void onClick(InventoryMenuSlot slot, InventoryClickEvent event) {
if (event.getAction().name().contains("PICKUP")) {
chances.remove(event.getSlot());
} else if (event.getAction().name().contains("PLACE")) {
chances.putIfAbsent(event.getSlot(), 1.0);
}
}
@Override
public void onClose(HumanEntity player) {
Bukkit.getScheduler().cancelTask(taskId);
}
@Override
public void run() {
List<ItemDrop> drops = Lists.newArrayList();
for (int i = 0; i < 5; i += 2) {
for (int j = 0; j < 9; j++) {
int slot = i * 9 + j;
ItemStack stack = inventory.getItem(slot);
if (stack == null || stack.getType() == Material.AIR)
continue;
drops.add(new ItemDrop(stack, chances.getOrDefault(slot, 1.0)));
}
}
this.trait.drops = drops;
}
}
private static class ItemDrop {
@Persist
double chance;
@Persist
ItemStack drop;
public ItemDrop() {
}
public ItemDrop(ItemStack drop, double chance) {
this.drop = drop;
this.chance = chance;
}
}
}