mirror of
https://github.com/OvercastNetwork/ProjectAres.git
synced 2025-04-11 22:56:08 +02:00
Add animation module
This commit is contained in:
parent
8220e90732
commit
dafc229d09
@ -1,6 +1,7 @@
|
|||||||
package tc.oc.pgm;
|
package tc.oc.pgm;
|
||||||
|
|
||||||
import tc.oc.commons.core.inject.HybridManifest;
|
import tc.oc.commons.core.inject.HybridManifest;
|
||||||
|
import tc.oc.pgm.animation.AnimationManifest;
|
||||||
import tc.oc.pgm.broadcast.BroadcastManifest;
|
import tc.oc.pgm.broadcast.BroadcastManifest;
|
||||||
import tc.oc.pgm.classes.ClassManifest;
|
import tc.oc.pgm.classes.ClassManifest;
|
||||||
import tc.oc.pgm.controlpoint.ControlPointManifest;
|
import tc.oc.pgm.controlpoint.ControlPointManifest;
|
||||||
@ -44,6 +45,7 @@ public class PGMModulesManifest extends HybridManifest {
|
|||||||
install(new TeamManifest());
|
install(new TeamManifest());
|
||||||
install(new TrackerManifest());
|
install(new TrackerManifest());
|
||||||
install(new StructureManifest());
|
install(new StructureManifest());
|
||||||
|
install(new AnimationManifest());
|
||||||
install(new PickerManifest());
|
install(new PickerManifest());
|
||||||
install(new ScoreboardManifest());
|
install(new ScoreboardManifest());
|
||||||
install(new DamageManifest());
|
install(new DamageManifest());
|
||||||
|
21
PGM/src/main/java/tc/oc/pgm/animation/Animation.java
Normal file
21
PGM/src/main/java/tc/oc/pgm/animation/Animation.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package tc.oc.pgm.animation;
|
||||||
|
|
||||||
|
import org.bukkit.World;
|
||||||
|
import tc.oc.pgm.features.Feature;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public interface Animation extends Feature<AnimationDefinition> {
|
||||||
|
void place(Frame frame);
|
||||||
|
|
||||||
|
World getWorld();
|
||||||
|
|
||||||
|
Duration getAfter();
|
||||||
|
|
||||||
|
Duration getLoop();
|
||||||
|
|
||||||
|
int getCount();
|
||||||
|
|
||||||
|
List<Frame> getFrames();
|
||||||
|
}
|
131
PGM/src/main/java/tc/oc/pgm/animation/AnimationDefinition.java
Normal file
131
PGM/src/main/java/tc/oc/pgm/animation/AnimationDefinition.java
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
package tc.oc.pgm.animation;
|
||||||
|
|
||||||
|
import com.google.inject.assistedinject.Assisted;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.util.ImVector;
|
||||||
|
import tc.oc.commons.core.inject.InnerFactory;
|
||||||
|
import tc.oc.pgm.features.FeatureDefinition;
|
||||||
|
import tc.oc.pgm.features.FeatureFactory;
|
||||||
|
import tc.oc.pgm.features.FeatureInfo;
|
||||||
|
import tc.oc.pgm.features.MatchFeatureContext;
|
||||||
|
import tc.oc.pgm.filters.FilterMatchModule;
|
||||||
|
import tc.oc.pgm.match.Match;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
@FeatureInfo(name = "animation")
|
||||||
|
public interface AnimationDefinition extends FeatureDefinition, FeatureFactory<Animation> {}
|
||||||
|
|
||||||
|
class AnimationDefinitionImpl extends FeatureDefinition.Impl implements AnimationDefinition {
|
||||||
|
|
||||||
|
interface Factory {
|
||||||
|
AnimationDefinitionImpl create(List<FrameDefinition> frames,
|
||||||
|
@Assisted("after") Duration after,
|
||||||
|
@Assisted("loop") Duration loop,
|
||||||
|
@Assisted("count") int count,
|
||||||
|
@Assisted("position") Optional<ImVector> position);
|
||||||
|
}
|
||||||
|
|
||||||
|
final @Inspect List<FrameDefinition> frames;
|
||||||
|
final @Inspect Duration after;
|
||||||
|
final @Inspect Duration loop;
|
||||||
|
final @Inspect int count;
|
||||||
|
final @Inspect Optional<ImVector> position;
|
||||||
|
|
||||||
|
private final InnerFactory<AnimationDefinitionImpl, AnimationImpl> factory;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
AnimationDefinitionImpl(@Assisted List<FrameDefinition> frames,
|
||||||
|
@Assisted("after") Duration after,
|
||||||
|
@Assisted("loop") Duration loop,
|
||||||
|
@Assisted("count") int count,
|
||||||
|
@Assisted("position") Optional<ImVector> position,
|
||||||
|
InnerFactory<AnimationDefinitionImpl, AnimationImpl> factory) {
|
||||||
|
|
||||||
|
this.frames = checkNotNull(frames);
|
||||||
|
this.after = after;
|
||||||
|
this.loop = loop;
|
||||||
|
this.count = count;
|
||||||
|
this.position = position;
|
||||||
|
this.factory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnimationImpl createFeature(Match match) {
|
||||||
|
return factory.create(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void place(Frame frame, World world, ImVector offset) {
|
||||||
|
frame.place(world, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(Match match) {
|
||||||
|
match.features().get(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
class AnimationImpl implements Animation {
|
||||||
|
|
||||||
|
final World world;
|
||||||
|
final Duration after;
|
||||||
|
final Duration loop;
|
||||||
|
final int count;
|
||||||
|
final List<Frame> frames;
|
||||||
|
|
||||||
|
@Inject AnimationImpl(World world, MatchFeatureContext features, AnimationScheduler scheduler, FilterMatchModule fmm) {
|
||||||
|
this.world = world;
|
||||||
|
final AnimationDefinitionImpl def = AnimationDefinitionImpl.this;
|
||||||
|
this.after = def.after;
|
||||||
|
this.loop = def.loop;
|
||||||
|
this.count = def.count;
|
||||||
|
this.frames = new ArrayList<>();
|
||||||
|
for (FrameDefinition frameDef : def.frames) {
|
||||||
|
Frame frame = features.get(frameDef);
|
||||||
|
frame.setOrigin(frameDef.origin());
|
||||||
|
frames.add(frame);
|
||||||
|
}
|
||||||
|
scheduler.animations.add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AnimationDefinition getDefinition() {
|
||||||
|
return AnimationDefinitionImpl.this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void place(Frame frame) {
|
||||||
|
frame.place(world, position.get().copy());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public World getWorld() {
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Duration getAfter() {
|
||||||
|
return after;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Duration getLoop() {
|
||||||
|
return loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Frame> getFrames() {
|
||||||
|
return frames;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
PGM/src/main/java/tc/oc/pgm/animation/AnimationManifest.java
Normal file
22
PGM/src/main/java/tc/oc/pgm/animation/AnimationManifest.java
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package tc.oc.pgm.animation;
|
||||||
|
|
||||||
|
import tc.oc.commons.core.inject.HybridManifest;
|
||||||
|
import tc.oc.pgm.map.inject.MapBinders;
|
||||||
|
import tc.oc.pgm.map.inject.MapScoped;
|
||||||
|
import tc.oc.pgm.match.MatchScope;
|
||||||
|
import tc.oc.pgm.match.inject.MatchBinders;
|
||||||
|
import tc.oc.pgm.match.inject.MatchScoped;
|
||||||
|
|
||||||
|
public class AnimationManifest extends HybridManifest implements MapBinders, MatchBinders {
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
installInnerClassFactory(AnimationDefinitionImpl.AnimationImpl.class);
|
||||||
|
installFactory(AnimationDefinitionImpl.Factory.class);
|
||||||
|
|
||||||
|
bind(AnimationParser.class).in(MapScoped.class);
|
||||||
|
rootParsers().addBinding().to(AnimationParser.class);
|
||||||
|
|
||||||
|
bind(AnimationScheduler.class).in(MatchScoped.class);
|
||||||
|
matchListener(AnimationScheduler.class, MatchScope.LOADED);
|
||||||
|
}
|
||||||
|
}
|
76
PGM/src/main/java/tc/oc/pgm/animation/AnimationParser.java
Normal file
76
PGM/src/main/java/tc/oc/pgm/animation/AnimationParser.java
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
package tc.oc.pgm.animation;
|
||||||
|
|
||||||
|
import com.google.common.collect.Range;
|
||||||
|
import org.bukkit.util.ImVector;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
import org.jdom2.Document;
|
||||||
|
import org.jdom2.Element;
|
||||||
|
import tc.oc.pgm.features.FeatureDefinitionContext;
|
||||||
|
import tc.oc.pgm.map.MapRootParser;
|
||||||
|
import tc.oc.pgm.regions.CuboidValidation;
|
||||||
|
import tc.oc.pgm.regions.RegionParser;
|
||||||
|
import tc.oc.pgm.utils.XMLUtils;
|
||||||
|
import tc.oc.pgm.xml.InvalidXMLException;
|
||||||
|
import tc.oc.pgm.xml.Node;
|
||||||
|
import tc.oc.pgm.xml.property.DurationProperty;
|
||||||
|
import tc.oc.pgm.xml.property.NumberProperty;
|
||||||
|
import tc.oc.pgm.xml.property.PropertyBuilderFactory;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class AnimationParser implements MapRootParser {
|
||||||
|
|
||||||
|
@Inject FeatureDefinitionContext features;
|
||||||
|
@Inject Document doc;
|
||||||
|
@Inject AnimationDefinitionImpl.Factory animationDefinitionFactory;
|
||||||
|
@Inject RegionParser regionParser;
|
||||||
|
@Inject PropertyBuilderFactory<Duration, DurationProperty> durations;
|
||||||
|
@Inject PropertyBuilderFactory<Integer, NumberProperty<Integer>> integers;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parse() throws InvalidXMLException {
|
||||||
|
|
||||||
|
for(Element elFrame : XMLUtils.flattenElements(doc.getRootElement(), "animations", "frame")) {
|
||||||
|
features.define(
|
||||||
|
elFrame,
|
||||||
|
new FrameDefinitionImpl(
|
||||||
|
XMLUtils.parseVector(elFrame.getAttribute("origin"), (Vector) null),
|
||||||
|
regionParser.property(elFrame, "region").validate(CuboidValidation.INSTANCE).required(),
|
||||||
|
XMLUtils.parseBoolean(elFrame.getAttribute("air"), false),
|
||||||
|
XMLUtils.parseBoolean(elFrame.getAttribute("clear"), true)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Element elAnimation : XMLUtils.flattenElements(doc.getRootElement(), "animations", "animation")) {
|
||||||
|
List<FrameDefinition> frames = new ArrayList<>();
|
||||||
|
for (Node elFrames : Node.fromChildren(elAnimation, "frames")) {
|
||||||
|
for (Node elFrame : Node.fromChildren(elFrames.asElement(), "frame")) {
|
||||||
|
frames.add(features.reference(Node.fromRequiredAttr(elFrame.asElement(), "id"), FrameDefinition.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Duration after = durations.property(elAnimation, "after").required();
|
||||||
|
Duration loop = durations.property(elAnimation, "loop").required();
|
||||||
|
|
||||||
|
int count = integers.property(elAnimation, "count")
|
||||||
|
.range(Range.atLeast(1))
|
||||||
|
.infinity(true)
|
||||||
|
.optional(Integer.MAX_VALUE);
|
||||||
|
|
||||||
|
final Optional<ImVector>
|
||||||
|
position = XMLUtils.parseVector(elAnimation, "location").optional(),
|
||||||
|
offset = XMLUtils.parseVector(elAnimation, "offset").optional();
|
||||||
|
|
||||||
|
if(position.isPresent() && offset.isPresent()) {
|
||||||
|
throw new InvalidXMLException("attributes 'location' and 'offset' cannot be used together", elAnimation);
|
||||||
|
}
|
||||||
|
|
||||||
|
features.define(elAnimation, animationDefinitionFactory.create(frames, after, loop, count, position));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
package tc.oc.pgm.animation;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import tc.oc.commons.core.scheduler.Task;
|
||||||
|
import tc.oc.commons.core.stream.Collectors;
|
||||||
|
import tc.oc.pgm.events.MatchBeginEvent;
|
||||||
|
import tc.oc.pgm.events.MatchEndEvent;
|
||||||
|
import tc.oc.pgm.match.MatchScheduler;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AnimationScheduler implements Listener {
|
||||||
|
|
||||||
|
final List<AnimationDefinitionImpl.AnimationImpl> animations;
|
||||||
|
private final MatchScheduler scheduler;
|
||||||
|
|
||||||
|
private List<AnimationTask> tasks = ImmutableList.of();
|
||||||
|
|
||||||
|
@Inject AnimationScheduler(MatchScheduler scheduler) {
|
||||||
|
this.animations = new ArrayList<>();
|
||||||
|
this.scheduler = scheduler;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void matchBegin(MatchBeginEvent event) {
|
||||||
|
tasks = animations.stream()
|
||||||
|
.map(AnimationTask::new)
|
||||||
|
.collect(Collectors.toImmutableList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void matchEnd(MatchEndEvent event) {
|
||||||
|
tasks.forEach(AnimationTask::cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AnimationTask {
|
||||||
|
final AnimationDefinitionImpl.AnimationImpl animation;
|
||||||
|
final Task task;
|
||||||
|
int count = 0;
|
||||||
|
int currentFrame = 0;
|
||||||
|
|
||||||
|
AnimationTask(AnimationDefinitionImpl.AnimationImpl animation) {
|
||||||
|
this.animation = animation;
|
||||||
|
this.task = scheduler.createRepeatingTask(animation.getAfter(), animation.getLoop(), this::send);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancel() {
|
||||||
|
task.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void send() {
|
||||||
|
animation.place(animation.getFrames().get(currentFrame));
|
||||||
|
|
||||||
|
this.currentFrame = currentFrame >= animation.getFrames().size() - 1 ? 0 : currentFrame + 1;
|
||||||
|
|
||||||
|
if(++count >= animation.getCount()) {
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
PGM/src/main/java/tc/oc/pgm/animation/Frame.java
Normal file
20
PGM/src/main/java/tc/oc/pgm/animation/Frame.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package tc.oc.pgm.animation;
|
||||||
|
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
import tc.oc.pgm.features.Feature;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created from a {@link FrameDefinition} for a specific {@link World}.
|
||||||
|
*/
|
||||||
|
public interface Frame extends Feature<FrameDefinition> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Place this frame in its origin world, offset by the given delta.
|
||||||
|
*/
|
||||||
|
void place(World world, Vector newLocation);
|
||||||
|
|
||||||
|
void setOrigin(Vector origin);
|
||||||
|
|
||||||
|
Vector getOrigin();
|
||||||
|
}
|
135
PGM/src/main/java/tc/oc/pgm/animation/FrameDefinition.java
Normal file
135
PGM/src/main/java/tc/oc/pgm/animation/FrameDefinition.java
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
package tc.oc.pgm.animation;
|
||||||
|
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.block.BlockImage;
|
||||||
|
import org.bukkit.geometry.Cuboid;
|
||||||
|
import org.bukkit.region.BlockRegion;
|
||||||
|
import org.bukkit.region.CuboidBlockRegion;
|
||||||
|
import org.bukkit.util.ImVector;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
import tc.oc.pgm.features.FeatureDefinition;
|
||||||
|
import tc.oc.pgm.features.FeatureFactory;
|
||||||
|
import tc.oc.pgm.features.FeatureInfo;
|
||||||
|
import tc.oc.pgm.match.Match;
|
||||||
|
import tc.oc.pgm.regions.Region;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
@FeatureInfo(name = "frame")
|
||||||
|
public interface FrameDefinition extends FeatureDefinition, FeatureFactory<Frame> {
|
||||||
|
|
||||||
|
Vector origin();
|
||||||
|
|
||||||
|
Region region();
|
||||||
|
|
||||||
|
Cuboid bounds();
|
||||||
|
|
||||||
|
boolean includeAir();
|
||||||
|
|
||||||
|
boolean clearSource();
|
||||||
|
|
||||||
|
BlockRegion staticBlocks();
|
||||||
|
}
|
||||||
|
|
||||||
|
class FrameDefinitionImpl extends FeatureDefinition.Impl implements FrameDefinition {
|
||||||
|
|
||||||
|
private final @Inspect Region region;
|
||||||
|
private final @Inspect boolean includeAir;
|
||||||
|
private final @Inspect boolean clearSource;
|
||||||
|
|
||||||
|
// Lazy init because of feature proxies
|
||||||
|
private @Nullable ImVector origin;
|
||||||
|
private Cuboid bounds;
|
||||||
|
private BlockRegion staticBlocks;
|
||||||
|
|
||||||
|
public FrameDefinitionImpl(@Nullable Vector origin, Region region, boolean includeAir, boolean clearSource) {
|
||||||
|
this.origin = origin == null ? null : ImVector.copyOf(origin);
|
||||||
|
this.region = checkNotNull(region);
|
||||||
|
this.includeAir = includeAir;
|
||||||
|
this.clearSource = clearSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector origin() {
|
||||||
|
if(origin == null) {
|
||||||
|
origin = region.getBounds().minimum();
|
||||||
|
}
|
||||||
|
return origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Region region() {
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean includeAir() {
|
||||||
|
return includeAir;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean clearSource() {
|
||||||
|
return clearSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Cuboid bounds() {
|
||||||
|
if(bounds == null) {
|
||||||
|
bounds = region.getBounds();
|
||||||
|
}
|
||||||
|
return bounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BlockRegion staticBlocks() {
|
||||||
|
if(staticBlocks == null) {
|
||||||
|
this.staticBlocks = CuboidBlockRegion.fromMinAndSize(bounds().minimumBlockInside(),
|
||||||
|
bounds().blockSize());
|
||||||
|
}
|
||||||
|
return staticBlocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void load(Match match) {
|
||||||
|
match.features().get(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Frame createFeature(Match match) {
|
||||||
|
return new FrameImpl(match.getWorld());
|
||||||
|
}
|
||||||
|
|
||||||
|
class FrameImpl implements Frame {
|
||||||
|
private final BlockImage image;
|
||||||
|
private Vector origin;
|
||||||
|
|
||||||
|
FrameImpl(World world) {
|
||||||
|
this.image = world.copyBlocks(staticBlocks(),
|
||||||
|
includeAir(),
|
||||||
|
clearSource());
|
||||||
|
this.origin = ImVector.ofZero();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FrameDefinition getDefinition() {
|
||||||
|
return tc.oc.pgm.animation.FrameDefinitionImpl.this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void place(World world, Vector newLocation) {
|
||||||
|
world.pasteBlocks(image, newLocation.minus(origin));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Vector getOrigin() {
|
||||||
|
return origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOrigin(Vector origin) {
|
||||||
|
this.origin = origin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user