ProjectAres/PGM/src/main/java/tc/oc/pgm/kits/KitDefinitionParser.java

264 lines
11 KiB
Java

package tc.oc.pgm.kits;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;
import javax.inject.Inject;
import com.google.common.collect.Range;
import org.bukkit.inventory.ItemStack;
import org.jdom2.Element;
import tc.oc.commons.bukkit.inventory.ArmorType;
import tc.oc.commons.bukkit.inventory.Slot;
import tc.oc.pgm.blitz.LivesKit;
import tc.oc.pgm.compose.CompositionParser;
import tc.oc.pgm.doublejump.DoubleJumpKit;
import tc.oc.pgm.features.FeatureDefinitionContext;
import tc.oc.pgm.features.FeatureDefinitionParser;
import tc.oc.pgm.features.FeatureParser;
import tc.oc.pgm.features.MagicMethodFeatureParser;
import tc.oc.pgm.filters.matcher.StaticFilter;
import tc.oc.pgm.filters.parser.FilterParser;
import tc.oc.pgm.itemmeta.ItemModifier;
import tc.oc.pgm.map.MapLogger;
import tc.oc.pgm.physics.RelativeFlags;
import tc.oc.pgm.shield.ShieldKit;
import tc.oc.pgm.shield.ShieldParameters;
import tc.oc.pgm.teams.TeamFactory;
import tc.oc.pgm.utils.AllMaterialMatcher;
import tc.oc.pgm.utils.MethodParser;
import tc.oc.pgm.utils.XMLUtils;
import tc.oc.pgm.xml.InvalidXMLException;
import tc.oc.pgm.xml.Node;
import tc.oc.pgm.xml.NodeSplitter;
import tc.oc.pgm.xml.property.PropertyBuilderFactory;
import static tc.oc.commons.core.exception.LambdaExceptionUtils.rethrowFunction;
import static tc.oc.commons.core.stream.Collectors.toImmutableSet;
public class KitDefinitionParser extends MagicMethodFeatureParser<Kit> implements FeatureDefinitionParser<Kit> {
@Inject protected FeatureDefinitionContext features;
@Inject protected ItemParser itemParser;
@Inject protected FilterParser filterParser;
@Inject protected FeatureParser<TeamFactory> teamParser;
@Inject protected CompositionParser<Kit> composer;
@Inject protected KitParser kitParser;
@Inject protected PropertyBuilderFactory<Boolean, ?> booleanParser;
@Inject protected MapLogger mapLogger;
@Inject protected ItemModifier itemModifier;
private Stream<Kit> parseParentKits(Element el) throws InvalidXMLException {
return Node.attributes(el, "parent", "parents")
.flatMap(attr -> NodeSplitter.LIST.split(attr)
.map(rethrowFunction(id -> kitParser.parseReference(attr, id.trim()))));
}
// TODO: this check can be removed after a little while
private static final Set<String> LEGACY_ACTION_ATTRS = Stream.of(KitRule.Action.values())
.map(action -> action.name().toLowerCase())
.collect(toImmutableSet());
@MethodParser
Kit kit(Element el) throws InvalidXMLException {
Node.nodes(el, LEGACY_ACTION_ATTRS).forEach(attr ->
mapLogger.warning(attr, "Kit give/take/lend attributes are no longer supported")
);
return new KitNodeImpl(
parseParentKits(el),
composer.parseElement(el),
filterParser.property(el, "filter").optional(StaticFilter.ALLOW),
booleanParser.property(el, "force").elements(false).optional(), // attrs only, since <force> is a type of kit
booleanParser.property(el, "potion-particles").optional()
);
}
protected Kit makeItemKit(Optional<Slot.Player> slot, ItemStack item) throws InvalidXMLException {
final ItemStack modded = itemModifier.modify(item).immutableCopy();
return slot.map(s -> (Kit) new SlotItemKit(modded, s))
.orElseGet(() -> new FreeItemKit(modded));
}
public Kit parseArmorKit(Element el, ArmorType type) throws InvalidXMLException {
return makeItemKit(Optional.of(Slot.Armor.forType(type)), itemParser.parseItem(el, true));
}
public Optional<Slot.Player> parseSlot(Element el) throws InvalidXMLException {
return Optional.ofNullable(Node.fromAttr(el, "slot"))
.map(rethrowFunction(XMLUtils::parsePlayerSlot));
}
@MethodParser
public Kit item(Element el) throws InvalidXMLException {
return makeItemKit(parseSlot(el), itemParser.parseItem(el, true));
}
@MethodParser
public Kit book(Element el) throws InvalidXMLException {
return makeItemKit(parseSlot(el), itemParser.parseBook(el));
}
@MethodParser
public Kit head(Element el) throws InvalidXMLException {
return makeItemKit(parseSlot(el), itemParser.parseHead(el));
}
@MethodParser public Kit boots(Element el) throws InvalidXMLException { return parseArmorKit(el, ArmorType.BOOTS); }
@MethodParser public Kit leggings(Element el) throws InvalidXMLException { return parseArmorKit(el, ArmorType.LEGGINGS); }
@MethodParser public Kit chestplate(Element el) throws InvalidXMLException { return parseArmorKit(el, ArmorType.CHESTPLATE); }
@MethodParser public Kit helmet(Element el) throws InvalidXMLException { return parseArmorKit(el, ArmorType.HELMET); }
@MethodParser
public Kit clear(Element el) throws InvalidXMLException {
return new ClearKit(
parseSlot(el),
XMLUtils.parseMaterialMatcher(el, AllMaterialMatcher.INSTANCE)
);
}
@MethodParser
public Kit clear_items(Element el) throws InvalidXMLException {
return new ClearItemsKit();
}
@MethodParser
public Kit knockback_reduction(Element el) throws InvalidXMLException {
return new KnockbackReductionKit(XMLUtils.parseNumber(el, Float.class));
}
@MethodParser
public Kit walk_speed(Element el) throws InvalidXMLException {
return new WalkSpeedKit(XMLUtils.parseNumber(el, Float.class, Range.closed(WalkSpeedKit.MIN, WalkSpeedKit.MAX)));
}
/*
~ <fly/> {FlyKit: allowFlight = true, flying = null }
~ <fly flying="false"/> {FlyKit: allowFlight = true, flying = false }
~ <fly allowFlight="false"/> {FlyKit: allowFlight = false, flying = null }
~ <fly flying="true"/> {FlyKit: allowFlight = true, flying = true }
*/
@MethodParser
public Kit fly(Element el) throws InvalidXMLException {
final boolean canFly = XMLUtils.parseBoolean(el.getAttribute("can-fly"), true);
final Boolean flying = XMLUtils.parseBoolean(el.getAttribute("flying"), null);
org.jdom2.Attribute flySpeedAtt = el.getAttribute("fly-speed");
float flySpeedMultiplier = 1;
if(flySpeedAtt != null) {
flySpeedMultiplier = XMLUtils.parseNumber(el.getAttribute("fly-speed"), Float.class, Range.closed(FlyKit.MIN, FlyKit.MAX));
}
return new FlyKit(canFly, flying, flySpeedMultiplier);
}
@MethodParser({"effect", "potion"})
public Kit effect(Element el) throws InvalidXMLException {
return new PotionKit(itemParser.parsePotionEffect(el));
}
@MethodParser
public Kit attribute(Element el) throws InvalidXMLException {
return new AttributeKit(XMLUtils.parseAttributeModifier(el));
}
@MethodParser
public Kit health(Element el) throws InvalidXMLException {
int health = XMLUtils.parseNumber(el, Integer.class);
if(health < 1 || health > 20) {
throw new InvalidXMLException(health + " is not a valid health value, must be between 1 and 20", el);
}
return new HealthKit(health);
}
@MethodParser
public Kit max_health(Element el) throws InvalidXMLException {
return new MaxHealthKit(XMLUtils.parseNumber(el, Double.class, Range.atLeast(1d)));
}
@MethodParser
public Kit saturation(Element el) throws InvalidXMLException {
return new HungerKit(XMLUtils.parseNumber(el, Float.class, Range.atLeast(0f)), null);
}
@MethodParser
public Kit foodlevel(Element el) throws InvalidXMLException {
return new HungerKit(null, XMLUtils.parseNumber(el, Integer.class, Range.atLeast(0)));
}
@MethodParser
public Kit double_jump(Element el) throws InvalidXMLException {
return new DoubleJumpKit(XMLUtils.parseBoolean(el.getAttribute("enabled"), true),
XMLUtils.parseNumber(el.getAttribute("power"), Float.class, DoubleJumpKit.DEFAULT_POWER),
XMLUtils.parseDuration(el.getAttribute("recharge-time"), DoubleJumpKit.DEFAULT_RECHARGE),
XMLUtils.parseBoolean(el.getAttribute("recharge-before-landing"), false));
}
@MethodParser
public Kit reser_ender_pearls(Element el) throws InvalidXMLException {
return new ResetEnderPearlsKit();
}
@MethodParser
public Kit game_mode(Element el) throws InvalidXMLException {
return new GameModeKit(XMLUtils.parseGameMode(new Node(el)));
}
@MethodParser
public Kit shield(Element el) throws InvalidXMLException {
return new ShieldKit(new ShieldParameters(XMLUtils.parseNumber(el.getAttribute("health"), Double.class, ShieldParameters.DEFAULT_HEALTH),
XMLUtils.parseDuration(el.getAttribute("delay"), ShieldParameters.DEFAULT_DELAY)));
}
@MethodParser
public Kit fast_regeneration(Element el) throws InvalidXMLException {
return new NaturalRegenerationKit(true, XMLUtils.parseBoolean(new Node(el)));
}
@MethodParser
public Kit slow_regeneration(Element el) throws InvalidXMLException {
return new NaturalRegenerationKit(false, XMLUtils.parseBoolean(new Node(el)));
}
@MethodParser
public Kit hitbox(Element el) throws InvalidXMLException {
return new HitboxKit(XMLUtils.parseNumber(Node.fromRequiredAttr(el, "width"), Double.class));
}
@MethodParser
private Kit remove(Element el) throws InvalidXMLException {
return features.validate(new RemoveKit(kitParser.parseReferenceElement(el)), new Node(el), RemovableValidation.get());
}
@MethodParser
private Kit team_switch(Element el) throws InvalidXMLException {
return new TeamSwitchKit(teamParser.property(el, "team").required());
}
@MethodParser
private Kit eliminate(Element el) throws InvalidXMLException {
return new EliminateKit();
}
private RelativeFlags parseRelativeFlags(Element el) throws InvalidXMLException {
return RelativeFlags.of(XMLUtils.parseBoolean(el.getAttribute("yaw"), false),
XMLUtils.parseBoolean(el.getAttribute("pitch"), false));
}
@MethodParser
private Kit impulse(Element el) throws InvalidXMLException {
return new ImpulseKit(XMLUtils.parseVector(new Node(el)),
parseRelativeFlags(el));
}
@MethodParser
private Kit force(Element el) throws InvalidXMLException {
return new ForceKit(XMLUtils.parseVector(new Node(el)),
parseRelativeFlags(el));
}
@MethodParser
private Kit lives(Element el) throws InvalidXMLException {
return new LivesKit(XMLUtils.parseNumber(new Node(el), Integer.class, false, +1));
}
}