Skip to content
This repository has been archived by the owner on Nov 25, 2019. It is now read-only.

Team Chest Mutation #90

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,10 @@ mutation.type.tools = Tools
mutation.type.tools.desc = enchanted diamond tools
mutation.type.apocalypse = Apocalypse
mutation.type.apocalypse.desc = mob spawning chaos
mutation.type.teamchest = Team Chest
mutation.type.teamchest.desc = access a shared team chest
mutation.type.teamchest.item_name = Team Chest
mutation.type.teamchest.item_lore = Right click to access an inventory shared by the team.

tnt.license.info.alreadyHas = You have a TNT license. You can surrender your license by typing {0}
tnt.license.info.doesNotHave = You do not have a TNT license. You can request one by typing {0}
Expand Down
3 changes: 2 additions & 1 deletion PGM/src/main/java/tc/oc/pgm/mutation/Mutation.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ public enum Mutation {
BREAD (BreadMutation.class, Material.BREAD),
BOAT (BoatMutation.class, Material.BOAT, false),
TOOLS (ToolsMutation.class, Material.DIAMOND_PICKAXE),
APOCALYPSE (ApocalypseMutation.class, Material.NETHER_STAR);
APOCALYPSE (ApocalypseMutation.class, Material.NETHER_STAR),
TEAMCHEST (TeamChestMutation.class, Material.ENDER_CHEST);

public static final String TYPE_KEY = "mutation.type.";
public static final String DESCRIPTION_KEY = ".desc";
Expand Down
139 changes: 139 additions & 0 deletions PGM/src/main/java/tc/oc/pgm/mutation/types/kit/TeamChestMutation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package tc.oc.pgm.mutation.types.kit;

import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import tc.oc.commons.bukkit.inventory.Slot;
import tc.oc.commons.bukkit.item.ItemBuilder;
import tc.oc.pgm.PGMTranslations;
import tc.oc.pgm.kits.ItemKit;
import tc.oc.pgm.kits.Kit;
import tc.oc.pgm.kits.SlotItemKit;
import tc.oc.pgm.match.Match;
import tc.oc.pgm.match.MatchPlayer;
import tc.oc.pgm.match.Party;
import tc.oc.pgm.mutation.types.KitMutation;
import tc.oc.pgm.wool.WoolMatchModule;

import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.WeakHashMap;

public class TeamChestMutation extends KitMutation {
final static Material TOOL_TYPE = Material.ENDER_CHEST;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this extra field?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it is used six times, I believe so. So in the future it may be easy to change it if needed.

final static int CHEST_SIZE = 27;

final Map<Party, Inventory> teamChests = new WeakHashMap<>();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though this is weak, you want to clear this disable()


final Optional<WoolMatchModule> optWools;

public TeamChestMutation(Match match) {
super(match, false);
optWools = match().module(WoolMatchModule.class);
}

@Override
public void enable() {
super.enable();
for (Party party : match().getParties()) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mutation modules are special, because they can be enabled or disabled on the fly. So this logic should go into

@Override
public boolean enable() {
    super.enable();
    for (Party party : match().getParties()) {
         // Rest of implementation
    }
}

You will also have to make sure you implement disable() too.

if (party.isParticipatingType()) {
// Could the chest title be localized properly?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it can, but you'll have to create an inventory view each time a player wishes to view it. See NavigatorInterface.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make this a TODO

teamChests.put(party, match().getServer().createInventory(null, CHEST_SIZE));
}
}
}

@Override
public void disable() {
teamChests.clear();
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remember super.disable()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's best to disable the current class, then the super class.


@Override
public void kits(MatchPlayer player, List<Kit> kits) {
super.kits(player, kits);
kits.add(getKitForPlayer(player));
}

// Open shared inventory instead of placing the chest
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
public void onChestUse(PlayerInteractEvent event) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rule of thumb for player events, very early in your event block you want to convert to a MatchPlayer and depending on the event a Participant.

MatchPlayer player = match.participant(event.getPlayer());
if(!player.isPresent() ||
   !(event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) ||
   event.getItem() == null || event.getItem().getType() != Material.ENDER_CHEST) {
       return;
}

Player bukkitPlayer = event.getPlayer();
Optional<MatchPlayer> optPlayer = match().participant((Entity) bukkitPlayer);
if (!optPlayer.isPresent() ||
!(event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) ||
event.getItem() == null ||
event.getItem().getType() != TOOL_TYPE) {
return;
}

Optional<Inventory> optTeamInventory = getTeamsInventory(bukkitPlayer);
optTeamInventory.ifPresent(teamInventory -> {
event.setCancelled(true);
// If the item is in the off-hand slot, it wont get put back visually for the player without this.
if(event.getHand() == EquipmentSlot.OFF_HAND) event.getActor().updateInventory();
bukkitPlayer.openInventory(teamInventory);
});
}

@EventHandler(priority = EventPriority.LOWEST)
public void onInventoryClick(InventoryClickEvent event) {
Player player = event.getActor();
if (event.getCurrentItem() == null) return;

// No putting blacklisted items (ender chest, possibly wool) into the chest
Optional<Inventory> teamChest = getTeamsInventory(player);
if (teamChest.map(teamInventory -> teamInventory.equals(event.getView().getTopInventory())).orElse(false) &&
isBlacklistedItem(event.getCurrentItem())) {
event.setCancelled(true);
return;
}

// If normal right click, in their inventory, on the chest, then open shared inventory.
getTeamsInventory(player).ifPresent(teamInventory -> {
if (event.getInventory().getType() == InventoryType.CRAFTING &&
event.getCurrentItem().getType() == TOOL_TYPE &&
event.getAction() == InventoryAction.PICKUP_HALF) {
event.setCancelled(true);
// This resets their mouse position annoyingly, but without it items can get stuck in places.
player.closeInventory();
// Prevent visual inconsistencies, specifically off-hand slot
if (event.getSlotType() == InventoryType.SlotType.QUICKBAR) {
player.updateInventory();
}
player.openInventory(teamInventory);
}
});
}

private boolean isBlacklistedItem(ItemStack item) {
return item.getType() == TOOL_TYPE ||
optWools.map(w -> w.isObjectiveWool(item)).orElse(false);
}

private Optional<Inventory> getTeamsInventory(Player bukkitPlayer) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For our needs, would an @nullable possibly be better?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we take in a MatchPlayer instead of a bukkit Player object?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional's are preferred over null values

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Optionals if it makes for cleaner code, if it makes things messier then you don't need to.

return match().participant((Entity) bukkitPlayer)
.map(matchPlayer -> teamChests.get(matchPlayer.getParty()));
}

private Kit getKitForPlayer(MatchPlayer player) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PGMTranslations is legacy. See RenderedItemBuilder.

ItemStack stack = new ItemBuilder(item(TOOL_TYPE))
.name(ChatColor.DARK_PURPLE + PGMTranslations.t("mutation.type.teamchest.item_name", player))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we able to not use PGMTranslations?

Copy link
Author

@DirkyJerky DirkyJerky Jun 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't seem to get it to work yet,
new Component(new TranslatableComponent("mutation.type.teamchest.item_name"), ChatColor.DARK_PURPLE).getText()
doesn't work.

Neither did new Component(ChatColor.DARK_PURPLE).translate("mutation.type.teamchest.item_name").getText()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toLegacyText()

Copy link
Author

@DirkyJerky DirkyJerky Jun 10, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do I get a ComponentRenderContext? That is what I assume I need (Readme says I need it), because nothing is translating it is just showing the translation key.

I can't inject it as I assume that is how it is normally recieved.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mutations don't support injection right now, so using PGMTranslations should be fine.

.lore(ChatColor.DARK_AQUA + PGMTranslations.t("mutation.type.teamchest.item_lore", player))
.get();

ItemKit kit = new SlotItemKit(stack, Slot.Player.forIndex(17));
return kit;
}
}
2 changes: 1 addition & 1 deletion PGM/src/main/java/tc/oc/pgm/wool/WoolMatchModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public class WoolMatchModule extends MatchModule implements Listener {
.collect(Collectors.toImmutableList());
}

private boolean isObjectiveWool(ItemStack stack) {
public boolean isObjectiveWool(ItemStack stack) {
if(stack.getType() == Material.WOOL) {
for(MonumentWool wool : this.wools) {
if(wool.getDefinition().isObjectiveWool(stack)) return true;
Expand Down