mirror of
https://github.com/Xiao-MoMi/Custom-Fishing.git
synced 2025-12-26 10:29:16 +00:00
totems
This commit is contained in:
@@ -126,6 +126,9 @@ public class IntegrationManagerImpl implements IntegrationManager {
|
||||
} else if (plugin.isHookedPluginEnabled("CustomCrops")) {
|
||||
this.seasonInterface = new CustomCropsSeasonImpl();
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("Vault")) {
|
||||
VaultHook.initialize();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) <2022> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customfishing.compatibility;
|
||||
|
||||
import net.milkbowl.vault.economy.Economy;
|
||||
import net.momirealms.customfishing.api.CustomFishingPlugin;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
|
||||
public class VaultHook {
|
||||
|
||||
private static Economy economy;
|
||||
|
||||
public static boolean initialize() {
|
||||
RegisteredServiceProvider<Economy> rsp = CustomFishingPlugin.getInstance().getServer().getServicesManager().getRegistration(Economy.class);
|
||||
if (rsp == null) {
|
||||
return false;
|
||||
}
|
||||
economy = rsp.getProvider();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Economy getEconomy() {
|
||||
return economy;
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import net.momirealms.customfishing.api.mechanic.action.ActionTrigger;
|
||||
import net.momirealms.customfishing.api.mechanic.loot.Loot;
|
||||
import net.momirealms.customfishing.api.mechanic.requirement.Requirement;
|
||||
import net.momirealms.customfishing.api.util.LogUtils;
|
||||
import net.momirealms.customfishing.compatibility.VaultHook;
|
||||
import net.momirealms.customfishing.compatibility.papi.PlaceholderManagerImpl;
|
||||
import net.momirealms.customfishing.mechanic.item.ItemManagerImpl;
|
||||
import net.momirealms.customfishing.setting.CFLocale;
|
||||
@@ -40,6 +41,7 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.ExperienceOrb;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
@@ -90,6 +92,7 @@ public class ActionManagerImpl implements ActionManager {
|
||||
this.registerItemAmountAction();
|
||||
this.registerItemDurabilityAction();
|
||||
this.registerGiveItemAction();
|
||||
this.registerMoneyAction();
|
||||
}
|
||||
|
||||
public void load() {
|
||||
@@ -199,22 +202,23 @@ public class ActionManagerImpl implements ActionManager {
|
||||
return condition -> {
|
||||
if (Math.random() > chance) return;
|
||||
Player owner = condition.getPlayer();
|
||||
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
double distance = LocationUtils.getDistance(player.getLocation(), owner.getLocation());
|
||||
if (distance <= range) {
|
||||
condition.insertArg("{near}", player.getName());
|
||||
List<String> replaced = PlaceholderManagerImpl.getInstance().parse(
|
||||
owner,
|
||||
msg,
|
||||
condition.getArgs()
|
||||
);
|
||||
for (String text : replaced) {
|
||||
AdventureManagerImpl.getInstance().sendPlayerMessage(player, text);
|
||||
plugin.getScheduler().runTaskSync(() -> {
|
||||
for (Entity player : condition.getLocation().getWorld().getNearbyEntities(condition.getLocation(), range, range, range, entity -> entity instanceof Player)) {
|
||||
double distance = LocationUtils.getDistance(player.getLocation(), condition.getLocation());
|
||||
if (distance <= range) {
|
||||
condition.insertArg("{near}", player.getName());
|
||||
List<String> replaced = PlaceholderManagerImpl.getInstance().parse(
|
||||
owner,
|
||||
msg,
|
||||
condition.getArgs()
|
||||
);
|
||||
for (String text : replaced) {
|
||||
AdventureManagerImpl.getInstance().sendPlayerMessage((Player) player, text);
|
||||
}
|
||||
condition.delArg("{near}");
|
||||
}
|
||||
condition.delArg("{near}");
|
||||
}
|
||||
}
|
||||
}, condition.getLocation());
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Illegal value format found at action: message-nearby");
|
||||
@@ -268,21 +272,23 @@ public class ActionManagerImpl implements ActionManager {
|
||||
return condition -> {
|
||||
if (Math.random() > chance) return;
|
||||
Player owner = condition.getPlayer();
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
double distance = LocationUtils.getDistance(player.getLocation(), owner.getLocation());
|
||||
if (distance <= range) {
|
||||
condition.insertArg("{near}", player.getName());
|
||||
List<String> replaced = PlaceholderManagerImpl.getInstance().parse(
|
||||
owner,
|
||||
cmd,
|
||||
condition.getArgs()
|
||||
);
|
||||
for (String text : replaced) {
|
||||
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), text);
|
||||
plugin.getScheduler().runTaskSync(() -> {
|
||||
for (Entity player : condition.getLocation().getWorld().getNearbyEntities(condition.getLocation(), range, range, range, entity -> entity instanceof Player)) {
|
||||
double distance = LocationUtils.getDistance(player.getLocation(), condition.getLocation());
|
||||
if (distance <= range) {
|
||||
condition.insertArg("{near}", player.getName());
|
||||
List<String> replaced = PlaceholderManagerImpl.getInstance().parse(
|
||||
owner,
|
||||
cmd,
|
||||
condition.getArgs()
|
||||
);
|
||||
for (String text : replaced) {
|
||||
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), text);
|
||||
}
|
||||
condition.delArg("{near}");
|
||||
}
|
||||
condition.delArg("{near}");
|
||||
}
|
||||
}
|
||||
}, condition.getLocation());
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Illegal value format found at action: command-nearby");
|
||||
@@ -316,6 +322,35 @@ public class ActionManagerImpl implements ActionManager {
|
||||
AdventureManagerImpl.getInstance().sendActionbar(condition.getPlayer(), random);
|
||||
};
|
||||
});
|
||||
registerAction("actionbar-nearby", (args, chance) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String actionbar = section.getString("actionbar");
|
||||
int range = section.getInt("range");
|
||||
return condition -> {
|
||||
if (Math.random() > chance) return;
|
||||
Player owner = condition.getPlayer();
|
||||
plugin.getScheduler().runTaskSync(() -> {
|
||||
for (Entity player : condition.getLocation().getWorld().getNearbyEntities(condition.getLocation(), range, range, range, entity -> entity instanceof Player)) {
|
||||
double distance = LocationUtils.getDistance(player.getLocation(), condition.getLocation());
|
||||
if (distance <= range) {
|
||||
condition.insertArg("{near}", player.getName());
|
||||
String replaced = PlaceholderManagerImpl.getInstance().parse(
|
||||
owner,
|
||||
actionbar,
|
||||
condition.getArgs()
|
||||
);
|
||||
AdventureManagerImpl.getInstance().sendActionbar((Player) player, replaced);
|
||||
condition.delArg("{near}");
|
||||
}
|
||||
}
|
||||
}, condition.getLocation()
|
||||
);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Illegal value format found at action: command-nearby");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void registerMendingAction() {
|
||||
@@ -367,21 +402,30 @@ public class ActionManagerImpl implements ActionManager {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String text = section.getString("text", "");
|
||||
int duration = section.getInt("duration", 20);
|
||||
boolean position = section.getString("position", "hook").equals("hook");
|
||||
boolean position = section.getString("position", "other").equals("other");
|
||||
double x = section.getDouble("x");
|
||||
double y = section.getDouble("y");
|
||||
double z = section.getDouble("z");
|
||||
int range = section.getInt("range", 16);
|
||||
return condition -> {
|
||||
if (Math.random() > chance) return;
|
||||
Player player = condition.getPlayer();
|
||||
Location location = position ? condition.getLocation() : player.getLocation();
|
||||
ArmorStandUtils.sendHologram(
|
||||
condition.getPlayer(),
|
||||
location.clone().add(x, y, z),
|
||||
AdventureManagerImpl.getInstance().getComponentFromMiniMessage(
|
||||
PlaceholderManagerImpl.getInstance().parse(player, text, condition.getArgs())
|
||||
),
|
||||
duration
|
||||
Player owner = condition.getPlayer();
|
||||
Location location = position ? condition.getLocation() : owner.getLocation();
|
||||
plugin.getScheduler().runTaskSync(() -> {
|
||||
for (Entity player : condition.getLocation().getWorld().getNearbyEntities(condition.getLocation(), range, range, range, entity -> entity instanceof Player)) {
|
||||
double distance = LocationUtils.getDistance(player.getLocation(), condition.getLocation());
|
||||
if (distance <= range) {
|
||||
ArmorStandUtils.sendHologram(
|
||||
(Player) player,
|
||||
location.clone().add(x, y, z),
|
||||
AdventureManagerImpl.getInstance().getComponentFromMiniMessage(
|
||||
PlaceholderManagerImpl.getInstance().parse(owner, text, condition.getArgs())
|
||||
),
|
||||
duration
|
||||
);
|
||||
}
|
||||
}
|
||||
}, condition.getLocation()
|
||||
);
|
||||
};
|
||||
} else {
|
||||
@@ -494,6 +538,23 @@ public class ActionManagerImpl implements ActionManager {
|
||||
});
|
||||
}
|
||||
|
||||
private void registerMoneyAction() {
|
||||
registerAction("give-money", (args, chance) -> {
|
||||
double money = ConfigUtils.getDoubleValue(args);
|
||||
return condition -> {
|
||||
if (Math.random() > chance) return;
|
||||
VaultHook.getEconomy().depositPlayer(condition.getPlayer(), money);
|
||||
};
|
||||
});
|
||||
registerAction("take-money", (args, chance) -> {
|
||||
double money = ConfigUtils.getDoubleValue(args);
|
||||
return condition -> {
|
||||
if (Math.random() > chance) return;
|
||||
VaultHook.getEconomy().withdrawPlayer(condition.getPlayer(), money);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private void registerDelayedAction() {
|
||||
registerAction("delay", (args, chance) -> {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
@@ -541,8 +602,44 @@ public class ActionManagerImpl implements ActionManager {
|
||||
fadeOut * 50
|
||||
);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Illegal value format found at action: title");
|
||||
return null;
|
||||
}
|
||||
});
|
||||
registerAction("title-nearby", (args, chance) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String title = section.getString("title");
|
||||
String subtitle = section.getString("subtitle");
|
||||
int fadeIn = section.getInt("fade-in", 20);
|
||||
int stay = section.getInt("stay", 30);
|
||||
int fadeOut = section.getInt("fade-out", 10);
|
||||
int range = section.getInt("range", 32);
|
||||
return condition -> {
|
||||
if (Math.random() > chance) return;
|
||||
plugin.getScheduler().runTaskSync(() -> {
|
||||
for (Entity player : condition.getLocation().getWorld().getNearbyEntities(condition.getLocation(), range, range, range, entity -> entity instanceof Player)) {
|
||||
double distance = LocationUtils.getDistance(player.getLocation(), condition.getLocation());
|
||||
if (distance <= range) {
|
||||
condition.insertArg("{near}", player.getName());
|
||||
AdventureManagerImpl.getInstance().sendTitle(
|
||||
condition.getPlayer(),
|
||||
PlaceholderManagerImpl.getInstance().parse(condition.getPlayer(), title, condition.getArgs()),
|
||||
PlaceholderManagerImpl.getInstance().parse(condition.getPlayer(), subtitle, condition.getArgs()),
|
||||
fadeIn * 50,
|
||||
stay * 50,
|
||||
fadeOut * 50
|
||||
);
|
||||
condition.delArg("{near}");
|
||||
}
|
||||
}
|
||||
}, condition.getLocation()
|
||||
);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Illegal value format found at action: title-nearby");
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
registerAction("random-title", (args, chance) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
@@ -562,8 +659,10 @@ public class ActionManagerImpl implements ActionManager {
|
||||
fadeOut * 50
|
||||
);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Illegal value format found at action: random-title");
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import net.momirealms.customfishing.api.mechanic.requirement.Requirement;
|
||||
import net.momirealms.customfishing.api.mechanic.requirement.RequirementExpansion;
|
||||
import net.momirealms.customfishing.api.mechanic.requirement.RequirementFactory;
|
||||
import net.momirealms.customfishing.api.util.LogUtils;
|
||||
import net.momirealms.customfishing.compatibility.VaultHook;
|
||||
import net.momirealms.customfishing.compatibility.papi.ParseUtils;
|
||||
import net.momirealms.customfishing.util.ClassUtils;
|
||||
import net.momirealms.customfishing.util.ConfigUtils;
|
||||
@@ -143,6 +144,7 @@ public class RequirementManagerImpl implements RequirementManager {
|
||||
this.registerNumberEqualRequirement();
|
||||
this.registerRegexRequirement();
|
||||
this.registerItemInHandRequirement();
|
||||
this.registerMoneyRequirement();
|
||||
}
|
||||
|
||||
public ConditionalElement getConditionalElements(ConfigurationSection section) {
|
||||
@@ -465,6 +467,19 @@ public class RequirementManagerImpl implements RequirementManager {
|
||||
});
|
||||
}
|
||||
|
||||
private void registerMoneyRequirement() {
|
||||
registerRequirement("money", (args, actions, advanced) -> {
|
||||
double money = ConfigUtils.getDoubleValue(args);
|
||||
return condition -> {
|
||||
double current = VaultHook.getEconomy().getBalance(condition.getPlayer());
|
||||
if (current >= money)
|
||||
return true;
|
||||
if (advanced) triggerActions(actions, condition);
|
||||
return false;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private void registerRandomRequirement() {
|
||||
registerRequirement("random", (args, actions, advanced) -> {
|
||||
double random = ConfigUtils.getDoubleValue(args);
|
||||
|
||||
@@ -17,11 +17,17 @@
|
||||
|
||||
package net.momirealms.customfishing.mechanic.totem;
|
||||
|
||||
import net.momirealms.customfishing.api.CustomFishingPlugin;
|
||||
import net.momirealms.customfishing.api.mechanic.action.Action;
|
||||
import net.momirealms.customfishing.api.mechanic.action.ActionTrigger;
|
||||
import net.momirealms.customfishing.api.mechanic.condition.Condition;
|
||||
import net.momirealms.customfishing.api.mechanic.effect.EffectCarrier;
|
||||
import net.momirealms.customfishing.api.scheduler.CancellableTask;
|
||||
import net.momirealms.customfishing.mechanic.totem.particle.ParticleSetting;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class ActivatedTotem {
|
||||
@@ -29,11 +35,15 @@ public class ActivatedTotem {
|
||||
private final List<CancellableTask> subTasks;
|
||||
private final Location coreLocation;
|
||||
private final TotemConfig totemConfig;
|
||||
private final long expireTime;
|
||||
private final EffectCarrier effectCarrier;
|
||||
|
||||
public ActivatedTotem(Location coreLocation, TotemConfig config) {
|
||||
this.subTasks = new ArrayList<>();
|
||||
this.expireTime = System.currentTimeMillis() + config.getDuration() * 1000L;
|
||||
this.coreLocation = coreLocation.clone().add(0.5,0,0.5);
|
||||
this.totemConfig = config;
|
||||
this.effectCarrier = CustomFishingPlugin.get().getEffectManager().getEffect("totem", config.getKey());
|
||||
for (ParticleSetting particleSetting : config.getParticleSettings()) {
|
||||
this.subTasks.add(particleSetting.start(coreLocation, config.getRadius()));
|
||||
}
|
||||
@@ -52,4 +62,26 @@ public class ActivatedTotem {
|
||||
task.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public long getExpireTime() {
|
||||
return expireTime;
|
||||
}
|
||||
|
||||
public void doTimerAction() {
|
||||
HashMap<String, String> args = new HashMap<>();
|
||||
args.put("{time_left}", String.valueOf((expireTime - System.currentTimeMillis())/1000));
|
||||
Condition condition = new Condition(coreLocation, null, args);
|
||||
if (effectCarrier != null) {
|
||||
Action[] actions = effectCarrier.getActions(ActionTrigger.TIMER);
|
||||
if (actions != null) {
|
||||
for (Action action : actions) {
|
||||
action.trigger(condition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public EffectCarrier getEffectCarrier() {
|
||||
return effectCarrier;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,11 @@ import net.momirealms.customfishing.api.mechanic.action.Action;
|
||||
import net.momirealms.customfishing.api.mechanic.action.ActionTrigger;
|
||||
import net.momirealms.customfishing.api.mechanic.condition.Condition;
|
||||
import net.momirealms.customfishing.api.mechanic.effect.EffectCarrier;
|
||||
import net.momirealms.customfishing.mechanic.totem.block.AxisImpl;
|
||||
import net.momirealms.customfishing.mechanic.totem.block.FaceImpl;
|
||||
import net.momirealms.customfishing.api.scheduler.CancellableTask;
|
||||
import net.momirealms.customfishing.mechanic.totem.block.property.AxisImpl;
|
||||
import net.momirealms.customfishing.mechanic.totem.block.property.FaceImpl;
|
||||
import net.momirealms.customfishing.mechanic.totem.block.TotemBlock;
|
||||
import net.momirealms.customfishing.mechanic.totem.block.TotemBlockProperty;
|
||||
import net.momirealms.customfishing.mechanic.totem.block.property.TotemBlockProperty;
|
||||
import net.momirealms.customfishing.mechanic.totem.block.type.TypeCondition;
|
||||
import net.momirealms.customfishing.mechanic.totem.particle.DustParticleSetting;
|
||||
import net.momirealms.customfishing.mechanic.totem.particle.ParticleSetting;
|
||||
@@ -58,6 +59,7 @@ public class TotemManagerImpl implements TotemManager, Listener {
|
||||
private final HashMap<String, List<TotemConfig>> totemConfigMap;
|
||||
private final List<String> allMaterials;
|
||||
private final ConcurrentHashMap<SimpleLocation, ActivatedTotem> activatedTotems;
|
||||
private CancellableTask timerCheckTask;
|
||||
|
||||
public TotemManagerImpl(CustomFishingPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
@@ -69,6 +71,21 @@ public class TotemManagerImpl implements TotemManager, Listener {
|
||||
public void load() {
|
||||
this.loadConfig();
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
this.timerCheckTask = plugin.getScheduler().runTaskAsyncTimer(() -> {
|
||||
long time = System.currentTimeMillis();
|
||||
ArrayList<SimpleLocation> removed = new ArrayList<>();
|
||||
for (Map.Entry<SimpleLocation, ActivatedTotem> entry : activatedTotems.entrySet()) {
|
||||
if (time > entry.getValue().getExpireTime()) {
|
||||
removed.add(entry.getKey());
|
||||
entry.getValue().cancel();
|
||||
} else {
|
||||
entry.getValue().doTimerAction();
|
||||
}
|
||||
}
|
||||
for (SimpleLocation simpleLocation : removed) {
|
||||
activatedTotems.remove(simpleLocation);
|
||||
}
|
||||
}, 1, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public void unload() {
|
||||
@@ -78,6 +95,8 @@ public class TotemManagerImpl implements TotemManager, Listener {
|
||||
}
|
||||
activatedTotems.clear();
|
||||
HandlerList.unregisterAll(this);
|
||||
if (this.timerCheckTask != null && !this.timerCheckTask.isCancelled())
|
||||
this.timerCheckTask.cancel();
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
@@ -89,7 +108,7 @@ public class TotemManagerImpl implements TotemManager, Listener {
|
||||
public EffectCarrier getTotemEffect(Location location) {
|
||||
for (ActivatedTotem activatedTotem : activatedTotems.values()) {
|
||||
if (LocationUtils.getDistance(activatedTotem.getCoreLocation(), location) < activatedTotem.getTotemConfig().getRadius()) {
|
||||
return plugin.getEffectManager().getEffect("totem", activatedTotem.getTotemConfig().getKey());
|
||||
return activatedTotem.getEffectCarrier();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -151,11 +170,6 @@ public class TotemManagerImpl implements TotemManager, Listener {
|
||||
if (previous != null) {
|
||||
previous.cancel();
|
||||
}
|
||||
|
||||
plugin.getScheduler().runTaskAsyncLater(() -> {
|
||||
ActivatedTotem activated = this.activatedTotems.remove(simpleLocation);
|
||||
if (activated != null) activated.cancel();
|
||||
}, config.getDuration(), TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@@ -197,19 +211,17 @@ public class TotemManagerImpl implements TotemManager, Listener {
|
||||
|
||||
HashSet<String> coreMaterials = new HashSet<>();
|
||||
for (TotemBlock totemBlock : totemConfig.getTotemCore()) {
|
||||
for (String text : totemBlock.getTypeCondition().getRawTexts()) {
|
||||
if (text.startsWith("*")) {
|
||||
String sub = text.substring(1);
|
||||
coreMaterials.addAll(allMaterials.stream().filter(it -> it.endsWith(sub)).toList());
|
||||
} else if (text.endsWith("*")) {
|
||||
String sub = text.substring(0, text.length() - 1);
|
||||
coreMaterials.addAll(allMaterials.stream().filter(it -> it.startsWith(sub)).toList());
|
||||
} else {
|
||||
coreMaterials.add(text);
|
||||
}
|
||||
String text = totemBlock.getTypeCondition().getRawText();
|
||||
if (text.startsWith("*")) {
|
||||
String sub = text.substring(1);
|
||||
coreMaterials.addAll(allMaterials.stream().filter(it -> it.endsWith(sub)).toList());
|
||||
} else if (text.endsWith("*")) {
|
||||
String sub = text.substring(0, text.length() - 1);
|
||||
coreMaterials.addAll(allMaterials.stream().filter(it -> it.startsWith(sub)).toList());
|
||||
} else {
|
||||
coreMaterials.add(text);
|
||||
}
|
||||
}
|
||||
|
||||
for (String material : coreMaterials) {
|
||||
putTotemConfigToMap(material, totemConfig);
|
||||
}
|
||||
@@ -319,6 +331,9 @@ public class TotemManagerImpl implements TotemManager, Listener {
|
||||
modelList.add(originalModel.mirrorHorizontally());
|
||||
}
|
||||
}
|
||||
for (TotemModel totemModel : modelList) {
|
||||
System.out.println(totemModel.toString());
|
||||
}
|
||||
return modelList.toArray(new TotemModel[0]);
|
||||
}
|
||||
|
||||
@@ -327,11 +342,14 @@ public class TotemManagerImpl implements TotemManager, Listener {
|
||||
ConfigurationSection layerSection = section.getConfigurationSection("layer");
|
||||
List<TotemBlock[][][]> totemBlocksList = new ArrayList<>();
|
||||
if (layerSection != null) {
|
||||
for (Map.Entry<String, Object> entry : layerSection.getValues(false).entrySet()) {
|
||||
var set = layerSection.getValues(false).entrySet();
|
||||
TotemBlock[][][][] totemBlocks = new TotemBlock[set.size()][][][];
|
||||
for (Map.Entry<String, Object> entry : set) {
|
||||
if (entry.getValue() instanceof List<?> list) {
|
||||
totemBlocksList.add(parseLayer((List<String>) list));
|
||||
totemBlocks[Integer.parseInt(entry.getKey())-1] = parseLayer((List<String>) list);
|
||||
}
|
||||
}
|
||||
totemBlocksList.addAll(List.of(totemBlocks));
|
||||
}
|
||||
|
||||
String[] core = section.getString("core","1,1,1").split(",");
|
||||
@@ -354,7 +372,7 @@ public class TotemManagerImpl implements TotemManager, Listener {
|
||||
|
||||
public TotemBlock[][] parseSingleLine(String line) {
|
||||
List<TotemBlock[]> totemBlocksList = new ArrayList<>();
|
||||
String[] splits = line.split("\\s");
|
||||
String[] splits = line.split("\\s+");
|
||||
for (String split : splits) {
|
||||
totemBlocksList.add(parseSingleElement(split));
|
||||
}
|
||||
@@ -371,12 +389,16 @@ public class TotemManagerImpl implements TotemManager, Listener {
|
||||
index = block.length();
|
||||
} else {
|
||||
String propertyStr = block.substring(index+1, block.length()-1);
|
||||
System.out.println(propertyStr);
|
||||
String[] properties = propertyStr.split(";");
|
||||
for (String property : properties) {
|
||||
System.out.println(property);
|
||||
String[] split = property.split("=");
|
||||
if (split.length <= 2) continue;
|
||||
if (split.length < 2) continue;
|
||||
String key = split[0];
|
||||
String value = split[1];
|
||||
System.out.println(key);
|
||||
System.out.println(value);
|
||||
switch (key) {
|
||||
case "face" -> {
|
||||
BlockFace blockFace = BlockFace.valueOf(value.toUpperCase(Locale.ENGLISH));
|
||||
|
||||
@@ -23,6 +23,8 @@ import org.bukkit.Axis;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
public class TotemModel implements Serializable {
|
||||
|
||||
@@ -58,6 +60,26 @@ public class TotemModel implements Serializable {
|
||||
return model;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (int h = 0; h < model.length; h++) {
|
||||
stringBuilder.append("layer: ").append(h + 1).append("\n");
|
||||
TotemBlock[][][] totemBlocks1 = model[h];
|
||||
for (TotemBlock[][] totemBlocks2 : totemBlocks1) {
|
||||
for (TotemBlock[] totemBlocks3 : totemBlocks2) {
|
||||
StringJoiner stringJoiner = new StringJoiner("||");
|
||||
for (TotemBlock totemBlock : totemBlocks3) {
|
||||
stringJoiner.add(totemBlock.toString());
|
||||
}
|
||||
stringBuilder.append(stringJoiner).append("\t");
|
||||
}
|
||||
stringBuilder.append("\n");
|
||||
}
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TotemModel clone() {
|
||||
return SerializationUtils.clone(this);
|
||||
@@ -139,7 +161,6 @@ public class TotemModel implements Serializable {
|
||||
int height = matrix.length;
|
||||
int rows = matrix[0].length;
|
||||
int cols = matrix[0][0].length;
|
||||
|
||||
TotemBlock[][][][] rotated = new TotemBlock[height][cols][rows][];
|
||||
for (int h = 0; h < height; h++) {
|
||||
for (int r = 0; r < rows; r++) {
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
|
||||
package net.momirealms.customfishing.mechanic.totem.block;
|
||||
|
||||
import net.momirealms.customfishing.mechanic.totem.block.property.TotemBlockProperty;
|
||||
import net.momirealms.customfishing.mechanic.totem.block.type.TypeCondition;
|
||||
import org.bukkit.Axis;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
public class TotemBlock implements Serializable {
|
||||
|
||||
@@ -64,4 +66,13 @@ public class TotemBlock implements Serializable {
|
||||
property.mirror(axis);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringJoiner stringJoiner = new StringJoiner(";");
|
||||
for (TotemBlockProperty property : properties) {
|
||||
stringJoiner.add(property.getRawText());
|
||||
}
|
||||
return typeCondition.getRawText() + "{" + stringJoiner + "}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,15 +15,18 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customfishing.mechanic.totem.block;
|
||||
package net.momirealms.customfishing.mechanic.totem.block.property;
|
||||
|
||||
import org.bukkit.Axis;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.Orientable;
|
||||
|
||||
public class AxisImpl implements TotemBlockProperty {
|
||||
import java.io.Serializable;
|
||||
import java.util.Locale;
|
||||
|
||||
private final Axis axis;
|
||||
public class AxisImpl implements TotemBlockProperty, Serializable {
|
||||
|
||||
private Axis axis;
|
||||
|
||||
public AxisImpl(Axis axis) {
|
||||
this.axis = axis;
|
||||
@@ -36,13 +39,12 @@ public class AxisImpl implements TotemBlockProperty {
|
||||
|
||||
@Override
|
||||
public TotemBlockProperty rotate90() {
|
||||
if (this.axis == Axis.Y) {
|
||||
return this;
|
||||
} else if (this.axis == Axis.X) {
|
||||
return new AxisImpl(Axis.Z);
|
||||
} else {
|
||||
return new AxisImpl(Axis.X);
|
||||
if (this.axis == Axis.X) {
|
||||
axis = Axis.Z;
|
||||
} else if (this.axis == Axis.Z) {
|
||||
axis = Axis.X;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -52,4 +54,9 @@ public class AxisImpl implements TotemBlockProperty {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRawText() {
|
||||
return "axis=" + axis.name().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
}
|
||||
@@ -15,16 +15,19 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customfishing.mechanic.totem.block;
|
||||
package net.momirealms.customfishing.mechanic.totem.block.property;
|
||||
|
||||
import org.bukkit.Axis;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.data.Directional;
|
||||
|
||||
public class FaceImpl implements TotemBlockProperty {
|
||||
import java.io.Serializable;
|
||||
import java.util.Locale;
|
||||
|
||||
private final BlockFace blockFace;
|
||||
public class FaceImpl implements TotemBlockProperty, Serializable {
|
||||
|
||||
private BlockFace blockFace;
|
||||
|
||||
public FaceImpl(BlockFace blockFace) {
|
||||
this.blockFace = blockFace;
|
||||
@@ -54,20 +57,13 @@ public class FaceImpl implements TotemBlockProperty {
|
||||
case UP, DOWN -> {
|
||||
return this;
|
||||
}
|
||||
case EAST -> {
|
||||
return new FaceImpl(BlockFace.SOUTH);
|
||||
}
|
||||
case SOUTH -> {
|
||||
return new FaceImpl(BlockFace.WEST);
|
||||
}
|
||||
case WEST -> {
|
||||
return new FaceImpl(BlockFace.NORTH);
|
||||
}
|
||||
case NORTH -> {
|
||||
return new FaceImpl(BlockFace.EAST);
|
||||
}
|
||||
case EAST -> blockFace = BlockFace.SOUTH;
|
||||
case SOUTH -> blockFace = BlockFace.WEST;
|
||||
case WEST -> blockFace = BlockFace.NORTH;
|
||||
case NORTH -> blockFace = BlockFace.EAST;
|
||||
default -> throw new IllegalArgumentException("Unsupported block facing: " + blockFace);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,4 +73,9 @@ public class FaceImpl implements TotemBlockProperty {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRawText() {
|
||||
return "face=" + blockFace.name().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customfishing.mechanic.totem.block;
|
||||
package net.momirealms.customfishing.mechanic.totem.block.property;
|
||||
|
||||
import org.bukkit.Axis;
|
||||
import org.bukkit.block.Block;
|
||||
@@ -28,4 +28,6 @@ public interface TotemBlockProperty {
|
||||
TotemBlockProperty rotate90();
|
||||
|
||||
boolean isPropertyMet(Block block);
|
||||
|
||||
String getRawText();
|
||||
}
|
||||
@@ -35,7 +35,7 @@ public class EndWithType implements TypeCondition, Serializable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getRawTexts() {
|
||||
return new String[]{"*" + end};
|
||||
public String getRawText() {
|
||||
return "*" + end;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
package net.momirealms.customfishing.mechanic.totem.block.type;
|
||||
|
||||
import net.momirealms.customfishing.api.CustomFishingPlugin;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import java.io.Serializable;
|
||||
@@ -31,11 +32,11 @@ public class EqualType implements TypeCondition, Serializable {
|
||||
|
||||
@Override
|
||||
public boolean isMet(Block type) {
|
||||
return this.type.equals(type.getType().name());
|
||||
return this.type.equals(CustomFishingPlugin.get().getBlockManager().getAnyBlockID(type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getRawTexts() {
|
||||
return new String[]{type};
|
||||
public String getRawText() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) <2022> <XiaoMoMi>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customfishing.mechanic.totem.block.type;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class OrType implements TypeCondition, Serializable {
|
||||
|
||||
private final TypeCondition[] typeConditions;
|
||||
|
||||
public OrType(TypeCondition[] typeConditions) {
|
||||
this.typeConditions = typeConditions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMet(Block block) {
|
||||
for (TypeCondition typeCondition : typeConditions) {
|
||||
if (typeCondition.isMet(block)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getRawTexts() {
|
||||
HashSet<String> strings = new HashSet<>();
|
||||
for (TypeCondition condition : typeConditions) {
|
||||
strings.addAll(List.of(condition.getRawTexts()));
|
||||
}
|
||||
return strings.toArray(new String[0]);
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ public class StartWithType implements TypeCondition, Serializable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getRawTexts() {
|
||||
return new String[]{start + "*"};
|
||||
public String getRawText() {
|
||||
return start + "*";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,26 +19,17 @@ package net.momirealms.customfishing.mechanic.totem.block.type;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public interface TypeCondition {
|
||||
|
||||
boolean isMet(Block block);
|
||||
|
||||
String[] getRawTexts();
|
||||
String getRawText();
|
||||
|
||||
static TypeCondition getTypeCondition(String raw) {
|
||||
if (raw.startsWith("*")) {
|
||||
return new EndWithType(raw.substring(1));
|
||||
} else if (raw.endsWith("*")) {
|
||||
return new StartWithType(raw.substring(0, raw.length() -1));
|
||||
} else if (raw.contains("||")) {
|
||||
String[] split = raw.split("\\|\\|");
|
||||
List<TypeCondition> typeConditionList = new ArrayList<>();
|
||||
for (String element : split)
|
||||
typeConditionList.add(getTypeCondition(element));
|
||||
return new OrType(typeConditionList.toArray(new TypeCondition[0]));
|
||||
} else {
|
||||
return new EqualType(raw);
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
package net.momirealms.customfishing.util;
|
||||
|
||||
public class MatrixUtils {
|
||||
|
||||
public static <T> T[][] rotate90(T[][] matrix) {
|
||||
int rows = matrix.length;
|
||||
if (rows == 0) {
|
||||
return matrix;
|
||||
}
|
||||
int cols = matrix[0].length;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
T[][] rotated = (T[][]) new Object[cols][rows];
|
||||
|
||||
for (int r = 0; r < rows; r++) {
|
||||
for (int c = 0; c < cols; c++) {
|
||||
rotated[c][rows - 1 - r] = matrix[r][c];
|
||||
}
|
||||
}
|
||||
return rotated;
|
||||
}
|
||||
|
||||
public static <T> void mirrorHorizontally(T[][] matrix) {
|
||||
int rows = matrix.length;
|
||||
int cols = matrix[0].length;
|
||||
|
||||
for (int i = 0; i < rows / 2; i++) {
|
||||
for (int j = 0; j < cols; j++) {
|
||||
T temp = matrix[i][j];
|
||||
matrix[i][j] = matrix[rows - i - 1][j];
|
||||
matrix[rows - i - 1][j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> void mirrorVertically(T[][] matrix) {
|
||||
int rows = matrix.length;
|
||||
int cols = matrix[0].length;
|
||||
|
||||
for (int i = 0; i < rows; i++) {
|
||||
for (int j = 0; j < cols / 2; j++) {
|
||||
T temp = matrix[i][j];
|
||||
matrix[i][j] = matrix[i][cols - j - 1];
|
||||
matrix[i][cols - j - 1] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,72 @@
|
||||
double_loot_fishing_totem:
|
||||
double_loot_totem:
|
||||
radius: 8
|
||||
duration: 300
|
||||
requirements: {}
|
||||
pattern:
|
||||
core: 3,1,2 # layer:3 line:1 index:2 -> CRYING_OBSIDIAN
|
||||
layer:
|
||||
4:
|
||||
- '*_STAIRS{face=east} OBSERVER{face=south} *_STAIRS{face=west}'
|
||||
3:
|
||||
- 'AIR CRYING_OBSIDIAN AIR'
|
||||
2:
|
||||
- 'AIR *_LOG{axis=y}||*_PILLAR{axis=y} AIR'
|
||||
1:
|
||||
- 'AIR ANVIL AIR'
|
||||
effects:
|
||||
double_loot:
|
||||
type: multiple-loot
|
||||
value: 1.0
|
||||
requirements:
|
||||
requirement_1:
|
||||
type: item-in-hand
|
||||
value:
|
||||
hand: main
|
||||
item: NAUTILUS_SHELL
|
||||
amount: 1
|
||||
not-met-actions:
|
||||
action_1:
|
||||
type: message
|
||||
value:
|
||||
- '<#BA55D3>[TotemActivation]</#BA55D3> <#F5FFFA>Hold a nautilus shell in main hand to activate the totem.'
|
||||
events:
|
||||
timer:
|
||||
actionbar_action:
|
||||
type: actionbar-nearby
|
||||
value:
|
||||
actionbar: '<#BA55D3>[Double Loot Totem]</#BA55D3> Time Left: {time_left} seconds'
|
||||
range: 16
|
||||
hologram_action_1:
|
||||
type: hologram
|
||||
value:
|
||||
duration: 20
|
||||
text: '<#BA55D3>[Double Loot Totem]</#BA55D3>'
|
||||
position: other
|
||||
range: 16
|
||||
y: 3.3
|
||||
x: 0
|
||||
z: 0
|
||||
hologram_action_2:
|
||||
type: hologram
|
||||
value:
|
||||
duration: 20
|
||||
text: 'Time Left: {time_left} seconds'
|
||||
position: other
|
||||
range: 16
|
||||
y: 2.8
|
||||
x: 0
|
||||
z: 0
|
||||
activate:
|
||||
remove_item_action:
|
||||
type: item-amount
|
||||
value:
|
||||
hand: main
|
||||
amount: -1
|
||||
broadcast_action:
|
||||
type: message-nearby
|
||||
value:
|
||||
message:
|
||||
- '<#BA55D3>[TotemActivation]</#BA55D3> <#F5FFFA>{player}</#F5FFFA> <#F5F5F5>activated a totem nearby!</#F5F5F5>'
|
||||
range: 32
|
||||
particles:
|
||||
particle_01:
|
||||
type: REDSTONE
|
||||
@@ -138,26 +203,97 @@ double_loot_fishing_totem:
|
||||
task:
|
||||
period: 40
|
||||
delay: 20
|
||||
golden_star_totem:
|
||||
radius: 10
|
||||
duration: 120
|
||||
pattern:
|
||||
core: 4,2,2 # layer:4 line:2 index:2 -> DAYLIGHT_DETECTOR
|
||||
layer:
|
||||
4:
|
||||
- 'AIR AIR AIR'
|
||||
- 'AIR DAYLIGHT_DETECTOR AIR'
|
||||
- 'AIR AIR AIR'
|
||||
3:
|
||||
- 'AIR AIR AIR'
|
||||
- 'AIR LIGHTNING_ROD AIR'
|
||||
- 'AIR AIR AIR'
|
||||
2:
|
||||
- 'AIR AIR AIR'
|
||||
- 'AIR GOLD_BLOCK AIR'
|
||||
- 'AIR AIR AIR'
|
||||
1:
|
||||
- 'AIR GOLD_BLOCK AIR'
|
||||
- 'GOLD_BLOCK GOLD_BLOCK GOLD_BLOCK'
|
||||
- 'AIR GOLD_BLOCK AIR'
|
||||
particles:
|
||||
particle_01:
|
||||
type: REDSTONE
|
||||
options:
|
||||
color: 255,215,0
|
||||
scale: 3
|
||||
polar-coordinates-formula:
|
||||
horizontal: '{radius} + sin({theta} * 5) * 2.5'
|
||||
vertical: '-2.5'
|
||||
theta:
|
||||
draw-interval: 5
|
||||
range:
|
||||
- 0~360
|
||||
task:
|
||||
period: 5
|
||||
delay: 0
|
||||
effects:
|
||||
double_loot:
|
||||
type: multiple-loot
|
||||
value: 1.0
|
||||
golden_weight_increase:
|
||||
type: group-mod
|
||||
value:
|
||||
- golden_star:+15
|
||||
requirements:
|
||||
requirement_1:
|
||||
type: item-in-hand
|
||||
value:
|
||||
hand: main
|
||||
item: GOLD_INGOT
|
||||
amount: 1
|
||||
not-met-actions:
|
||||
action_1:
|
||||
type: message
|
||||
value:
|
||||
- '<#BA55D3>[TotemActivation]</#BA55D3> <#F5FFFA>Hold a gold ingot in main hand to activate the totem.'
|
||||
events:
|
||||
timer:
|
||||
actionbar_action:
|
||||
type: actionbar-nearby
|
||||
value:
|
||||
actionbar: '<#FFFF00>[Golden Star Totem]</#FFFF00> Time Left: {time_left} seconds'
|
||||
range: 16
|
||||
hologram_action_1:
|
||||
type: hologram
|
||||
value:
|
||||
duration: 20
|
||||
text: '<#FFFF00>[Golden Star Totem]</#FFFF00>'
|
||||
position: other
|
||||
range: 16
|
||||
y: 1
|
||||
x: 0
|
||||
z: 0
|
||||
hologram_action_2:
|
||||
type: hologram
|
||||
value:
|
||||
duration: 20
|
||||
text: 'Time Left: {time_left} seconds'
|
||||
position: other
|
||||
range: 16
|
||||
y: 0.5
|
||||
x: 0
|
||||
z: 0
|
||||
activate:
|
||||
remove_item_action:
|
||||
type: item-amount
|
||||
value:
|
||||
hand: main
|
||||
amount: -1
|
||||
broadcast_action:
|
||||
type: message-nearby
|
||||
value:
|
||||
message:
|
||||
- '<#BA55D3>[TotemActivation]</#BA55D3> <#F5FFFA>{player}</#F5FFFA> <#F5F5F5>activated a totem nearby!</#F5F5F5>'
|
||||
range: 32
|
||||
pattern:
|
||||
core: 3,1,2 # layer:3 line:1 index:2 -> CRYING_OBSIDIAN
|
||||
layer:
|
||||
1:
|
||||
- 'AIR ANVIL AIR'
|
||||
2:
|
||||
- 'AIR *_LOG{axis:y}||*_PILLAR{axis:y} AIR'
|
||||
3:
|
||||
- 'AIR CRYING_OBSIDIAN AIR'
|
||||
4:
|
||||
- '*_STAIRS{face:south} OBSERVER{face:west} *_STAIRS{face:north}'
|
||||
- '<#FFFF00>[TotemActivation]</#FFFF00> <#F5FFFA>{player}</#F5FFFA> <#F5F5F5>activated a totem nearby!</#F5F5F5>'
|
||||
range: 32
|
||||
@@ -44,8 +44,6 @@ global-group:
|
||||
- rainbow_7:+1
|
||||
ocean_fish_game:
|
||||
conditions:
|
||||
group:
|
||||
- ocean
|
||||
biome:
|
||||
- minecraft:ocean
|
||||
- minecraft:deep_ocean
|
||||
@@ -78,8 +76,16 @@ global-group:
|
||||
- tension_game_hard:+7
|
||||
river_fish_game:
|
||||
conditions:
|
||||
group:
|
||||
- river
|
||||
'!biome':
|
||||
- minecraft:ocean
|
||||
- minecraft:deep_ocean
|
||||
- minecraft:cold_ocean
|
||||
- minecraft:deep_cold_ocean
|
||||
- minecraft:frozen_ocean
|
||||
- minecraft:deep_frozen_ocean
|
||||
- minecraft:lukewarm_ocean
|
||||
- minecraft:deep_lukewarm_ocean
|
||||
- minecraft:warm_ocean
|
||||
list:
|
||||
- accurate_click_bar_1_easy:+15
|
||||
- accurate_click_bar_1_normal:+5
|
||||
|
||||
Reference in New Issue
Block a user