package net.t7seven7t.craftfx.trigger;
import com.google.common.collect.MapMaker;
import net.t7seven7t.craftfx.CraftFX;
import net.t7seven7t.craftfx.data.ConfigDataHolder;
import net.t7seven7t.craftfx.data.Data;
import net.t7seven7t.craftfx.data.trigger.CooldownData;
import net.t7seven7t.craftfx.effect.Effect;
import net.t7seven7t.craftfx.effect.EffectContext;
import net.t7seven7t.craftfx.item.ItemDefinition;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.MemoryConfiguration;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
*
*/
public final class Trigger extends ConfigDataHolder {
/**
* The ItemDefinition that causes this trigger
*/
private final ItemDefinition itemDefinition;
/**
* The list of effects that this trigger causes
*/
private final List<Effect> effectList;
/**
* Whether this trigger should only cancel ongoing effects
*/
private final boolean canceller;
/**
* The TriggerSpec for this Trigger
*/
private final TriggerSpec spec;
/**
* The times each player last used this trigger
*/
private Map<Player, Long> lastUseTimes;
Trigger(TriggerSpec spec, ItemDefinition itemDefinition, ConfigurationSection config,
List<Effect> effectList,
boolean canceller) {
super(config);
this.spec = spec;
this.itemDefinition = itemDefinition;
this.effectList = effectList;
this.canceller = canceller;
spec.addTrigger(this);
}
public static Builder builder() {
return new Builder();
}
public TriggerSpec getSpec() {
return spec;
}
void setupCooldowns() {
final CooldownData cooldownData = getData(CooldownData.class).get();
if (cooldownData.getCooldownMillis() != 0) {
lastUseTimes = new MapMaker().weakKeys().makeMap();
} else {
lastUseTimes = null;
}
}
public ItemDefinition getItemDefinition() {
return itemDefinition;
}
public boolean isCanceller() {
return canceller;
}
/**
* Runs all of this trigger's associated effects in the context provided
*
* @param context context
*/
public void run(TriggerContext context) {
if (lastUseTimes != null) {
if (!lastUseTimes.containsKey(context.getInitiator())) {
lastUseTimes.put(context.getInitiator(), System.currentTimeMillis());
} else {
final CooldownData data = getData(CooldownData.class).get();
if (System.currentTimeMillis() - lastUseTimes.get(context.getInitiator())
> data.getCooldownMillis()) {
lastUseTimes.remove(context.getInitiator());
} else {
return;
}
}
}
// run all effects for initiator:
// todo: get targeting params
for (Effect effect : effectList) {
final EffectContext effectContext = new EffectContext(effect, context.getInitiator(),
context.getTarget(), context.getItemDefinition(), context.getSpec(), this);
effect.run(effectContext);
}
}
/**
* Fills a TriggerContext with this Trigger's state
*
* @param context context
*/
public void fill(TriggerContext context) {
context.holder = this;
context.itemDefinition = this.itemDefinition;
}
public static class Builder {
private final List<Effect> effectList = new ArrayList<>();
private final List<Data> dataList = new ArrayList<>();
private final ConfigurationSection config = new MemoryConfiguration();
private TriggerSpec spec;
private ItemDefinition itemDefinition;
private boolean canceller;
public Builder item(ItemDefinition item) {
this.itemDefinition = item;
return this;
}
public Builder spec(String alias) {
return spec(CraftFX.instance().getTriggerRegistry().getSpec(alias).orElse(this.spec));
}
public Builder spec(TriggerSpec spec) {
this.spec = spec;
return this;
}
public Builder cancels(boolean cancels) {
this.canceller = cancels;
return this;
}
public Builder effect(Effect effect) {
this.effectList.add(effect);
return this;
}
public Builder data(Data data) {
this.dataList.add(data);
return this;
}
public Builder property(String propertyName, Object value) {
config.set(propertyName, value);
return this;
}
public Trigger build() {
Validate.notNull(itemDefinition, "ItemDefinition cannot be null");
Validate.notNull(spec, "TriggerSpec cannot be null");
final Trigger trigger = new Trigger(spec, itemDefinition, config, effectList,
canceller);
dataList.forEach(trigger::offer);
// cooldown data may have changed
trigger.setupCooldowns();
return trigger;
}
}
}