Add new mutations

This commit is contained in:
Electroid 2017-03-31 14:30:41 -07:00 committed by GitHub
parent b883ef5799
commit ee06c979b4
62 changed files with 2171 additions and 542 deletions

View File

@ -30,11 +30,7 @@ public interface MatchDoc extends Model {
Collection<String> winning_team_ids();
Collection<String> winning_user_ids();
enum Mutation {
BLITZ, UHC, EXPLOSIVES, NO_FALL, MOBS, STRENGTH, DOUBLE_JUMP, INVISIBILITY, LIGHTNING, RAGE, ELYTRA;
}
Set<Mutation> mutations();
Set<String> mutations();
@Serialize
interface Team extends MapDoc.Team, CompetitorDoc {

View File

@ -138,7 +138,7 @@ public interface ServerDoc {
@Serialize
interface Mutation extends Partial {
Set<MatchDoc.Mutation> queued_mutations();
Set<String> queued_mutations();
}
/**

View File

@ -33,7 +33,5 @@ public class TypeAdaptersManifest extends Manifest {
gson.bindAdapter(new TypeLiteral<Set<MapDoc.Gamemode>>(){})
.to(new TypeLiteral<LenientEnumSetTypeAdapter<MapDoc.Gamemode>>(){});
gson.bindAdapter(new TypeLiteral<Set<MatchDoc.Mutation>>(){})
.to(new TypeLiteral<LenientEnumSetTypeAdapter<MatchDoc.Mutation>>(){});
}
}

View File

@ -279,7 +279,7 @@ public class LocalServerDocument extends StartupServerDocument implements Server
}
@Override
public Set<MatchDoc.Mutation> queued_mutations() {
public Set<String> queued_mutations() {
return mutations != null ? mutations.queued_mutations() : Collections.emptySet();
}
}

View File

@ -90,9 +90,19 @@ command.mutation.enable.later.plural = You have enabled the {0} mutations for th
command.mutation.disable.later.singular = You have disabled the {0} mutation for the next match
command.mutation.disable.later.plural = You have disabled the {0} mutations for the next match
# {0} = command sender
# {1} = mutation name(s)
command.mutation.enable.now.singular = {0} has enabled the {1} mutation
command.mutation.enable.now.plural = {0} has enabled the {1} mutations
command.mutation.disable.now.singular = {0} has disabled the {1} mutation
command.mutation.disable.now.plural = {0} has disabled the {1} mutations
command.mutation.error.mutate = An internal error occured with the '{0}' mutation
command.mutation.error.find = Unable to find mutation named '{0}'
command.mutation.error.enabled = All mutations have already been enabled
command.mutation.error.disabled = All mutations have already been disabled
command.mutation.error.enabled = {0} mutation is already enabled
command.mutation.error.enabled.all = All mutations have already been enabled
command.mutation.error.disabled = {0} mutation is already disabled
command.mutation.error.disabled.all = All mutations have already been disabled
command.mutation.list.current = Current Mutations
command.mutation.list.queued = Queued Mutations
@ -177,28 +187,41 @@ skillRequirement.fail.general = Play on unranked servers to improve your skill a
huddle.instructions = Your team now has {0} to strategize before the match starts
mutation.type.blitz = Blitz
mutation.type.uhc = UHC
mutation.type.explosives = Explosives
mutation.type.no_fall = No Fall
mutation.type.mobs = Mobs
mutation.type.strength = Strength
mutation.type.double_jump = Double Jump
mutation.type.invisibility = Invisibility
mutation.type.lightning = Lightning
mutation.type.rage = Rage
mutation.type.elytra = Elytra
mutation.type.blitz.desc = no respawning
mutation.type.uhc.desc = no natural regeneration
mutation.type.explosives.desc = stronger and more powerful explosions
mutation.type.no_fall.desc = fall all you want
mutation.type.mobs.desc = natural mob spawning
mutation.type.strength.desc = strength potions everywhere
mutation.type.double_jump.desc = super jump powers
mutation.type.invisibility.desc = enemy players cannot be seen
mutation.type.lightning.desc = lightning strikes from the sky
mutation.type.rage = Rage
mutation.type.rage.desc = instant kills
mutation.type.hardcore = Hardcore
mutation.type.hardcore.desc = no natural regeneration
mutation.type.jump = Jump
mutation.type.jump.desc = double jump and no fall
mutation.type.explosive = Explosive
mutation.type.explosive.desc = tnt and fire bows
mutation.type.elytra = Elytra
mutation.type.elytra.desc = fly around with an elytra
mutation.type.projectile = Projectile
mutation.type.projectile.desc = arrow potion effects
mutation.type.enchantment = Enchantment
mutation.type.enchantment.desc = random item enchantments
mutation.type.potion = Potion
mutation.type.potion.desc = random special potions
mutation.type.equestrian = Equestrian
mutation.type.equestrian.desc = ride a custom horse
mutation.type.health = Health
mutation.type.health.desc = double health and gold apples
mutation.type.glow = Glow
mutation.type.glow.desc = glowing effect on all players
mutation.type.stealth = Stealth
mutation.type.stealth.desc = invisibility with no armor
mutation.type.armor = Armor
mutation.type.armor.desc = heavy diamond armor
mutation.type.mobs = Mobs
mutation.type.mobs.desc = mob spawning eggs
mutation.type.lightning = Lightning
mutation.type.lightning.desc = lightning strikes from the sky
mutation.type.bomber = Bomber
mutation.type.bomber.desc = tnt rain
mutation.type.apocalypse = Apocalypse
mutation.type.apocalypse.desc = mob spawning chaos
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}

View File

@ -120,10 +120,10 @@ public class MatchDocument extends AbstractModel implements MatchDoc {
}
@Override
public Set<Mutation> mutations() {
return mutations.map(mmm -> mmm.getHistoricalMutations()
public Set<String> mutations() {
return mutations.map(mmm -> mmm.mutationsHistorical()
.stream()
.map(tc.oc.pgm.mutation.Mutation::toApi)
.map(tc.oc.pgm.mutation.Mutation::name)
.collect(Collectors.toImmutableSet()))
.orElse(ImmutableSet.of());
}

View File

@ -65,7 +65,7 @@ public class BlitzMatchModule extends MatchModule implements Listener, JoinHandl
public BlitzMatchModule(Match match, BlitzConfig config) {
super(match);
this.config = MutationMatchModule.check(match, Mutation.BLITZ) ? new BlitzConfig(1, true) : config;
this.config = match.module(MutationMatchModule.class).get().enabled(Mutation.BLITZ) ? new BlitzConfig(1, true) : config;
this.lifeManager = new LifeManager(this.config.getNumLives());
}

View File

@ -3,6 +3,7 @@ package tc.oc.pgm.damage;
import javax.annotation.Nullable;
import javax.inject.Inject;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
import org.bukkit.block.Block;
@ -36,12 +37,12 @@ public class DisableDamageMatchModule extends MatchModule implements Listener {
this.causes = causes;
}
@Override
public void load() {
super.load();
if(MutationMatchModule.check(match, Mutation.NO_FALL)) {
this.causes.putAll(DamageCause.FALL, Sets.newHashSet(PlayerRelation.values()));
}
public SetMultimap<DamageCause, PlayerRelation> causes() {
return causes;
}
public ImmutableSetMultimap<DamageCause, PlayerRelation> causesImmutable() {
return ImmutableSetMultimap.copyOf(causes());
}
private static DamageCause getBlockDamageCause(Block block) {
@ -59,11 +60,11 @@ public class DisableDamageMatchModule extends MatchModule implements Listener {
}
private boolean canDamage(DamageCause cause, MatchPlayer victim, @Nullable ParticipantState damager) {
return !this.causes.containsEntry(cause, PlayerRelation.get(victim.getParticipantState(), damager));
return !causesImmutable().containsEntry(cause, PlayerRelation.get(victim.getParticipantState(), damager));
}
private boolean canDamage(DamageCause cause, MatchPlayer victim, DamageInfo info) {
return !this.causes.containsEntry(cause, PlayerRelation.get(victim.getParticipantState(), info.getAttacker()));
return !causesImmutable().containsEntry(cause, PlayerRelation.get(victim.getParticipantState(), info.getAttacker()));
}
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)

View File

@ -21,10 +21,23 @@ public class DoubleJumpKit extends Kit.Impl {
this.rechargeInAir = rechargeInAir;
}
public DoubleJumpKit() {
this(true, DEFAULT_POWER, DEFAULT_RECHARGE, true);
}
@Override
public void apply(MatchPlayer player, boolean force, ItemKitApplicator items) {
DoubleJumpMatchModule djmm = player.getMatch().getMatchModule(DoubleJumpMatchModule.class);
if(djmm != null) djmm.setKit(player.getBukkit(), this);
player.getMatch().module(DoubleJumpMatchModule.class).ifPresent(jump -> jump.setKit(player.getBukkit(), this));
}
@Override
public boolean isRemovable() {
return true;
}
@Override
public void remove(MatchPlayer player) {
player.getMatch().module(DoubleJumpMatchModule.class).ifPresent(jump -> jump.setKit(player.getBukkit(), null));
}
public float chargePerTick() {

View File

@ -57,7 +57,7 @@ public class ProjectileTrailMatchModule extends MatchModule implements Listener
return Math.max(0.001, rgb / 255.0);
}
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onProjectileLaunch(ProjectileLaunchEvent event) {
match.player(event.getActor()).ifPresent(shooter -> {
final Projectile projectile = event.getEntity();

View File

@ -15,7 +15,7 @@ public class MatchMutationFilter extends TypedFilter.Impl<IMatchQuery> {
@Override
public boolean matches(IMatchQuery query) {
return query.module(MutationMatchModule.class)
.filter(mmm -> mmm.getActiveMutations().contains(mutation))
.filter(mmm -> mmm.enabled(mutation))
.isPresent();
}
}

View File

@ -1,30 +0,0 @@
package tc.oc.pgm.gamerules;
public enum GameRule {
DO_FIRE_TICK("doFireTick"),
DO_MOB_LOOT("doMobLoot"),
DO_TILE_DROPS("doTileDrops"),
MOB_GRIEFING("mobGriefing"),
NATURAL_REGENERATION("naturalRegeneration"),
DO_DAYLIGHT_CYCLE("doDaylightCycle");
private String value;
GameRule(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
public static GameRule forName(String query) {
for (GameRule gamerule : values()) {
if (gamerule.getValue().equalsIgnoreCase(query)) {
return gamerule;
}
}
return null;
}
}

View File

@ -6,29 +6,38 @@ import com.google.common.collect.ImmutableMap;
import tc.oc.pgm.match.Match;
import tc.oc.pgm.match.MatchModule;
import tc.oc.pgm.mutation.Mutation;
import tc.oc.pgm.mutation.MutationMatchModule;
import tc.oc.pgm.match.Repeatable;
import tc.oc.time.Time;
public class GameRulesMatchModule extends MatchModule {
private final Map<GameRule, Boolean> gameRules;
private final Map<String, String> gameRules;
public GameRulesMatchModule(Match match, Map<GameRule, Boolean> gameRules) {
public GameRulesMatchModule(Match match, Map<String, String> gameRules) {
super(match);
this.gameRules = Preconditions.checkNotNull(gameRules, "gamerules");
if(MutationMatchModule.check(match, Mutation.UHC)) {
this.gameRules.put(GameRule.NATURAL_REGENERATION, Boolean.FALSE);
}
}
@Override
public void load() {
for (Map.Entry<GameRule, Boolean> gameRule : this.gameRules.entrySet()) {
this.match.getWorld().setGameRuleValue(gameRule.getKey().getValue(), gameRule.getValue().toString());
}
update();
}
public ImmutableMap<GameRule, Boolean> getGameRules() {
return ImmutableMap.copyOf(gameRules);
@Repeatable(interval = @Time(seconds = 1))
public void tick() {
update();
}
public void update() {
gameRulesImmutable().forEach((String rule, String val) -> match.getWorld().setGameRuleValue(rule, val));
}
public Map<String, String> gameRules() {
return gameRules;
}
public ImmutableMap<String, String> gameRulesImmutable() {
return ImmutableMap.copyOf(gameRules());
}
}

View File

@ -18,9 +18,9 @@ import tc.oc.pgm.xml.InvalidXMLException;
@ModuleDescription(name="Gamerules", follows = MutationMapModule.class)
public class GameRulesModule implements MapModule, MatchModuleFactory<GameRulesMatchModule> {
private Map<GameRule, Boolean> gameRules;
private Map<String, String> gameRules;
private GameRulesModule(Map<GameRule, Boolean> gamerules) {
private GameRulesModule(Map<String, String> gamerules) {
this.gameRules = gamerules;
}
@ -33,32 +33,32 @@ public class GameRulesModule implements MapModule, MatchModuleFactory<GameRulesM
// ---------------------
public static GameRulesModule parse(MapModuleContext context, Logger logger, Document doc) throws InvalidXMLException {
Map<GameRule, Boolean> gameRules = new HashMap<>();
Map<String, String> gameRules = new HashMap<>();
for (Element gameRulesElement : doc.getRootElement().getChildren("gamerules")) {
for (Element gameRuleElement : gameRulesElement.getChildren()) {
GameRule gameRule = GameRule.forName(gameRuleElement.getName());
String gameRule = gameRuleElement.getName();
String value = gameRuleElement.getValue();
if (gameRule == null) {
if(gameRule == null) {
throw new InvalidXMLException(gameRuleElement.getName() + " is not a valid gamerule", gameRuleElement);
}
if (value == null) {
throw new InvalidXMLException("Missing value for gamerule " + gameRule.getValue(), gameRuleElement);
if(value == null) {
throw new InvalidXMLException("Missing value for gamerule " + gameRule, gameRuleElement);
} else if (!(value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false"))) {
throw new InvalidXMLException(gameRuleElement.getValue() + " is not a valid gamerule value", gameRuleElement);
}
if (gameRules.containsKey(gameRule)){
throw new InvalidXMLException(gameRule.getValue() + " has already been specified", gameRuleElement);
if(gameRules.containsKey(gameRule)){
throw new InvalidXMLException(gameRule + " has already been specified", gameRuleElement);
}
gameRules.put(gameRule, Boolean.valueOf(value));
gameRules.put(gameRule, value);
}
}
return new GameRulesModule(gameRules);
}
public ImmutableMap<GameRule, Boolean> getGameRules() {
public ImmutableMap<String, String> getGameRules() {
return ImmutableMap.copyOf(this.gameRules);
}

View File

@ -3,6 +3,8 @@ package tc.oc.pgm.killreward;
import com.google.common.collect.ImmutableList;
import org.bukkit.inventory.ItemStack;
import tc.oc.pgm.filters.Filter;
import tc.oc.pgm.filters.matcher.StaticFilter;
import tc.oc.pgm.kits.ItemKit;
import tc.oc.pgm.kits.Kit;
public class KillReward {
@ -15,4 +17,8 @@ public class KillReward {
this.filter = filter;
this.kit = kit;
}
public KillReward(ItemKit kit) {
this(ImmutableList.of(kit.item()), StaticFilter.ALLOW, kit);
}
}

View File

@ -2,11 +2,10 @@ package tc.oc.pgm.killreward;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import com.google.common.base.Predicate;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
import org.bukkit.event.Event;
@ -27,34 +26,38 @@ import tc.oc.pgm.tracker.damage.DamageInfo;
@ListenerScope(MatchScope.RUNNING)
public class KillRewardMatchModule extends MatchModule implements Listener {
protected final ImmutableList<KillReward> killRewards;
protected final Multimap<MatchPlayer, KillReward> deadPlayerRewards = ArrayListMultimap.create();
private final List<KillReward> killRewards;
private final Multimap<MatchPlayer, KillReward> deadPlayerRewards = ArrayListMultimap.create();
public KillRewardMatchModule(Match match, List<KillReward> killRewards) {
super(match);
this.killRewards = ImmutableList.copyOf(killRewards);
this.killRewards = killRewards;
}
private Collection<KillReward> getRewards(@Nullable Event event, ParticipantState victim, DamageInfo damageInfo) {
public List<KillReward> rewards() {
return killRewards;
}
public ImmutableList<KillReward> rewardsImmutable() {
return ImmutableList.copyOf(killRewards);
}
public List<KillReward> rewards(@Nullable Event event, ParticipantState victim, DamageInfo damageInfo) {
final DamageQuery query = DamageQuery.attackerDefault(event, victim, damageInfo);
return Collections2.filter(killRewards, new Predicate<KillReward>() {
@Override
public boolean apply(KillReward killReward) {
return killReward.filter.query(query).isAllowed();
}
});
return rewardsImmutable().stream().filter(reward -> reward.filter.query(query).isAllowed()).collect(Collectors.toList());
}
private Collection<KillReward> getRewards(MatchPlayerDeathEvent event) {
return getRewards(event, event.getVictim().getParticipantState(), event.getDamageInfo());
public List<KillReward> rewards(MatchPlayerDeathEvent event) {
return rewards(event, event.getVictim().getParticipantState(), event.getDamageInfo());
}
private void giveRewards(MatchPlayer killer, Collection<KillReward> rewards) {
for(KillReward reward : rewards) {
public void giveRewards(MatchPlayer killer, Collection<KillReward> rewards) {
rewards.forEach(reward -> {
// Apply kit first so it can not override reward items
reward.kit.apply(killer);
reward.items.forEach(stack -> ItemKitApplicator.fireEventAndTransfer(killer, stack));
}
});
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
@ -63,7 +66,7 @@ public class KillRewardMatchModule extends MatchModule implements Listener {
MatchPlayer killer = event.getOnlineKiller();
if(killer == null) return;
Collection<KillReward> rewards = getRewards(event);
List<KillReward> rewards = rewards(event);
if(killer.isDead()) {
// If a player earns a KW while dead, give it to them when they respawn. Rationale: If they click respawn
@ -87,4 +90,5 @@ public class KillRewardMatchModule extends MatchModule implements Listener {
public void onPartyChange(PlayerPartyChangeEvent event) {
deadPlayerRewards.removeAll(event.getPlayer());
}
}

View File

@ -1,5 +1,6 @@
package tc.oc.pgm.killreward;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.logging.Logger;
@ -27,10 +28,10 @@ import tc.oc.pgm.xml.InvalidXMLException;
@ModuleDescription(name="Kill Reward")
public class KillRewardModule implements MapModule, MatchModuleFactory<KillRewardMatchModule> {
protected final ImmutableList<KillReward> rewards;
protected final List<KillReward> rewards;
public KillRewardModule(List<KillReward> rewards) {
this.rewards = ImmutableList.copyOf(rewards);
this.rewards = rewards;
}
@Override
@ -43,7 +44,7 @@ public class KillRewardModule implements MapModule, MatchModuleFactory<KillRewar
// ---------------------
public static KillRewardModule parse(MapModuleContext context, Logger logger, Document doc) throws InvalidXMLException {
ImmutableList.Builder<KillReward> rewards = ImmutableList.builder();
List<KillReward> rewards = new ArrayList<>();
final ItemParser itemParser = context.needModule(ItemParser.class);
final Optional<ItemModifyModule> itemModifier = context.module(ItemModifyModule.class);
@ -61,11 +62,6 @@ public class KillRewardModule implements MapModule, MatchModuleFactory<KillRewar
rewards.add(new KillReward(items.build(), filter, kit));
}
ImmutableList<KillReward> list = rewards.build();
if(list.isEmpty()) {
return null;
} else {
return new KillRewardModule(list);
}
return new KillRewardModule(rewards);
}
}

View File

@ -1,8 +1,15 @@
package tc.oc.pgm.kits;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import tc.oc.commons.bukkit.inventory.Slot;
import tc.oc.pgm.match.MatchPlayer;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
public class FreeItemKit extends BaseItemKit {
protected final ItemStack item;
@ -20,4 +27,36 @@ public class FreeItemKit extends BaseItemKit {
public void apply(MatchPlayer player, boolean force, ItemKitApplicator items) {
items.add(item);
}
@Override
public boolean isRemovable() {
return true;
}
@Override
public void remove(MatchPlayer player) {
int left = item.getAmount();
PlayerInventory inv = player.getInventory();
for(Map.Entry<Slot.Player, Optional<ItemStack>> entry : Slot.Player.player()
.collect(Collectors.toMap(Function.identity(), slot -> slot.item(inv))).entrySet()) {
Slot.Player slot = entry.getKey();
Optional<ItemStack> itemMaybe = entry.getValue();
if(itemMaybe.isPresent() && this.item.isSimilar(itemMaybe.get())) {
ItemStack item = itemMaybe.get();
int delta = item.getAmount() - left;
if(delta > 0) {
ItemStack replaced = item.clone();
replaced.setAmount(delta);
slot.putItem(inv, replaced);
break;
} else {
slot.putItem(inv, null);
if(delta < 0) {
left = -delta;
}
}
}
}
}
}

View File

@ -1,13 +1,11 @@
package tc.oc.pgm.kits;
import com.google.common.base.Preconditions;
import tc.oc.pgm.match.MatchPlayer;
public class HealthKit extends Kit.Impl {
protected final int halfHearts;
public HealthKit(int halfHearts) {
Preconditions.checkArgument(0 < halfHearts && halfHearts <= 20, "halfHearts must be greater than 0 and less than or equal to 20");
this.halfHearts = halfHearts;
}

View File

@ -11,12 +11,27 @@ public class NaturalRegenerationKit extends Kit.Impl {
this.enabled = enabled;
}
@Override
public void apply(MatchPlayer player, boolean force, ItemKitApplicator items) {
public void toggle(MatchPlayer player, boolean enabled) {
if(fast) {
player.getBukkit().setFastNaturalRegeneration(enabled);
} else {
player.getBukkit().setSlowNaturalRegeneration(enabled);
}
}
@Override
public void apply(MatchPlayer player, boolean force, ItemKitApplicator items) {
toggle(player, enabled);
}
@Override
public boolean isRemovable() {
return true;
}
@Override
public void remove(MatchPlayer player) {
toggle(player, !enabled);
}
}

View File

@ -21,4 +21,5 @@ public class SlotItemKit extends FreeItemKit {
public void apply(MatchPlayer player, boolean force, ItemKitApplicator items) {
items.put(slot, item, force);
}
}

View File

@ -164,11 +164,11 @@ public class MatchAnnouncer implements PluginFacet, Listener {
}
final MutationMatchModule mmm = viewer.getMatch().getMatchModule(MutationMatchModule.class);
if(mmm != null && mmm.getActiveMutations().size() > 0) {
if(mmm != null && mmm.mutationsActive().size() > 0) {
viewer.sendMessage(
new Component(" ", ChatColor.DARK_GRAY).extra(
new TranslatableComponent("broadcast.welcomeMessage.mutations",
new ListComponent(Collections2.transform(mmm.getActiveMutations(), Mutation.toComponent(ChatColor.GREEN)))
new ListComponent(Collections2.transform(mmm.mutationsActive(), Mutation.toComponent(ChatColor.GREEN)))
)
)
);

View File

@ -25,7 +25,6 @@ import tc.oc.pgm.Config;
import tc.oc.pgm.events.MatchBeginEvent;
import tc.oc.pgm.events.MatchEndEvent;
import tc.oc.pgm.events.MatchLoadEvent;
import tc.oc.pgm.gamerules.GameRule;
import tc.oc.pgm.gamerules.GameRulesModule;
import tc.oc.pgm.match.MatchManager;
import tc.oc.pgm.modules.TimeLockModule;
@ -99,9 +98,11 @@ public class PGMListener implements PluginFacet, Listener {
// Time Lock
// lock time before, during (if time lock enabled), and after the match
//
static final String DO_DAYLIGHT_CYCLE = "doDaylightCycle";
@EventHandler
public void lockTime(final MatchLoadEvent event) {
event.getMatch().getWorld().setGameRuleValue(GameRule.DO_DAYLIGHT_CYCLE.getValue(), Boolean.toString(false));
event.getMatch().getWorld().setGameRuleValue(DO_DAYLIGHT_CYCLE, Boolean.toString(false));
}
@EventHandler
@ -113,16 +114,16 @@ public class PGMListener implements PluginFacet, Listener {
GameRulesModule gameRulesModule = event.getMatch().getModuleContext().getModule(GameRulesModule.class);
if (gameRulesModule != null && gameRulesModule.getGameRules().containsKey(GameRule.DO_DAYLIGHT_CYCLE)) {
unlockTime = gameRulesModule.getGameRules().get(GameRule.DO_DAYLIGHT_CYCLE);
if (gameRulesModule != null && gameRulesModule.getGameRules().containsKey(DO_DAYLIGHT_CYCLE)) {
unlockTime = Boolean.valueOf(gameRulesModule.getGameRules().get(DO_DAYLIGHT_CYCLE));
}
event.getMatch().getWorld().setGameRuleValue(GameRule.DO_DAYLIGHT_CYCLE.getValue(), Boolean.toString(unlockTime));
event.getMatch().getWorld().setGameRuleValue(DO_DAYLIGHT_CYCLE, Boolean.toString(unlockTime));
}
@EventHandler
public void lockTime(final MatchEndEvent event) {
event.getMatch().getWorld().setGameRuleValue(GameRule.DO_DAYLIGHT_CYCLE.getValue(), Boolean.toString(false));
event.getMatch().getWorld().setGameRuleValue(DO_DAYLIGHT_CYCLE, Boolean.toString(false));
}
@EventHandler

View File

@ -4,22 +4,21 @@ import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent;
import tc.oc.pgm.events.ListenerScope;
import tc.oc.pgm.filters.matcher.StaticFilter;
import tc.oc.pgm.match.Match;
import tc.oc.pgm.filters.Filter;
import tc.oc.pgm.filters.query.EntitySpawnQuery;
import tc.oc.pgm.match.MatchModule;
import tc.oc.pgm.match.MatchScope;
import tc.oc.pgm.mutation.Mutation;
import tc.oc.pgm.mutation.MutationMatchModule;
@ListenerScope(MatchScope.LOADED)
public class MobsMatchModule extends MatchModule implements Listener {
private final Filter mobsFilter;
public MobsMatchModule(Match match, Filter mobsFilter) {
super(match);
this.mobsFilter = MutationMatchModule.check(match, Mutation.MOBS) ? StaticFilter.ALLOW : mobsFilter;
this.mobsFilter = mobsFilter;
}
@Override
@ -40,8 +39,10 @@ public class MobsMatchModule extends MatchModule implements Listener {
@EventHandler(ignoreCancelled = true)
public void checkSpawn(final CreatureSpawnEvent event) {
if(event.getSpawnReason() != CreatureSpawnEvent.SpawnReason.CUSTOM) {
if(!match.module(MutationMatchModule.class).map(mmm -> mmm.allowMob(event.getSpawnReason())).orElse(false) &&
event.getSpawnReason() != CreatureSpawnEvent.SpawnReason.CUSTOM) {
event.setCancelled(mobsFilter.query(new EntitySpawnQuery(event, event.getEntity(), event.getSpawnReason())).isDenied());
}
}
}

View File

@ -7,58 +7,61 @@ import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.chat.TranslatableComponent;
import tc.oc.api.docs.virtual.MatchDoc;
import tc.oc.commons.core.chat.Component;
import tc.oc.pgm.mutation.submodule.MutationModule;
import tc.oc.pgm.PGM;
import tc.oc.pgm.mutation.types.MutationModule;
import tc.oc.pgm.mutation.types.kit.ArmorMutation;
import tc.oc.pgm.mutation.types.kit.ElytraMutation;
import tc.oc.pgm.mutation.types.kit.EnchantmentMutation;
import tc.oc.pgm.mutation.types.kit.EquestrianMutation;
import tc.oc.pgm.mutation.types.kit.ExplosiveMutation;
import tc.oc.pgm.mutation.types.kit.GlowMutation;
import tc.oc.pgm.mutation.types.kit.HardcoreMutation;
import tc.oc.pgm.mutation.types.kit.HealthMutation;
import tc.oc.pgm.mutation.types.kit.JumpMutation;
import tc.oc.pgm.mutation.types.kit.MobsMutation;
import tc.oc.pgm.mutation.types.kit.PotionMutation;
import tc.oc.pgm.mutation.types.kit.ProjectileMutation;
import tc.oc.pgm.mutation.types.kit.StealthMutation;
import tc.oc.pgm.mutation.types.other.RageMutation;
import tc.oc.pgm.mutation.types.targetable.ApocalypseMutation;
import tc.oc.pgm.mutation.types.targetable.BomberMutation;
import tc.oc.pgm.mutation.types.targetable.LightningMutation;
import static tc.oc.pgm.mutation.submodule.MutationModules.*;
import java.util.stream.Stream;
public enum Mutation {
BLITZ (null, false),
UHC (null, false),
EXPLOSIVES (Explosives.class, true),
NO_FALL (null, false),
MOBS (null, false),
STRENGTH (Strength.class, true),
DOUBLE_JUMP (DoubleJump.class, true),
INVISIBILITY(Invisibility.class, true),
LIGHTNING (Lightning.class, true),
RAGE (Rage.class, true),
ELYTRA (Elytra.class, true);
BLITZ (null),
RAGE (RageMutation.class),
HARDCORE (HardcoreMutation.class),
JUMP (JumpMutation.class),
EXPLOSIVE (ExplosiveMutation.class),
ELYTRA (ElytraMutation.class),
PROJECTILE (ProjectileMutation.class),
ENCHANTMENT(EnchantmentMutation.class),
POTION (PotionMutation.class),
EQUESTRIAN (EquestrianMutation.class),
HEALTH (HealthMutation.class),
GLOW (GlowMutation.class),
STEALTH (StealthMutation.class),
ARMOR (ArmorMutation.class),
MOBS (MobsMutation.class),
LIGHTNING (LightningMutation.class),
BOMBER (BomberMutation.class),
APOCALYPSE (ApocalypseMutation.class);
public static final String TYPE_KEY = "mutation.type.";
public static final String DESCRIPTION_KEY = ".desc";
/**
* The module class that handles this mutation.
*/
private final @Nullable Class<? extends MutationModule> clazz;
private final @Nullable Class<? extends MutationModule> loader;
/**
* Whether this mutation be changed during a match.
*/
private final boolean change;
Mutation(@Nullable Class<? extends MutationModule> clazz, boolean change) {
this.clazz = clazz;
this.change = change;
Mutation(@Nullable Class<? extends MutationModule> loader) {
this.loader = loader;
}
public static Mutation fromApi(MatchDoc.Mutation mutation) {
return values()[mutation.ordinal()];
}
public MatchDoc.Mutation toApi() {
return MatchDoc.Mutation.values()[ordinal()];
}
public Class<? extends MutationModule> getModuleClass() {
return clazz;
}
public boolean isChangeable() {
return change;
public Class<? extends MutationModule> loader() {
return loader;
}
public String getName() {
@ -76,4 +79,14 @@ public enum Mutation {
public static Function<Mutation, BaseComponent> toComponent(final ChatColor color) {
return mutation -> mutation.getComponent(color);
}
public static Stream<Mutation> fromString(final String name) {
try {
return Stream.of(Mutation.valueOf(name));
} catch(IllegalArgumentException iae) {
PGM.get().getLogger().warning("Unable to find mutation named '" + name + "'");
return Stream.empty();
}
}
}

View File

@ -1,24 +1,24 @@
package tc.oc.pgm.mutation;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import org.bukkit.event.entity.CreatureSpawnEvent;
import tc.oc.commons.core.util.MapUtils;
import tc.oc.commons.core.random.RandomUtils;
import tc.oc.pgm.Config;
import tc.oc.pgm.match.*;
import tc.oc.pgm.mutation.command.MutationCommands;
import tc.oc.pgm.mutation.submodule.MutationModule;
import tc.oc.pgm.mutation.types.MutationModule;
import tc.oc.commons.core.random.ImmutableWeightedRandomChooser;
import java.util.*;
import java.util.logging.Level;
import java.util.stream.Stream;
import javax.inject.Inject;
public class MutationMatchModule extends MatchModule {
// TODO: send remote mutation alerts via an AMQP message
/**
* Chance that a mutation event will occur.
@ -63,39 +63,36 @@ public class MutationMatchModule extends MatchModule {
this.chance = options.chance;
this.amount = options.amount;
this.weightedSelector = new ImmutableWeightedRandomChooser<>(options.weights);
this.mutations = getDefaultMutations();
this.mutations = mutationsDefault();
this.history = new HashSet<>();
this.modules = new HashMap<>();
}
public final ImmutableMap<Mutation, Boolean> getMutations() {
public final ImmutableMap<Mutation, Boolean> mutations() {
return ImmutableMap.copyOf(mutations);
}
public final ImmutableSet<Mutation> getActiveMutations() {
return ImmutableSet.copyOf(Collections2.filter(getMutations().keySet(), new Predicate<Mutation>() {
@Override
public boolean apply(Mutation mutation) {
return mutations.get(mutation);
}
}));
public final ImmutableSet<Mutation> mutationsActive() {
return ImmutableSet.copyOf(Collections2.filter(mutations().keySet(), mutations::get));
}
public final ImmutableSet<Mutation> getHistoricalMutations() {
public final ImmutableSet<Mutation> mutationsHistorical() {
return ImmutableSet.copyOf(history);
}
public final ImmutableSet<MutationModule> getMutationModules() {
private Map<Mutation, Boolean> mutationsDefault() {
Map<Mutation, Boolean> defaults = new HashMap<>();
MapUtils.putAll(defaults, Sets.newHashSet(Mutation.values()), false);
return defaults;
}
public final ImmutableSet<MutationModule> mutationModules() {
return ImmutableSet.copyOf(modules.values());
}
@Override
public boolean shouldLoad() {
return Config.Mutations.enabled();
}
@Override
public void load() {
if(!Config.Mutations.enabled()) return;
Random random = match.getRandom();
// Check if the api has any queued mutations
Collection<Mutation> queuedMutations = mutationQueue.mutations();
@ -113,7 +110,7 @@ public class MutationMatchModule extends MatchModule {
mutationQueue.clear();
}
// Load the mutation modules for this match
for(Mutation mutation : getActiveMutations()) {
for(Mutation mutation : mutationsActive()) {
try {
mutate(mutation);
} catch (Throwable throwable) {
@ -124,43 +121,53 @@ public class MutationMatchModule extends MatchModule {
@Override
public void enable() {
for(MutationModule module : modules.values()) {
module.enable(match.isRunning());
}
modules.values().forEach(MutationModule::enable);
}
@Override
public void disable() {
for(MutationModule module : modules.values()) {
module.disable(match.isRunning());
}
modules.values().forEach(MutationModule::disable);
}
public void register(Mutation mutation, boolean load) {
mutations.put(mutation, load);
}
public void mutate(Mutation mutation) throws Throwable {
Class<? extends MutationModule> clazz = mutation.getModuleClass();
if(clazz == null || (match.isRunning() && !mutation.isChangeable())) return;
MutationModule module = modules.containsKey(clazz) ? modules.get(clazz) : mutation.getModuleClass().getDeclaredConstructor(Match.class).newInstance(match);
Class<? extends MutationModule> loader = mutation.loader();
if(loader == null) return;
MutationModule module = modules.containsKey(loader) ? modules.get(loader) : loader.getDeclaredConstructor(Match.class).newInstance(match);
if(mutations.get(mutation)) {
module.enable(match.isRunning());
modules.put(clazz, module);
module.enable();
modules.put(loader, module);
mutations.put(mutation, true);
history.add(mutation);
} else {
module.disable(match.isRunning());
modules.remove(clazz);
module.disable();
modules.remove(loader);
mutations.put(mutation, false);
}
}
private Map<Mutation, Boolean> getDefaultMutations() {
Map<Mutation, Boolean> defaults = new HashMap<>();
MapUtils.putAll(defaults, Sets.newHashSet(Mutation.values()), false);
return defaults;
public boolean enabled() {
return !mutationsActive().isEmpty();
}
public static boolean check(Match match, Mutation mutation) {
return Config.Mutations.enabled() &&
match.hasMatchModule(MutationMatchModule.class) &&
match.getMatchModule(MutationMatchModule.class).getActiveMutations().contains(mutation);
public boolean enabled(Mutation... mutations) {
return mutationsActive().stream().anyMatch(m1 -> Stream.of(mutations).anyMatch(m2 -> m2.equals(m1)));
}
public boolean allowMob(CreatureSpawnEvent.SpawnReason reason) {
switch(reason) {
case NATURAL:
case DEFAULT:
case CHUNK_GEN:
case JOCKEY:
case MOUNT:
return false;
default:
return true;
}
}
}

View File

@ -6,7 +6,6 @@ import java.util.HashSet;
import java.util.stream.Collectors;
import javax.inject.Inject;
import com.google.common.collect.Collections2;
import com.google.common.util.concurrent.ListenableFuture;
import tc.oc.api.docs.Server;
import tc.oc.api.docs.virtual.ServerDoc;
@ -28,12 +27,12 @@ public class MutationQueue {
.getLocalServer()
.queued_mutations()
.stream()
.map(mutation -> Mutation.values()[mutation.ordinal()])
.flatMap(Mutation::fromString)
.collect(Collectors.toList());
}
public ListenableFuture<Server> clear() {
return force(Collections.<Mutation>emptyList());
return force(Collections.emptyList());
}
public ListenableFuture<Server> removeAll(final Collection<Mutation> mutations) {
@ -53,6 +52,7 @@ public class MutationQueue {
}
private ListenableFuture<Server> force(final Collection<Mutation> mutations) {
return minecraftService.updateLocalServer((ServerDoc.Mutation) () -> mutations.stream().map(Mutation::toApi).collect(Collectors.toSet()));
return minecraftService.updateLocalServer((ServerDoc.Mutation) () -> mutations.stream().map(Mutation::name).collect(Collectors.toSet()));
}
}

View File

@ -2,20 +2,21 @@ package tc.oc.pgm.mutation.command;
import java.util.Collection;
import java.util.HashSet;
import java.util.logging.Level;
import javax.inject.Inject;
import com.google.common.collect.Collections2;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.NestedCommand;
import com.sk89q.minecraft.util.commands.*;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TranslatableComponent;
import org.bukkit.command.CommandSender;
import tc.oc.commons.bukkit.chat.PlayerComponent;
import tc.oc.commons.bukkit.chat.WarningComponent;
import tc.oc.commons.bukkit.nick.IdentityProvider;
import tc.oc.commons.core.chat.Audience;
import tc.oc.minecraft.scheduler.SyncExecutor;
import tc.oc.commons.bukkit.chat.Audiences;
import tc.oc.commons.bukkit.chat.ListComponent;
@ -56,39 +57,42 @@ public class MutationCommands implements NestedCommands {
private final SyncExecutor syncExecutor;
private final Audiences audiences;
private final MutationQueue mutationQueue;
private final IdentityProvider identityProvider;
@Inject
MutationCommands(SyncExecutor syncExecutor, Audiences audiences, MutationQueue mutationQueue) {
@Inject MutationCommands(SyncExecutor syncExecutor, Audiences audiences, MutationQueue mutationQueue, IdentityProvider identityProvider) {
this.syncExecutor = syncExecutor;
this.audiences = audiences;
this.mutationQueue = mutationQueue;
this.identityProvider = identityProvider;
}
@Command(
aliases = {"enable", "add"},
aliases = {"enable", "e"},
desc = "Adds a mutation to the upcoming match." +
"You can use '?' as a wildcard or " +
"'*' to use all.",
usage = "<mutation|?|*>",
flags = "q",
min = 1,
max = 1
)
@CommandPermissions(PERMISSION_SET)
public void enable(CommandContext args, CommandSender sender) throws CommandException {
public void enable(CommandContext args, CommandSender sender) throws CommandException, SuggestException {
set(args, sender, true);
}
@Command(
aliases = {"disable", "remove"},
aliases = {"disable", "d"},
desc = "Remove a mutation to the upcoming match." +
"You can use '?' as a wildcard or " +
"'*' to use all.",
usage = "<mutation|?|*>",
flags = "q",
min = 1,
max = 1
)
@CommandPermissions(PERMISSION_SET)
public void disable(CommandContext args, CommandSender sender) throws CommandException {
public void disable(CommandContext args, CommandSender sender) throws CommandException, SuggestException {
set(args, sender, false);
}
@ -105,8 +109,8 @@ public class MutationCommands implements NestedCommands {
public void list(final CommandContext args, CommandSender sender) throws CommandException {
MutationMatchModule module = verify(sender);
final boolean queued = args.hasFlag('q');
final Collection<Mutation> active = queued ? mutationQueue.mutations() : module.getActiveMutations();
new Paginator<Mutation>() {
final Collection<Mutation> active = queued ? mutationQueue.mutations() : module.mutationsActive();
new Paginator<Mutation>(Mutation.values().length / 2) {
@Override
protected BaseComponent title() {
return new TranslatableComponent(queued ? "command.mutation.list.queued" : "command.mutation.list.current");
@ -124,20 +128,26 @@ public class MutationCommands implements NestedCommands {
return CommandUtils.getMatchModule(MutationMatchModule.class, sender);
}
public void set(CommandContext args, final CommandSender sender, final boolean value) throws CommandException {
public void set(CommandContext args, final CommandSender sender, final boolean value) throws CommandException, SuggestException {
final MutationMatchModule module = verify(sender);
final Match match = module.getMatch();
String action = args.getString(0);
boolean queued = args.hasFlag('q') || match.isFinished();
// Mutations that *