package tc.oc.pgm.portals; import org.bukkit.EntityLocation; import org.bukkit.Sound; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerTeleportEvent; import tc.oc.commons.bukkit.chat.BukkitSound; import tc.oc.pgm.features.FeatureDefinition; import tc.oc.pgm.features.FeatureInfo; import tc.oc.pgm.filters.Filter; import tc.oc.pgm.filters.FilterMatchModule; import tc.oc.pgm.match.Match; import tc.oc.pgm.match.MatchPlayer; @FeatureInfo(name = "portal") public interface Portal extends FeatureDefinition {} class PortalImpl extends FeatureDefinition.Impl implements Portal { private static final BukkitSound USE_SOUND = new BukkitSound(Sound.ENTITY_ENDERMEN_TELEPORT, 1f, 1f); private final @Inspect Filter trigger; private final @Inspect Filter participantFilter, observerFilter; private final @Inspect PortalTransform transform; private final @Inspect boolean sound; private final @Inspect boolean smooth; public PortalImpl(Filter trigger, PortalTransform transform, Filter participantFilter, Filter observerFilter, boolean sound, boolean smooth) { this.transform = transform; this.trigger = trigger; this.participantFilter = participantFilter; this.observerFilter = observerFilter; this.sound = sound; this.smooth = smooth; } private boolean canUse(MatchPlayer player) { return (player.isParticipating() ? participantFilter : observerFilter).query(player).isAllowed(); } @Override public void load(Match match) { final FilterMatchModule fmm = match.needMatchModule(FilterMatchModule.class); fmm.onRise(MatchPlayer.class, trigger, player -> { if(canUse(player) && !player.facet(PortalPlayerFacet.class).teleport()) { teleportPlayer(player, player.getBukkit().getEntityLocation()); } }); } private void teleportPlayer(final MatchPlayer player, final EntityLocation from) { final EntityLocation to = transform.apply(from); final Player bukkit = player.getBukkit(); final Match match = player.getMatch(); if(sound) { // Don't play the sound for the teleporting player at the entering portal, // because they will instantly teleport away and hear the one at the exit. for(MatchPlayer listener : match.getPlayers()) { if(!player.equals(listener) && listener.getBukkit().canSee(player.getBukkit())) { listener.playSound(USE_SOUND, from); } } } // Use ENDER_PEARL as the cause so that this teleport is treated // as an "in-game" movement if(smooth) { bukkit.teleportRelative(to.toVector().subtract(from.toVector()), to.getYaw() - from.getYaw(), to.getPitch() - from.getPitch(), PlayerTeleportEvent.TeleportCause.ENDER_PEARL); } else { bukkit.teleport(to, PlayerTeleportEvent.TeleportCause.ENDER_PEARL); } // Reset fall distance bukkit.setFallDistance(0); if(sound) { for(MatchPlayer listener : match.getPlayers()) { if(listener.getBukkit().canSee(player.getBukkit())) { listener.playSound(USE_SOUND, to); } } } } }