9
0
mirror of https://github.com/Xiao-MoMi/Custom-Fishing.git synced 2025-12-26 10:29:16 +00:00
This commit is contained in:
XiaoMoMi
2023-09-17 23:06:47 +08:00
parent a03b0ab729
commit b61391cea6
22 changed files with 518 additions and 230 deletions

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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;
});
}

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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));

View File

@@ -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++) {

View File

@@ -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 + "}";
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}

View File

@@ -35,7 +35,7 @@ public class EndWithType implements TypeCondition, Serializable {
}
@Override
public String[] getRawTexts() {
return new String[]{"*" + end};
public String getRawText() {
return "*" + end;
}
}

View File

@@ -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;
}
}

View File

@@ -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]);
}
}

View File

@@ -35,7 +35,7 @@ public class StartWithType implements TypeCondition, Serializable {
}
@Override
public String[] getRawTexts() {
return new String[]{start + "*"};
public String getRawText() {
return start + "*";
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}
}
}

View File

@@ -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

View File

@@ -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