Party System

Fully implemented party system backend.
Currently implemented in commands.
Fixed Entities not being removed on reload
Fixed ghost chest issue.
Started Party Menu GUI
This commit is contained in:
James Peters 2020-10-18 12:10:19 +01:00
parent 33dfc42d67
commit 3a0c0e23c1
16 changed files with 584 additions and 15 deletions

View File

@ -14,6 +14,8 @@ import com.jamesdpeters.minecraft.chests.maventemplates.BuildConstants;
import com.jamesdpeters.minecraft.chests.misc.Permissions;
import com.jamesdpeters.minecraft.chests.misc.Stats;
import com.jamesdpeters.minecraft.chests.misc.Utils;
import com.jamesdpeters.minecraft.chests.party.PlayerParty;
import com.jamesdpeters.minecraft.chests.party.PlayerPartyStorage;
import com.jamesdpeters.minecraft.chests.serialize.Config;
import com.jamesdpeters.minecraft.chests.serialize.ConfigStorage;
import com.jamesdpeters.minecraft.chests.serialize.LocationInfo;
@ -60,6 +62,9 @@ import org.bukkit.plugin.java.annotation.plugin.author.Author;
@Permission(name = Permissions.AUTOCRAFT_OPEN_REMOTE, desc = "Gives permission to remotely open AutoCrafting stations.", defaultValue = PermissionDefault.TRUE)
@Permission(name = Permissions.AUTOCRAFT_ADD, desc = "Gives permission to add AutoCrafting stations.", defaultValue = PermissionDefault.TRUE)
@Permission(name = Permissions.AUTOCRAFT_REMOVE, desc = "Gives permission to remove AutoCrafting stations.", defaultValue = PermissionDefault.TRUE)
@Permission(name = Permissions.PARTY_CREATE, desc = "Gives permission to create Chests++ parties.", defaultValue = PermissionDefault.TRUE)
@Permission(name = Permissions.PARTY_ACCEPT_INVITE, desc = "Gives permission to accept Chests++ party invites.", defaultValue = PermissionDefault.TRUE)
@Permission(name = Permissions.PARTY_INVITE, desc = "Gives permission to invite players to Chests++ parties.", defaultValue = PermissionDefault.TRUE)
public class ChestsPlusPlus extends JavaPlugin {
public static JavaPlugin PLUGIN;
@ -73,6 +78,8 @@ public class ChestsPlusPlus extends JavaPlugin {
ConfigurationSerialization.registerClass(AutoCraftingStorage.class, "AutoCraftingStorage");
ConfigurationSerialization.registerClass(RecipeSerializable.class, "Recipe");
ConfigurationSerialization.registerClass(LocationInfo.class, "LocationInfo");
ConfigurationSerialization.registerClass(PlayerPartyStorage.class, "PlayerPartyStorage");
ConfigurationSerialization.registerClass(PlayerParty.class, "PlayerParty");
}
@ -122,15 +129,15 @@ public class ChestsPlusPlus extends JavaPlugin {
}, 0, PluginConfig.UPDATE_CHECKER_PERIOD.get() * 20);
}
// Remove armour stands if disabled
Utils.fixEntities();
//Load storages after load.
Bukkit.getScheduler().scheduleSyncDelayedTask(this, () -> {
Crafting.load();
new Config();
getLogger().info("Chests++ Successfully Loaded Config and Recipes");
// Remove armour stands if disabled
Utils.fixEntities();
//Register event listeners
getServer().getPluginManager().registerEvents(new StorageListener(), this);
getServer().getPluginManager().registerEvents(new InventoryListener(), this);

View File

@ -2,7 +2,14 @@ package com.jamesdpeters.minecraft.chests.commands;
import com.jamesdpeters.minecraft.chests.ChestsPlusPlus;
import com.jamesdpeters.minecraft.chests.api.ApiSpecific;
import com.jamesdpeters.minecraft.chests.inventories.PartyMenu;
import com.jamesdpeters.minecraft.chests.lang.Message;
import com.jamesdpeters.minecraft.chests.maventemplates.BuildConstants;
import com.jamesdpeters.minecraft.chests.misc.Messages;
import com.jamesdpeters.minecraft.chests.misc.Permissions;
import com.jamesdpeters.minecraft.chests.misc.Utils;
import com.jamesdpeters.minecraft.chests.party.PartyUtils;
import com.jamesdpeters.minecraft.chests.serialize.Config;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
@ -17,6 +24,8 @@ public class ChestsPlusPlusCommand extends ServerCommand {
private enum OPTIONS {
VERSION("/chestsplusplus version", "Display the current version of the plugin."),
PARTY("/chestsplusplus party <create/delete/invite/remove-member/list>", "Create, delete or manage members of your party"),
PARTY_MENU("/chestsplusplus party <create/delete/invite/remove-member/list>", "Create, delete or manage members of your party"),
RELOAD("/chestsplusplus reload", "Reloads the plugin.");
String description, commandHelp;
@ -45,6 +54,11 @@ public class ChestsPlusPlusCommand extends ServerCommand {
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
sender.sendMessage("Only a player can use this command");
return false;
}
Player player = (Player) sender;
if (args != null && args.length > 0) {
switch (OPTIONS.valueOf(args[0].toUpperCase())) {
case VERSION:
@ -58,6 +72,73 @@ public class ChestsPlusPlusCommand extends ServerCommand {
ChestsPlusPlus.PLUGIN.onEnable();
return true;
case PARTY_MENU:
PartyMenu.getMenu(player).getMenu().open(player);
return true;
case PARTY:
if (args.length > 1) {
if (sender.hasPermission(Permissions.PARTY_ACCEPT_INVITE)) {
if (args[1].toLowerCase().equals("accept-invite")) {
PartyUtils.acceptInvite(player);
return true;
}
} else {
Messages.NO_PERMISSION(player);
return true;
}
if (args[1].toLowerCase().equals("list")) {
// TODO Print list of owned parties.
return true;
}
}
if (args.length > 2) {
if(sender.hasPermission(Permissions.PARTY_CREATE)){
if (args[1].toLowerCase().equals("create")){
String partyName = args[2];
boolean result = PartyUtils.createParty(player, partyName);
if (result){
sender.sendMessage(ChatColor.GREEN+Message.PARTY_CREATED.getString(ChatColor.WHITE+partyName+ChatColor.GREEN));
} else {
sender.sendMessage(ChatColor.RED+Message.PARTY_ALREADY_EXISTS.getString(ChatColor.WHITE+partyName+ChatColor.RED));
}
return true;
}
if (args[1].toLowerCase().equals("delete")){
String partyName = args[2];
boolean result = PartyUtils.deleteParty(player, partyName);
if (result){
sender.sendMessage(ChatColor.GREEN+Message.PARTY_DELETED.getString(ChatColor.WHITE+partyName+ChatColor.GREEN));
} else {
sender.sendMessage(ChatColor.RED+Message.PARTY_DOESNT_EXIST.getString(ChatColor.WHITE+partyName+ChatColor.RED));
}
return true;
}
} else {
Messages.NO_PERMISSION(player);
return true;
}
if (args.length > 3) {
if (sender.hasPermission(Permissions.PARTY_INVITE)) {
if (args[1].toLowerCase().equals("invite")) {
String partyName = args[2];
String playerToInvite = args[3];
PartyUtils.invitePlayer(player, Bukkit.getOfflinePlayer(playerToInvite), partyName);
return true;
}
} else {
Messages.NO_PERMISSION(player);
return true;
}
if (args[1].toLowerCase().equals("remove-member")) {
String partyName = args[2];
String playerToInvite = args[3];
PartyUtils.removePlayer(player, Bukkit.getOfflinePlayer(playerToInvite), partyName);
return true;
}
}
}
default:
for (ChestsPlusPlusCommand.OPTIONS option : ChestsPlusPlusCommand.OPTIONS.values()) {
sender.sendMessage(ChatColor.RED + option.commandHelp);
@ -72,26 +153,44 @@ public class ChestsPlusPlusCommand extends ServerCommand {
@Override
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
if ((sender instanceof Player)) {
Player player = (Player) sender;
if (args.length == 1) {
return OPTIONS.valuesList;
}
if (args.length == 2) {
try {
switch (OPTIONS.valueOf(args[0].toUpperCase())) {
case PARTY:
return Stream.of("create", "invite", "delete", "remove-member", "accept-invite", "list").filter(s -> s.contains(args[1])).collect(Collectors.toList());
}
} catch (IllegalArgumentException ignored) {
}
}
if (args.length == 3) {
try {
switch (OPTIONS.valueOf(args[0].toUpperCase())) {
case PARTY: {
String arg = args[1];
if (arg.equals("delete") || arg.equals("invite") || arg.equals("remove-member")) {
List<String> strings = PartyUtils.getPlayerPartyStorage(player).getOwnedPartiesAsStrings();
return Utils.filterList(strings, args[2]);
}
}
}
} catch (IllegalArgumentException ignored) {
}
}
if (args.length == 4) {
try {
switch (OPTIONS.valueOf(args[0].toUpperCase())) {
case PARTY: {
String arg = args[2];
if (arg.equals("invite") || arg.equals("remove-member")) {
return Utils.filterList(Utils.getAllPlayers(), args[3]);
}
}
}
} catch (IllegalArgumentException ignored) {
}
}

View File

@ -20,10 +20,11 @@ import java.util.List;
public class ChestLinkMenu implements InventoryProvider {
public static HashMap<Player, SmartInventory> menus;
public static HashMap<Player, ChestLinkMenu> menus;
private final Collection<ChestLinkStorage> storages;
private final SmartInventory menu;
private int lastPage; // Store the last page the player was on.
private ChestLinkMenu(Player player) {
this.storages = Config.getChestLink().getStorageMap(player.getUniqueId()).values();
@ -34,16 +35,17 @@ public class ChestLinkMenu implements InventoryProvider {
.manager(ChestsPlusPlus.INVENTORY_MANAGER)
.size(6, 9)
.build();
lastPage = 0;
//menu.setInsertable(true);
}
public static SmartInventory getMenu(Player player) {
public static ChestLinkMenu getMenu(Player player) {
if (menus == null) menus = new HashMap<>();
if (menus.containsKey(player)) {
return menus.get(player);
} else {
menus.put(player, new ChestLinkMenu(player).getMenu());
menus.put(player, new ChestLinkMenu(player));
return menus.get(player);
}
}
@ -72,9 +74,23 @@ public class ChestLinkMenu implements InventoryProvider {
}
contents.set(5, 2, ClickableItem.from(Utils.getNamedItem(new ItemStack(Material.ARROW), "Previous"),
e -> menu.open(player, pagination.previous().getPage())));
e -> {
lastPage = pagination.previous().getPage();
menu.open(player, lastPage);
}));
contents.set(5, 6, ClickableItem.from(Utils.getNamedItem(new ItemStack(Material.ARROW), "Next"),
e -> menu.open(player, pagination.next().getPage())));
e -> {
lastPage = pagination.next().getPage();
menu.open(player, lastPage);
}));
}
public void openLastPage(Player player){
menu.open(player, lastPage);
}
public void open(Player player){
menu.open(player);
}
@Override

View File

@ -0,0 +1,73 @@
package com.jamesdpeters.minecraft.chests.inventories;
import com.jamesdpeters.minecraft.chests.ChestsPlusPlus;
import com.jamesdpeters.minecraft.chests.misc.Utils;
import com.jamesdpeters.minecraft.chests.serialize.Config;
import com.jamesdpeters.minecraft.chests.storage.chestlink.ChestLinkStorage;
import fr.minuskube.inv.ClickableItem;
import fr.minuskube.inv.SmartInventory;
import fr.minuskube.inv.content.InventoryContents;
import fr.minuskube.inv.content.InventoryProvider;
import fr.minuskube.inv.content.Pagination;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
public class PartyMenu implements InventoryProvider {
public static HashMap<Player, PartyMenu> menus;
private final SmartInventory menu;
private ClickableItem CREATE = ClickableItem.from(Utils.getNamedItem(new ItemStack(Material.ANVIL), "Create a Party"), itemClickData -> {itemClickData.getPlayer().sendMessage("CREATE");});
private ClickableItem INVITE = ClickableItem.from(Utils.getNamedItem(new ItemStack(Material.WRITABLE_BOOK), "Invite a Player to a Party"), itemClickData -> {itemClickData.getPlayer().sendMessage("INVITE");});
private ClickableItem REMOVE_PLAYER = ClickableItem.from(Utils.getNamedItem(new ItemStack(Material.SKELETON_SKULL), "Remove a Player from a Party"), itemClickData -> {itemClickData.getPlayer().sendMessage("INVITE");});
private ClickableItem LIST = ClickableItem.from(Utils.getNamedItem(new ItemStack(Material.MAP), "List all your parties"), itemClickData -> {itemClickData.getPlayer().sendMessage("LIST");});
private ClickableItem DELETE = ClickableItem.from(Utils.getNamedItem(new ItemStack(Material.BARRIER), "Delete a Party"), itemClickData -> {itemClickData.getPlayer().sendMessage("DELETE");});
private List<ClickableItem> itemList = Arrays.asList(CREATE, INVITE, LIST, DELETE);
private PartyMenu() {
menu = SmartInventory.builder()
.id("partyMenu")
.title("Party Menu")
.provider(this)
.manager(ChestsPlusPlus.INVENTORY_MANAGER)
.size(3, 9)
.build();
//menu.setInsertable(true);
}
public static PartyMenu getMenu(Player player) {
if (menus == null) menus = new HashMap<>();
if (!menus.containsKey(player)) {
menus.put(player, new PartyMenu());
}
return menus.get(player);
}
@Override
public void init(Player player, InventoryContents contents) {
contents.fillBorders(ClickableItem.empty(Utils.getNamedItem(new ItemStack(Material.GRAY_STAINED_GLASS_PANE), " ")));
for (ClickableItem item : itemList) {
contents.add(item);
}
}
@Override
public void update(Player player, InventoryContents contents) {
}
public SmartInventory getMenu() {
return menu;
}
}

View File

@ -1,8 +1,11 @@
package com.jamesdpeters.minecraft.chests.lang;
import org.bukkit.ChatColor;
import java.text.MessageFormat;
public enum Message {
//Messages.java
CHEST_HAD_OVERFLOW("Chest item's wouldn't all fit into ChestLink!"),
MUST_HOLD_SIGN("You must be holding a sign to do that!"),
@ -67,7 +70,18 @@ public enum Message {
ITEM_FRAME_FILTER_DEFAULT("ItemFrame is in default filtering mode. Rotate Item Frame to change mode!"),
ITEM_FRAME_FILTER_ALL_TYPES("ItemFrame now filters all types of this item! e.g Enchanted Books."),
ITEM_FRAME_FILTER_DENY("ItemFrame now prevents this item from being accepted in the hopper!"),
ITEM_FRAME_FILTER_DENY_ALL_TYPES("ItemFrame now prevents all types of this item from being accepted in the hopper! e.g Enchanted Books.");
ITEM_FRAME_FILTER_DENY_ALL_TYPES("ItemFrame now prevents all types of this item from being accepted in the hopper! e.g Enchanted Books."),
//Party
PARTY_CREATED("Party {0} has been created!", Tag.PARTY_NAME),
PARTY_DELETED("Party {0} has been deleted!", Tag.PARTY_NAME),
PARTY_ALREADY_EXISTS("Party {0} already exists, unable to create it!", Tag.PARTY_NAME),
PARTY_DOESNT_EXIST("The party {0} doesn't exist!", Tag.PARTY_NAME),
PARTY_INVITE("You have been invited to join {0}''s party: {1}", Tag.PLAYER_NAME, Tag.PARTY_NAME),
PARTY_INVITE_OWNER("You have invited {0} to join your party: {1}", Tag.PLAYER_NAME, Tag.PARTY_NAME),
PARTY_JOINED("You have joined {0}''s party: {1}", Tag.PLAYER_NAME, Tag.PARTY_NAME),
PARTY_NO_INVITE("You currently have no pending party invites!"),
PARTY_ACCEPT_INVITE("Use "+ ChatColor.GREEN+ChatColor.BOLD+"/chestsplusplus party accept-invite"+ChatColor.RESET+" or "+ ChatColor.GREEN+ChatColor.BOLD+"'/c++ party accept-invite'"+ChatColor.RESET+" to accept the invite!");
String message;

View File

@ -1,6 +1,7 @@
package com.jamesdpeters.minecraft.chests.lang;
public enum Tag {
PARTY_NAME,
STORAGE_IDENTIFIER,
SORT_METHOD,
PLAYER_NAME,

View File

@ -14,4 +14,7 @@ public class Permissions {
public static final String AUTOCRAFT_OPEN_REMOTE = "chestlink.autocraft.remote-open";
public static final String AUTOCRAFT_ADD = "chestlink.autocraft.add";
public static final String AUTOCRAFT_REMOVE = "chestlink.autocraft.remove";
public static final String PARTY_CREATE = "chestslink.party.create";
public static final String PARTY_INVITE = "chestlink.party.invite";
public static final String PARTY_ACCEPT_INVITE = "chestlink.party.accept_invite";
}

View File

@ -0,0 +1,43 @@
package com.jamesdpeters.minecraft.chests.party;
import com.jamesdpeters.minecraft.chests.lang.Message;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
public class PartyInvite {
OfflinePlayer owner, player;
PlayerParty party;
boolean pending;
public PartyInvite(OfflinePlayer owner, OfflinePlayer player, PlayerParty party) {
this.owner = owner;
this.player = player;
this.party = party;
}
public void sendInvite() {
Player onlinePlayer = player.getPlayer();
if(onlinePlayer != null) {
onlinePlayer.sendMessage(ChatColor.GREEN+Message.PARTY_INVITE.getString(ChatColor.WHITE+player.getName()+ChatColor.GREEN, ChatColor.WHITE+party.getPartyName()+ChatColor.GREEN));
onlinePlayer.sendMessage(Message.PARTY_ACCEPT_INVITE.getString());
}
Player onlineOwner = owner.getPlayer();
if (onlineOwner != null){
onlineOwner.sendMessage(ChatColor.GREEN+Message.PARTY_INVITE_OWNER.getString(ChatColor.WHITE+player.getName()+ChatColor.GREEN, ChatColor.WHITE+party.getPartyName()+ChatColor.GREEN));
}
pending = true;
}
public void acceptInvite(){
if (pending){
party.addMember(player);
Player onlinePlayer = player.getPlayer();
if (onlinePlayer != null){
onlinePlayer.sendMessage(ChatColor.GREEN+Message.PARTY_JOINED.getString(ChatColor.WHITE+owner.getName()+ChatColor.GREEN, ChatColor.WHITE+party.getPartyName()+ChatColor.GREEN));
}
pending = false;
}
}
}

View File

@ -0,0 +1,125 @@
package com.jamesdpeters.minecraft.chests.party;
import com.jamesdpeters.minecraft.chests.lang.Message;
import com.jamesdpeters.minecraft.chests.serialize.Config;
import org.bukkit.ChatColor;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.UUID;
public class PartyUtils {
public enum PARTY_STATUS {
PARTY_ALREADY_EXISTS,
PARTY_CREATED
}
// Stores the last party invite sent to this player.
private static HashMap<UUID, PartyInvite> latestPartyInvite = new HashMap<>();
/**
* Invites a player to the owners given party. The last pending invite is overwritten.
* @param owner
* @param playerToInvite
* @param partyName
*/
public static void invitePlayer(OfflinePlayer owner, OfflinePlayer playerToInvite, String partyName){
PlayerPartyStorage storage = getPlayerPartyStorage(owner);
PlayerParty party = storage.getOwnedParties().get(partyName);
if (party == null){
Player onlineOwner = owner.getPlayer();
if(onlineOwner != null) {
onlineOwner.sendMessage(Message.PARTY_DOESNT_EXIST.getString(partyName));
}
return;
}
PartyInvite invite = new PartyInvite(owner, playerToInvite, storage.getOwnedParties().get(partyName));
latestPartyInvite.put(playerToInvite.getUniqueId(), invite);
invite.sendInvite();
}
public static void removePlayer(OfflinePlayer owner, OfflinePlayer playerToRemove, String partyName){
PlayerPartyStorage storage = getPlayerPartyStorage(owner);
PlayerParty party = storage.getOwnedParties().get(partyName);
if (party == null){
Player onlineOwner = owner.getPlayer();
if(onlineOwner != null) {
onlineOwner.sendMessage(Message.PARTY_DOESNT_EXIST.getString(partyName));
}
return;
}
party.removeMember(playerToRemove);
}
/**
* Accepts the current pending invite for this player.
* @param player
*/
public static void acceptInvite(OfflinePlayer player){
PartyInvite invite = latestPartyInvite.get(player.getUniqueId());
if (invite == null) {
Player onlinePlayer = player.getPlayer();
if (onlinePlayer != null) {
onlinePlayer.sendMessage(Message.PARTY_NO_INVITE.getString());
}
return;
}
invite.acceptInvite();
latestPartyInvite.remove(player.getUniqueId());
}
/**
* Creates a party.
* @param owner
* @param partyName
* @return
*/
public static boolean createParty(OfflinePlayer owner, String partyName){
PlayerPartyStorage storage = getPlayerPartyStorage(owner);
// Check if party already exists.
if (storage.getOwnedParties().containsKey(partyName)) return false;
storage.getOwnedParties().put(partyName, new PlayerParty(owner, partyName));
return true;
}
public static boolean deleteParty(OfflinePlayer owner, String partyName){
HashMap<String, PlayerPartyStorage> map = Config.getStore().parties;
PlayerPartyStorage storage = map.get(owner.getUniqueId().toString());
if (storage == null) {
storage = new PlayerPartyStorage(owner);
map.put(owner.getUniqueId().toString(), storage);
}
// Check if party already exists.
if (!storage.getOwnedParties().containsKey(partyName)) {
Player onlineOwner = owner.getPlayer();
if (onlineOwner != null) {
onlineOwner.sendMessage(ChatColor.RED + Message.PARTY_DOESNT_EXIST.getString(partyName));
}
return false;
}
// Remove party
storage.getOwnedParties().remove(partyName);
return true;
}
public static PlayerPartyStorage getPlayerPartyStorage(OfflinePlayer owner) {
HashMap<String, PlayerPartyStorage> map = Config.getStore().parties;
PlayerPartyStorage storage = map.get(owner.getUniqueId().toString());
if (storage == null){
storage = new PlayerPartyStorage(owner);
map.put(owner.getUniqueId().toString(), storage);
}
return storage;
}
}

View File

@ -0,0 +1,89 @@
package com.jamesdpeters.minecraft.chests.party;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.SerializableAs;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SerializableAs("PlayerParty")
public class PlayerParty implements ConfigurationSerializable {
private OfflinePlayer owner;
private UUID ownerUUID;
private String partyName;
private List<OfflinePlayer> members;
private ArrayList<String> memberUUIDs;
public PlayerParty(OfflinePlayer owner, String partyName) {
this.owner = owner;
this.ownerUUID = owner.getUniqueId();
this.partyName = partyName;
this.members = new ArrayList<>();
}
@SuppressWarnings("unchecked")
public PlayerParty(Map<String, Object> map){
ownerUUID = UUID.fromString((String) map.get("owner"));
owner = Bukkit.getOfflinePlayer(ownerUUID);
partyName = (String) map.get("partyName");
Object o = map.get("members");
if (o != null) {
memberUUIDs = (ArrayList<String>) o;
members = new ArrayList<>();
for (String uuid : memberUUIDs){
members.add(Bukkit.getOfflinePlayer(UUID.fromString(uuid)));
}
}
}
@Override
public Map<String, Object> serialize() {
HashMap<String, Object> map = new LinkedHashMap<>();
map.put("owner", owner.getUniqueId().toString());
map.put("partyName", partyName);
memberUUIDs = new ArrayList<>();
members.forEach(player -> memberUUIDs.add(player.getUniqueId().toString()));
map.put("members", memberUUIDs);
return map;
}
public OfflinePlayer getOwner() {
return owner;
}
public String getPartyName() {
return partyName;
}
public List<OfflinePlayer> getMembers() {
return members;
}
public void addMember(OfflinePlayer player) {
if (members == null){
members = new ArrayList<>();
}
members.add(player);
}
public void removeMember(OfflinePlayer player) {
if (members != null) members.remove(player);
}
public boolean isMember(OfflinePlayer player) {
return getMembers().stream().anyMatch(p -> p.getUniqueId().equals(player.getUniqueId()));
}
}

View File

@ -0,0 +1,75 @@
package com.jamesdpeters.minecraft.chests.party;
import com.jamesdpeters.minecraft.chests.serialize.Config;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.SerializableAs;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@SerializableAs("PlayerPartyStorage")
public class PlayerPartyStorage implements ConfigurationSerializable {
private OfflinePlayer owner;
private HashMap<String, PlayerParty> ownedParties;
public PlayerPartyStorage(OfflinePlayer owner){
this.owner = owner;
this.ownedParties = new HashMap<>();
}
@SuppressWarnings("unchecked")
public PlayerPartyStorage(Map<String, Object> map){
UUID ownerUUID = UUID.fromString((String) map.get("owner"));
owner = Bukkit.getOfflinePlayer(ownerUUID);
ownedParties = (HashMap<String, PlayerParty>) map.get("ownedParties");
if (ownedParties == null) ownedParties = new HashMap<>();
}
@Override
public Map<String, Object> serialize() {
HashMap<String, Object> map = new LinkedHashMap<>();
map.put("owner", owner.getUniqueId().toString());
map.put("ownedParties", ownedParties);
return map;
}
/**
* Checks the owners parties to see if the given player is a member.
*/
public static boolean doPlayersShareParty(OfflinePlayer owner, OfflinePlayer player){
PlayerPartyStorage storage = Config.getStore().parties.get(owner.getUniqueId().toString());
if (storage != null){
for (PlayerParty ownedParty : storage.ownedParties.values()) {
if (ownedParty.getMembers().contains(player)) return true;
}
}
return false;
}
public OfflinePlayer getOwner() {
return owner;
}
public HashMap<String, PlayerParty> getOwnedParties() {
return ownedParties;
}
public Collection<PlayerParty> getOwnedPartiesCollection() {
return ownedParties.values();
}
public List<String> getOwnedPartiesAsStrings(){
List<String> strings = new ArrayList<>();
ownedParties.values().forEach(party -> strings.add(party.getPartyName()));
return strings;
}
}

View File

@ -1,5 +1,6 @@
package com.jamesdpeters.minecraft.chests.serialize;
import com.jamesdpeters.minecraft.chests.party.PlayerPartyStorage;
import com.jamesdpeters.minecraft.chests.storage.autocraft.AutoCraftingStorage;
import com.jamesdpeters.minecraft.chests.storage.chestlink.ChestLinkStorage;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
@ -15,12 +16,14 @@ public class ConfigStorage implements ConfigurationSerializable {
public HashMap<String, HashMap<String, ChestLinkStorage>> chests;
public HashMap<String, HashMap<String, AutoCraftingStorage>> autocraftingtables;
public HashMap<String, PlayerPartyStorage> parties;
@Override
public Map<String, Object> serialize() {
LinkedHashMap<String, Object> hashMap = new LinkedHashMap<>();
hashMap.put("chests", chests);
hashMap.put("autocraftingtables", autocraftingtables);
hashMap.put("parties", parties);
return hashMap;
}
@ -28,25 +31,31 @@ public class ConfigStorage implements ConfigurationSerializable {
public ConfigStorage(Map<String, Object> map) {
//Legacy handling
chests = (HashMap<String, HashMap<String, ChestLinkStorage>>) map.get("chests");
if (chests == null) chests = new HashMap<>();
// }
autocraftingtables = (HashMap<String, HashMap<String, AutoCraftingStorage>>) map.get("autocraftingtables");
if (autocraftingtables == null) autocraftingtables = new HashMap<>();
parties = (HashMap<String, PlayerPartyStorage>) map.get("parties");
if (parties == null) parties = new HashMap<>();
validate();
}
private void validate() {
if (chests != null) chests.forEach((s, invMap) -> invMap.values().removeIf(Objects::isNull));
if (chests != null)
chests.forEach((s, invMap) -> invMap.values().removeIf(Objects::isNull));
if (autocraftingtables != null)
autocraftingtables.forEach((s, craftMap) -> craftMap.values().removeIf(Objects::isNull));
if (parties != null)
parties.values().removeIf(Objects::isNull);
}
public ConfigStorage() {
chests = new HashMap<>();
autocraftingtables = new HashMap<>();
parties = new HashMap<>();
}
}

View File

@ -5,6 +5,7 @@ import com.jamesdpeters.minecraft.chests.api.ApiSpecific;
import com.jamesdpeters.minecraft.chests.misc.Permissions;
import com.jamesdpeters.minecraft.chests.misc.Utils;
import com.jamesdpeters.minecraft.chests.misc.Values;
import com.jamesdpeters.minecraft.chests.party.PlayerPartyStorage;
import com.jamesdpeters.minecraft.chests.serialize.LocationInfo;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@ -350,6 +351,7 @@ public abstract class AbstractStorage implements ConfigurationSerializable {
public boolean hasPermission(OfflinePlayer player) {
if (isPublic) return true;
if (player.getUniqueId().equals(playerUUID)) return true;
if (PlayerPartyStorage.doPlayersShareParty(getOwner(), player)) return true;
if (members != null) {
for (String uuid : members) {
if (player.getUniqueId().toString().equals(uuid)) return true;

View File

@ -5,6 +5,7 @@ import com.jamesdpeters.minecraft.chests.ChestsPlusPlus;
import com.jamesdpeters.minecraft.chests.misc.Messages;
import com.jamesdpeters.minecraft.chests.misc.Utils;
import com.jamesdpeters.minecraft.chests.misc.Values;
import com.jamesdpeters.minecraft.chests.party.PartyUtils;
import com.jamesdpeters.minecraft.chests.serialize.Config;
import com.jamesdpeters.minecraft.chests.serialize.ConfigStorage;
import com.jamesdpeters.minecraft.chests.serialize.LocationInfo;
@ -142,6 +143,8 @@ public abstract class StorageType<T extends AbstractStorage> implements Listener
public List<T> getStorageMemberOf(Player player) {
return getMap().entrySet().stream().flatMap(map -> map.getValue().values().stream().filter(storage -> {
if (PartyUtils.getPlayerPartyStorage(storage.getOwner()).getOwnedPartiesCollection().stream().anyMatch(party -> party.isMember(player))) return true; // Uses party to match.
if (storage.isPublic()) return false;
if (storage.getOwner().getUniqueId().equals(player.getUniqueId())) return false;
if (storage.getMembers() == null) return false;
@ -243,6 +246,7 @@ public abstract class StorageType<T extends AbstractStorage> implements Listener
public T removeBlock(T storage, Location location, boolean hasPickedUp) {
if (storage != null) {
storage.removeLocation(location);
storageCache.remove(location);
if (storage.getLocationsSize() == 0 && !hasPickedUp) {
storage.dropInventory(location);
getStorageMap(storage.getOwner().getUniqueId()).remove(storage.getIdentifier());

View File

@ -151,7 +151,7 @@ public class ChestLinkStorage extends AbstractStorage implements ConfigurationSe
InventoryHolder inventoryHolder = getInventory().getHolder();
if (inventoryHolder instanceof VirtualInventoryHolder) {
((VirtualInventoryHolder) inventoryHolder).setPreviousInventory(() -> {
Bukkit.getScheduler().runTask(ChestsPlusPlus.PLUGIN, () -> ChestLinkMenu.getMenu(player).open(player));
Bukkit.getScheduler().runTask(ChestsPlusPlus.PLUGIN, () -> ChestLinkMenu.getMenu(player).openLastPage(player));
});
}
Utils.openChestInventory(player, getInventory());

View File

@ -4,6 +4,8 @@
# It should be located in the 'lang' folder
# Then in config.yml 'language-file: default' would be renamed to 'language-file: en_US'
# To help contribute to the plugin and provide new language files you can create a pull-request at https://github.com/JamesPeters98/ChestsPlusPlus or join our Discord https://discord.gg/YRs3mP5
PARTY_CREATED=Party {party_name} has been created\!
PARTY_DELETED=Party {party_name} has been deleted\!
COMMAND_CHESTLINK_LIST=Lists all ChestLinks that you own\!
COMMAND_MEMBER=Add, remove or list members of a group
COMMAND_AUTOCRAFT_LIST=Lists all AutoCraft groups that you own\!
@ -20,6 +22,7 @@ SORT=Sort method for {storage_identifier} has been set to {sort_method}
ITEM_FRAME_FILTER_DENY_ALL_TYPES=ItemFrame now prevents all types of this item from being accepted in the hopper\! e.g Enchanted Books.
NO_PERMISSION=You don't have permission to do that\!
COMMAND_CHESTLINK_SETPUBLIC=Set a ChestLink to be accessible by anyone.
PARTY_NO_INVITE=You currently have no pending party invites\!
CURRENT_MEMBERS=Current Members\: {player_list}
CANNOT_RENAME_GROUP_DOESNT_EXIST=Error renaming group\! {storage_identifier} doesn't exist\!
STORAGE_ADDED=Successfully added {storage_type} to group\: {storage_group} for {player_name}
@ -32,6 +35,7 @@ LIST_MEMBERS_OF_GROUP=Members of {storage_type} group {storage_identifier}\: {pl
REMOVE_MEMBER_FROM_ALL=Successfully removed {player_name} from all {storage_type} groups
COMMAND_CHESTLINK_RENAME=Rename a ChestLink.
STORAGE_REMOVED=Successfully removed {storage_type} from group\: {storage_group} for {player_name}
PARTY_INVITE=You have been invited to join {player_name}''s party\: {party_name}
COMMAND_CHESTLINK_REMOVE=Delete a ChestLink and drop its inventory at your feet\!
COMMAND_CHESTLINK_MENU=Open the ChestLink menu to display all groups\!
GROUP_DOESNT_EXIST={storage_group} isn't a valid {storage_type} group to remove\!
@ -41,11 +45,14 @@ CANNOT_RENAME_GROUP_ALREADY_EXISTS=Error renaming group\! {storage_identifier} a
NO_ADDITIONAL_MEMBERS=There are no additional members in the group\: {storage_identifier}
CHEST_HAD_OVERFLOW=Chest item's wouldn't all fit into ChestLink\!
COMMAND_AUTOCRAFT_ADD=Create/add a Crafting Table to an AutoCraft group
PARTY_ALREADY_EXISTS=Party {party_name} already exists, unable to create it\!
MUST_HOLD_SIGN=You must be holding a sign to do that\!
COMMAND_CHESTLINK_ADD=Create/add a chest to a ChestLink group
COMMAND_HELP=List of commands and their uses\!
UNABLE_TO_ADD_MEMBER_TO_ALL=Unable to add player {player_name} to {storage_type}\!
PARTY_JOINED=You have joined {player_name}''s party\: {party_name}
ITEM_FRAME_FILTER_ALL_TYPES=ItemFrame now filters all types of this item\! e.g Enchanted Books.
PARTY_INVITE_OWNER=You have invited {player_name} to join your party\: {party_name}
COMMAND_AUTOCRAFT_RENAME=Rename an AutoCraft group.
MUST_LOOK_AT_CRAFTING_TABLE=You must be looking at the Crafting Table you want to AutoCraft with\!
COMMAND_AUTOCRAFT_REMOVE=Delete an AutoCraft group and drop all the Crafting Tables\!
@ -53,4 +60,6 @@ UNABLE_TO_REMOVE_MEMBER=Unable to remove player {player_name} from {storage_type
COMMAND_AUTOCRAFT_SETPUBLIC=Set an AutoCraft group to be accessible by anyone.
ALREADY_PART_OF_GROUP=This {storage_type} is already a part of a group\!
INVALID_ID=Invalid {storage_type} ID\! Must not contain a colon '\:' unless you are referencing another players group that you are a member of
PARTY_ACCEPT_INVITE=Use §a§l/chestsplusplus party accept-invite§r or §a§l'/c++ party accept-invite'§r to accept the invite\!
FOUND_UNLINKED_STORAGE=This {storage_type} wasn't linked to your system\! It has been added under the {storage_identifier} group\!
PARTY_DOESNT_EXIST=The party {party_name} doesn't exist\!