mirror of
https://github.com/Xiao-MoMi/Custom-Crops.git
synced 2025-12-25 18:09:28 +00:00
3.6
This commit is contained in:
@@ -1,192 +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.customcrops;
|
||||
|
||||
import net.momirealms.antigrieflib.AntiGriefLib;
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.event.CustomCropsReloadEvent;
|
||||
import net.momirealms.customcrops.api.manager.ConfigManager;
|
||||
import net.momirealms.customcrops.api.manager.CoolDownManager;
|
||||
import net.momirealms.customcrops.api.util.EventUtils;
|
||||
import net.momirealms.customcrops.api.util.LogUtils;
|
||||
import net.momirealms.customcrops.compatibility.IntegrationManagerImpl;
|
||||
import net.momirealms.customcrops.libraries.classpath.ReflectionClassPathAppender;
|
||||
import net.momirealms.customcrops.libraries.dependencies.Dependency;
|
||||
import net.momirealms.customcrops.libraries.dependencies.DependencyManager;
|
||||
import net.momirealms.customcrops.libraries.dependencies.DependencyManagerImpl;
|
||||
import net.momirealms.customcrops.manager.*;
|
||||
import net.momirealms.customcrops.mechanic.action.ActionManagerImpl;
|
||||
import net.momirealms.customcrops.mechanic.condition.ConditionManagerImpl;
|
||||
import net.momirealms.customcrops.mechanic.item.ItemManagerImpl;
|
||||
import net.momirealms.customcrops.mechanic.item.factory.BukkitItemFactory;
|
||||
import net.momirealms.customcrops.mechanic.misc.migrator.Migration;
|
||||
import net.momirealms.customcrops.mechanic.requirement.RequirementManagerImpl;
|
||||
import net.momirealms.customcrops.mechanic.world.WorldManagerImpl;
|
||||
import net.momirealms.customcrops.scheduler.SchedulerImpl;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CustomCropsPluginImpl extends CustomCropsPlugin {
|
||||
|
||||
private DependencyManager dependencyManager;
|
||||
private PacketManager packetManager;
|
||||
private CommandManager commandManager;
|
||||
private HologramManager hologramManager;
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
this.versionManager = new VersionManagerImpl(this);
|
||||
this.dependencyManager = new DependencyManagerImpl(this, new ReflectionClassPathAppender(this.getClassLoader()));
|
||||
this.dependencyManager.loadDependencies(new ArrayList<>(
|
||||
List.of(
|
||||
Dependency.GSON,
|
||||
Dependency.EXP4J,
|
||||
Dependency.SLF4J_API,
|
||||
Dependency.SLF4J_SIMPLE,
|
||||
versionManager.isMojmap() ? Dependency.COMMAND_API_MOJMAP : Dependency.COMMAND_API,
|
||||
Dependency.BOOSTED_YAML,
|
||||
Dependency.BSTATS_BASE,
|
||||
Dependency.BSTATS_BUKKIT
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
instance = this;
|
||||
this.adventure = new AdventureManagerImpl(this);
|
||||
this.scheduler = new SchedulerImpl(this);
|
||||
this.configManager = new ConfigManagerImpl(this);
|
||||
this.integrationManager = new IntegrationManagerImpl(this);
|
||||
this.conditionManager = new ConditionManagerImpl(this);
|
||||
this.actionManager = new ActionManagerImpl(this);
|
||||
this.requirementManager = new RequirementManagerImpl(this);
|
||||
this.coolDownManager = new CoolDownManager(this);
|
||||
this.worldManager = new WorldManagerImpl(this);
|
||||
this.itemManager = new ItemManagerImpl(this,
|
||||
AntiGriefLib.builder(this)
|
||||
.silentLogs(true)
|
||||
.ignoreOP(true)
|
||||
.build()
|
||||
);
|
||||
this.messageManager = new MessageManagerImpl(this);
|
||||
this.packetManager = new PacketManager(this);
|
||||
this.commandManager = new CommandManager(this);
|
||||
this.placeholderManager = new PlaceholderManagerImpl(this);
|
||||
this.hologramManager = new HologramManager(this);
|
||||
this.commandManager.init();
|
||||
try {
|
||||
this.integrationManager.init();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
BukkitItemFactory.create(this);
|
||||
Migration.tryUpdating();
|
||||
this.reload();
|
||||
if (ConfigManager.metrics()) new Metrics(this, 16593);
|
||||
if (ConfigManager.checkUpdate()) {
|
||||
this.versionManager.checkUpdate().thenAccept(result -> {
|
||||
if (!result) this.getAdventure().sendConsoleMessage("[CustomCrops] You are using the latest version.");
|
||||
else this.getAdventure().sendConsoleMessage("[CustomCrops] Update is available: <u>https://polymart.org/resource/2625<!u>");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (this.commandManager != null) this.commandManager.disable();
|
||||
if (this.adventure != null) this.adventure.disable();
|
||||
if (this.requirementManager != null) this.requirementManager.disable();
|
||||
if (this.actionManager != null) this.actionManager.disable();
|
||||
if (this.worldManager != null) this.worldManager.disable();
|
||||
if (this.itemManager != null) this.itemManager.disable();
|
||||
if (this.conditionManager != null) this.conditionManager.disable();
|
||||
if (this.coolDownManager != null) this.coolDownManager.disable();
|
||||
if (this.placeholderManager != null) this.placeholderManager.disable();
|
||||
if (this.scheduler != null) ((SchedulerImpl) scheduler).shutdown();
|
||||
instance = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
this.configManager.reload();
|
||||
this.messageManager.reload();
|
||||
this.itemManager.reload();
|
||||
this.worldManager.reload();
|
||||
this.actionManager.reload();
|
||||
this.requirementManager.reload();
|
||||
this.conditionManager.reload();
|
||||
this.coolDownManager.reload();
|
||||
this.placeholderManager.reload();
|
||||
this.hologramManager.reload();
|
||||
((SchedulerImpl) scheduler).reload();
|
||||
EventUtils.fireAndForget(new CustomCropsReloadEvent(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String debug) {
|
||||
if (ConfigManager.debug()) {
|
||||
LogUtils.info(debug);
|
||||
}
|
||||
}
|
||||
|
||||
public DependencyManager getDependencyManager() {
|
||||
return dependencyManager;
|
||||
}
|
||||
|
||||
public PacketManager getPacketManager() {
|
||||
return packetManager;
|
||||
}
|
||||
|
||||
public HologramManager getHologramManager() {
|
||||
return hologramManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHookedPluginEnabled(String plugin) {
|
||||
return Bukkit.getPluginManager().isPluginEnabled(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isHookedPluginEnabled(String hooked, String... versionPrefix) {
|
||||
Plugin p = Bukkit.getPluginManager().getPlugin(hooked);
|
||||
if (p != null) {
|
||||
String ver = p.getDescription().getVersion();
|
||||
for (String prefix : versionPrefix) {
|
||||
if (ver.startsWith(prefix)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesHookedPluginExist(String plugin) {
|
||||
return Bukkit.getPluginManager().getPlugin(plugin) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerVersion() {
|
||||
return Bukkit.getServer().getBukkitVersion().split("-")[0];
|
||||
}
|
||||
}
|
||||
@@ -15,21 +15,28 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.util;
|
||||
package net.momirealms.customcrops.bukkit;
|
||||
|
||||
import org.bukkit.Particle;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class ParticleUtils {
|
||||
public class BukkitBootstrap extends JavaPlugin {
|
||||
|
||||
public static Particle getParticle(String particle) {
|
||||
try {
|
||||
return Particle.valueOf(particle);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return switch (particle) {
|
||||
case "REDSTONE" -> Particle.valueOf("DUST");
|
||||
case "VILLAGER_HAPPY" -> Particle.valueOf("HAPPY_VILLAGER");
|
||||
default -> Particle.valueOf(particle);
|
||||
};
|
||||
}
|
||||
private BukkitCustomCropsPlugin plugin;
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
this.plugin = new BukkitCustomCropsPluginImpl(this);
|
||||
this.plugin.load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
this.plugin.enable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
this.plugin.disable();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
package net.momirealms.customcrops.bukkit;
|
||||
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.core.ConfigManager;
|
||||
import net.momirealms.customcrops.api.core.SimpleRegistryAccess;
|
||||
import net.momirealms.customcrops.api.core.block.*;
|
||||
import net.momirealms.customcrops.api.core.item.*;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
|
||||
import net.momirealms.customcrops.api.event.CustomCropsReloadEvent;
|
||||
import net.momirealms.customcrops.api.misc.cooldown.CoolDownManager;
|
||||
import net.momirealms.customcrops.api.misc.placeholder.BukkitPlaceholderManager;
|
||||
import net.momirealms.customcrops.api.util.EventUtils;
|
||||
import net.momirealms.customcrops.bukkit.action.BlockActionManager;
|
||||
import net.momirealms.customcrops.bukkit.action.PlayerActionManager;
|
||||
import net.momirealms.customcrops.bukkit.command.BukkitCommandManager;
|
||||
import net.momirealms.customcrops.bukkit.config.BukkitConfigManager;
|
||||
import net.momirealms.customcrops.bukkit.integration.BukkitIntegrationManager;
|
||||
import net.momirealms.customcrops.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.customcrops.bukkit.misc.HologramManager;
|
||||
import net.momirealms.customcrops.bukkit.requirement.BlockRequirementManager;
|
||||
import net.momirealms.customcrops.bukkit.requirement.PlayerRequirementManager;
|
||||
import net.momirealms.customcrops.bukkit.scheduler.BukkitSchedulerAdapter;
|
||||
import net.momirealms.customcrops.bukkit.sender.BukkitSenderFactory;
|
||||
import net.momirealms.customcrops.bukkit.world.BukkitWorldManager;
|
||||
import net.momirealms.customcrops.common.config.ConfigLoader;
|
||||
import net.momirealms.customcrops.common.dependency.Dependency;
|
||||
import net.momirealms.customcrops.common.dependency.DependencyManagerImpl;
|
||||
import net.momirealms.customcrops.common.helper.VersionHelper;
|
||||
import net.momirealms.customcrops.common.locale.TranslationManager;
|
||||
import net.momirealms.customcrops.common.plugin.classpath.ClassPathAppender;
|
||||
import net.momirealms.customcrops.common.plugin.classpath.ReflectionClassPathAppender;
|
||||
import net.momirealms.customcrops.common.plugin.feature.Reloadable;
|
||||
import net.momirealms.customcrops.common.plugin.logging.JavaPluginLogger;
|
||||
import net.momirealms.customcrops.common.plugin.logging.PluginLogger;
|
||||
import net.momirealms.sparrow.heart.SparrowHeart;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class BukkitCustomCropsPluginImpl extends BukkitCustomCropsPlugin {
|
||||
|
||||
private final ClassPathAppender classPathAppender;
|
||||
private final PluginLogger logger;
|
||||
private BukkitCommandManager commandManager;
|
||||
private HologramManager hologramManager;
|
||||
private Consumer<Object> debugger;
|
||||
private String buildByBit = "%%__BUILTBYBIT__%%";
|
||||
private String polymart = "%%__POLYMART__%%";
|
||||
private String time = "%%__TIMESTAMP__%%";
|
||||
private String user = "%%__USER__%%";
|
||||
private String username = "%%__USERNAME__%%";
|
||||
|
||||
public BukkitCustomCropsPluginImpl(Plugin boostrap) {
|
||||
super(boostrap);
|
||||
VersionHelper.init(getServerVersion());
|
||||
this.scheduler = new BukkitSchedulerAdapter(this);
|
||||
this.logger = new JavaPluginLogger(getBoostrap().getLogger());
|
||||
this.classPathAppender = new ReflectionClassPathAppender(this);
|
||||
this.dependencyManager = new DependencyManagerImpl(this);
|
||||
this.registryAccess = new SimpleRegistryAccess(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Object message) {
|
||||
if (this.debugger != null)
|
||||
this.debugger.accept(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResourceStream(String filePath) {
|
||||
return getBoostrap().getResource(filePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PluginLogger getPluginLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassPathAppender getClassPathAppender() {
|
||||
return classPathAppender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Path getDataDirectory() {
|
||||
return getBoostrap().getDataFolder().toPath().toAbsolutePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigLoader getConfigManager() {
|
||||
return configManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerVersion() {
|
||||
return Bukkit.getServer().getBukkitVersion().split("-")[0];
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public String getPluginVersion() {
|
||||
return getBoostrap().getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
this.dependencyManager.loadDependencies(
|
||||
List.of(
|
||||
Dependency.BOOSTED_YAML,
|
||||
Dependency.BSTATS_BASE, Dependency.BSTATS_BUKKIT,
|
||||
Dependency.CAFFEINE,
|
||||
Dependency.GEANTY_REF,
|
||||
Dependency.CLOUD_CORE, Dependency.CLOUD_SERVICES, Dependency.CLOUD_BUKKIT, Dependency.CLOUD_PAPER, Dependency.CLOUD_BRIGADIER, Dependency.CLOUD_MINECRAFT_EXTRAS,
|
||||
Dependency.GSON,
|
||||
Dependency.EXP4J,
|
||||
Dependency.ZSTD
|
||||
)
|
||||
);
|
||||
this.registerDefaultMechanics();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
SparrowHeart.getInstance();
|
||||
this.configManager = new BukkitConfigManager(this);
|
||||
super.requirementManagers.put(Player.class, new PlayerRequirementManager(this));
|
||||
super.requirementManagers.put(CustomCropsBlockState.class, new BlockRequirementManager(this));
|
||||
super.actionManagers.put(Player.class, new PlayerActionManager(this));
|
||||
super.actionManagers.put(CustomCropsBlockState.class, new BlockActionManager(this));
|
||||
this.translationManager = new TranslationManager(this);
|
||||
this.senderFactory = new BukkitSenderFactory(this);
|
||||
this.itemManager = new BukkitItemManager(this);
|
||||
this.integrationManager = new BukkitIntegrationManager(this);
|
||||
this.placeholderManager = new BukkitPlaceholderManager(this);
|
||||
this.coolDownManager = new CoolDownManager(this);
|
||||
this.worldManager = new BukkitWorldManager(this);
|
||||
this.hologramManager = new HologramManager(this);
|
||||
this.commandManager = new BukkitCommandManager(this);
|
||||
this.commandManager.registerDefaultFeatures();
|
||||
|
||||
boolean downloadFromPolymart = polymart.equals("1");
|
||||
boolean downloadFromBBB = buildByBit.equals("true");
|
||||
|
||||
this.getScheduler().sync().runLater(() -> {
|
||||
this.reload();
|
||||
((SimpleRegistryAccess) registryAccess).freeze();
|
||||
if (ConfigManager.metrics()) new Metrics((JavaPlugin) getBoostrap(), 16593);
|
||||
if (ConfigManager.checkUpdate()) {
|
||||
VersionHelper.UPDATE_CHECKER.apply(this).thenAccept(result -> {
|
||||
String link;
|
||||
if (downloadFromPolymart) {
|
||||
link = "https://polymart.org/resource/2625/";
|
||||
} else if (downloadFromBBB) {
|
||||
link = "https://builtbybit.com/resources/36363/";
|
||||
} else {
|
||||
link = "https://github.com/Xiao-MoMi/Custom-Crops/";
|
||||
}
|
||||
if (!result) {
|
||||
this.getPluginLogger().info("You are using the latest version.");
|
||||
} else {
|
||||
this.getPluginLogger().warn("Update is available: " + link);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, 1, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
this.worldManager.disable();
|
||||
this.placeholderManager.disable();
|
||||
this.hologramManager.disable();
|
||||
this.integrationManager.disable();
|
||||
this.coolDownManager.disable();
|
||||
this.commandManager.unregisterFeatures();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
|
||||
this.worldManager.unload();
|
||||
|
||||
this.configManager.reload();
|
||||
this.debugger = ConfigManager.debug() ? (s) -> logger.info("[DEBUG] " + s.toString()) : (s) -> {};
|
||||
this.coolDownManager.reload();
|
||||
this.placeholderManager.reload();
|
||||
this.translationManager.reload();
|
||||
this.hologramManager.reload();
|
||||
|
||||
this.actionManagers.values().forEach(Reloadable::reload);
|
||||
this.requirementManagers.values().forEach(Reloadable::reload);
|
||||
|
||||
this.worldManager.load();
|
||||
|
||||
EventUtils.fireAndForget(new CustomCropsReloadEvent(this));
|
||||
}
|
||||
|
||||
private void registerDefaultMechanics() {
|
||||
registryAccess.registerFertilizerType(FertilizerType.SPEED_GROW);
|
||||
registryAccess.registerFertilizerType(FertilizerType.QUALITY);
|
||||
registryAccess.registerFertilizerType(FertilizerType.SOIL_RETAIN);
|
||||
registryAccess.registerFertilizerType(FertilizerType.VARIATION);
|
||||
registryAccess.registerFertilizerType(FertilizerType.YIELD_INCREASE);
|
||||
|
||||
registryAccess.registerBlockMechanic(new CropBlock());
|
||||
registryAccess.registerBlockMechanic(new PotBlock());
|
||||
registryAccess.registerBlockMechanic(new ScarecrowBlock());
|
||||
registryAccess.registerBlockMechanic(new SprinklerBlock());
|
||||
registryAccess.registerBlockMechanic(new GreenhouseBlock());
|
||||
|
||||
registryAccess.registerItemMechanic(new SeedItem());
|
||||
registryAccess.registerItemMechanic(new WateringCanItem());
|
||||
registryAccess.registerItemMechanic(new FertilizerItem());
|
||||
registryAccess.registerItemMechanic(new SprinklerItem());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package net.momirealms.customcrops.bukkit.action;
|
||||
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.action.AbstractActionManager;
|
||||
import net.momirealms.customcrops.api.action.Action;
|
||||
import net.momirealms.customcrops.api.context.ContextKeys;
|
||||
import net.momirealms.customcrops.api.core.CustomForm;
|
||||
import net.momirealms.customcrops.api.core.ExistenceForm;
|
||||
import net.momirealms.customcrops.api.core.FurnitureRotation;
|
||||
import net.momirealms.customcrops.api.core.block.CropBlock;
|
||||
import net.momirealms.customcrops.api.core.block.PotBlock;
|
||||
import net.momirealms.customcrops.api.core.block.VariationData;
|
||||
import net.momirealms.customcrops.api.core.item.Fertilizer;
|
||||
import net.momirealms.customcrops.api.core.item.FertilizerConfig;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsChunk;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
|
||||
import net.momirealms.customcrops.api.core.world.Pos3;
|
||||
import org.bukkit.Location;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class BlockActionManager extends AbstractActionManager<CustomCropsBlockState> {
|
||||
|
||||
public BlockActionManager(BukkitCustomCropsPlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
loadExpansions(CustomCropsBlockState.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerBuiltInActions() {
|
||||
super.registerBuiltInActions();
|
||||
super.registerBundleAction(CustomCropsBlockState.class);
|
||||
this.registerVariationAction();
|
||||
}
|
||||
|
||||
private void registerVariationAction() {
|
||||
registerAction((args, chance) -> {
|
||||
if (args instanceof Section section) {
|
||||
boolean ignore = section.getBoolean("ignore-fertilizer", false);
|
||||
List<VariationData> variationDataList = new ArrayList<>();
|
||||
for (Map.Entry<String, Object> entry : section.getStringRouteMappedValues(false).entrySet()) {
|
||||
if (entry.getValue() instanceof Section inner) {
|
||||
VariationData variationData = new VariationData(
|
||||
inner.getString("item"),
|
||||
CustomForm.valueOf(inner.getString("type", "TripWire").toUpperCase(Locale.ENGLISH)).existenceForm(),
|
||||
inner.getDouble("chance")
|
||||
);
|
||||
variationDataList.add(variationData);
|
||||
}
|
||||
}
|
||||
VariationData[] variations = variationDataList.toArray(new VariationData[0]);
|
||||
return context -> {
|
||||
if (Math.random() > chance) return;
|
||||
if (!(context.holder().type() instanceof CropBlock cropBlock)) {
|
||||
return;
|
||||
}
|
||||
Fertilizer[] fertilizers = null;
|
||||
Location location = requireNonNull(context.arg(ContextKeys.LOCATION));
|
||||
Optional<CustomCropsWorld<?>> world = plugin.getWorldManager().getWorld(location.getWorld());
|
||||
if (world.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Pos3 pos3 = Pos3.from(location);
|
||||
if (!ignore) {
|
||||
Pos3 potLocation = pos3.add(0, -1, 0);
|
||||
Optional<CustomCropsChunk> chunk = world.get().getChunk(potLocation.toChunkPos());
|
||||
if (chunk.isPresent()) {
|
||||
Optional<CustomCropsBlockState> state = chunk.get().getBlockState(potLocation);
|
||||
if (state.isPresent()) {
|
||||
if (state.get().type() instanceof PotBlock potBlock) {
|
||||
fertilizers = potBlock.fertilizers(state.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ArrayList<FertilizerConfig> configs = new ArrayList<>();
|
||||
if (fertilizers != null) {
|
||||
for (Fertilizer fertilizer : fertilizers) {
|
||||
Optional.ofNullable(fertilizer.config()).ifPresent(configs::add);
|
||||
}
|
||||
}
|
||||
for (VariationData variationData : variations) {
|
||||
double variationChance = variationData.chance();
|
||||
for (FertilizerConfig fertilizer : configs) {
|
||||
variationChance = fertilizer.processVariationChance(variationChance);
|
||||
}
|
||||
if (Math.random() < variationChance) {
|
||||
plugin.getItemManager().remove(location, ExistenceForm.ANY);
|
||||
world.get().removeBlockState(pos3);
|
||||
plugin.getItemManager().place(location, variationData.existenceForm(), variationData.id(), FurnitureRotation.random());
|
||||
cropBlock.fixOrGetState(world.get(), pos3, variationData.id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at variation action which is expected to be `Section`");
|
||||
return Action.empty();
|
||||
}
|
||||
}, "variation");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,524 @@
|
||||
package net.momirealms.customcrops.bukkit.action;
|
||||
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.sound.Sound;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.action.AbstractActionManager;
|
||||
import net.momirealms.customcrops.api.action.Action;
|
||||
import net.momirealms.customcrops.api.context.ContextKeys;
|
||||
import net.momirealms.customcrops.api.core.block.CropBlock;
|
||||
import net.momirealms.customcrops.api.core.block.CropConfig;
|
||||
import net.momirealms.customcrops.api.core.block.CropStageConfig;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
|
||||
import net.momirealms.customcrops.api.core.world.Pos3;
|
||||
import net.momirealms.customcrops.api.misc.placeholder.BukkitPlaceholderManager;
|
||||
import net.momirealms.customcrops.api.misc.value.MathValue;
|
||||
import net.momirealms.customcrops.api.misc.value.TextValue;
|
||||
import net.momirealms.customcrops.api.util.LocationUtils;
|
||||
import net.momirealms.customcrops.api.util.PlayerUtils;
|
||||
import net.momirealms.customcrops.bukkit.integration.VaultHook;
|
||||
import net.momirealms.customcrops.bukkit.misc.HologramManager;
|
||||
import net.momirealms.customcrops.common.helper.AdventureHelper;
|
||||
import net.momirealms.customcrops.common.util.ListUtils;
|
||||
import net.momirealms.customcrops.common.util.RandomUtils;
|
||||
import net.momirealms.sparrow.heart.SparrowHeart;
|
||||
import net.momirealms.sparrow.heart.feature.inventory.HandSlot;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.ExperienceOrb;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class PlayerActionManager extends AbstractActionManager<Player> {
|
||||
|
||||
public PlayerActionManager(BukkitCustomCropsPlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
loadExpansions(Player.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerBuiltInActions() {
|
||||
super.registerBuiltInActions();
|
||||
super.registerBundleAction(Player.class);
|
||||
this.registerPlayerCommandAction();
|
||||
this.registerCloseInvAction();
|
||||
this.registerActionBarAction();
|
||||
this.registerExpAction();
|
||||
this.registerFoodAction();
|
||||
this.registerItemAction();
|
||||
this.registerMoneyAction();
|
||||
this.registerPotionAction();
|
||||
this.registerSoundAction();
|
||||
this.registerPluginExpAction();
|
||||
this.registerTitleAction();
|
||||
this.registerSwingHandAction();
|
||||
this.registerForceTickAction();
|
||||
this.registerHologramAction();
|
||||
this.registerMessageAction();
|
||||
}
|
||||
|
||||
private void registerMessageAction() {
|
||||
registerAction((args, chance) -> {
|
||||
List<String> messages = ListUtils.toList(args);
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
List<String> replaced = plugin.getPlaceholderManager().parse(context.holder(), messages, context.placeholderMap());
|
||||
Audience audience = plugin.getSenderFactory().getAudience(context.holder());
|
||||
for (String text : replaced) {
|
||||
audience.sendMessage(AdventureHelper.miniMessage(text));
|
||||
}
|
||||
};
|
||||
}, "message");
|
||||
registerAction((args, chance) -> {
|
||||
List<String> messages = ListUtils.toList(args);
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
String random = messages.get(RandomUtils.generateRandomInt(0, messages.size() - 1));
|
||||
random = BukkitPlaceholderManager.getInstance().parse(context.holder(), random, context.placeholderMap());
|
||||
Audience audience = plugin.getSenderFactory().getAudience(context.holder());
|
||||
audience.sendMessage(AdventureHelper.miniMessage(random));
|
||||
};
|
||||
}, "random-message");
|
||||
}
|
||||
|
||||
private void registerPlayerCommandAction() {
|
||||
registerAction((args, chance) -> {
|
||||
List<String> commands = ListUtils.toList(args);
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
List<String> replaced = BukkitPlaceholderManager.getInstance().parse(context.holder(), commands, context.placeholderMap());
|
||||
plugin.getScheduler().sync().run(() -> {
|
||||
for (String text : replaced) {
|
||||
context.holder().performCommand(text);
|
||||
}
|
||||
}, context.holder().getLocation());
|
||||
};
|
||||
}, "player-command");
|
||||
}
|
||||
|
||||
private void registerCloseInvAction() {
|
||||
registerAction((args, chance) -> context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
context.holder().closeInventory();
|
||||
}, "close-inv");
|
||||
}
|
||||
|
||||
private void registerActionBarAction() {
|
||||
registerAction((args, chance) -> {
|
||||
String text = (String) args;
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
Audience audience = plugin.getSenderFactory().getAudience(context.holder());
|
||||
Component component = AdventureHelper.miniMessage(plugin.getPlaceholderManager().parse(context.holder(), text, context.placeholderMap()));
|
||||
audience.sendActionBar(component);
|
||||
};
|
||||
}, "actionbar");
|
||||
registerAction((args, chance) -> {
|
||||
List<String> texts = ListUtils.toList(args);
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
String random = texts.get(RandomUtils.generateRandomInt(0, texts.size() - 1));
|
||||
random = plugin.getPlaceholderManager().parse(context.holder(), random, context.placeholderMap());
|
||||
Audience audience = plugin.getSenderFactory().getAudience(context.holder());
|
||||
audience.sendActionBar(AdventureHelper.miniMessage(random));
|
||||
};
|
||||
}, "random-actionbar");
|
||||
}
|
||||
|
||||
private void registerExpAction() {
|
||||
registerAction((args, chance) -> {
|
||||
MathValue<Player> value = MathValue.auto(args);
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
final Player player = context.holder();
|
||||
ExperienceOrb entity = player.getLocation().getWorld().spawn(player.getLocation().clone().add(0,0.5,0), ExperienceOrb.class);
|
||||
entity.setExperience((int) value.evaluate(context));
|
||||
};
|
||||
}, "mending");
|
||||
registerAction((args, chance) -> {
|
||||
MathValue<Player> value = MathValue.auto(args);
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
final Player player = context.holder();
|
||||
player.giveExp((int) Math.round(value.evaluate(context)));
|
||||
Audience audience = plugin.getSenderFactory().getAudience(player);
|
||||
AdventureHelper.playSound(audience, Sound.sound(Key.key("minecraft:entity.experience_orb.pickup"), Sound.Source.PLAYER, 1, 1));
|
||||
};
|
||||
}, "exp");
|
||||
registerAction((args, chance) -> {
|
||||
MathValue<Player> value = MathValue.auto(args);
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
Player player = context.holder();
|
||||
player.setLevel((int) Math.max(0, player.getLevel() + value.evaluate(context)));
|
||||
};
|
||||
}, "level");
|
||||
}
|
||||
|
||||
private void registerFoodAction() {
|
||||
registerAction((args, chance) -> {
|
||||
MathValue<Player> value = MathValue.auto(args);
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
Player player = context.holder();
|
||||
player.setFoodLevel((int) (player.getFoodLevel() + value.evaluate(context)));
|
||||
};
|
||||
}, "food");
|
||||
registerAction((args, chance) -> {
|
||||
MathValue<Player> value = MathValue.auto(args);
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
Player player = context.holder();
|
||||
player.setSaturation((float) (player.getSaturation() + value.evaluate(context)));
|
||||
};
|
||||
}, "saturation");
|
||||
}
|
||||
|
||||
private void registerItemAction() {
|
||||
registerAction((args, chance) -> {
|
||||
if (args instanceof Section section) {
|
||||
boolean mainOrOff = section.getString("hand", "main").equalsIgnoreCase("main");
|
||||
int amount = section.getInt("amount", 1);
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
Player player = context.holder();
|
||||
boolean tempHand = mainOrOff;
|
||||
EquipmentSlot hand = context.arg(ContextKeys.SLOT);
|
||||
if (hand == EquipmentSlot.OFF_HAND || hand == EquipmentSlot.HAND) {
|
||||
tempHand = hand == EquipmentSlot.HAND;
|
||||
}
|
||||
ItemStack itemStack = tempHand ? player.getInventory().getItemInMainHand() : player.getInventory().getItemInOffHand();
|
||||
itemStack.setAmount(Math.max(0, itemStack.getAmount() + amount));
|
||||
};
|
||||
} else {
|
||||
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at item-amount action which is expected to be `Section`");
|
||||
return Action.empty();
|
||||
}
|
||||
}, "item-amount");
|
||||
registerAction((args, chance) -> {
|
||||
int amount;
|
||||
EquipmentSlot slot;
|
||||
if (args instanceof Integer integer) {
|
||||
slot = null;
|
||||
amount = integer;
|
||||
} else if (args instanceof Section section) {
|
||||
slot = Optional.ofNullable(section.getString("slot"))
|
||||
.map(hand -> EquipmentSlot.valueOf(hand.toUpperCase(Locale.ENGLISH)))
|
||||
.orElse(null);
|
||||
amount = section.getInt("amount", 1);
|
||||
} else {
|
||||
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at durability action which is expected to be `Section`");
|
||||
return Action.empty();
|
||||
}
|
||||
return context -> {
|
||||
if (Math.random() > chance) return;
|
||||
Player player = context.holder();
|
||||
if (player == null) return;
|
||||
EquipmentSlot tempSlot = slot;
|
||||
EquipmentSlot equipmentSlot = context.arg(ContextKeys.SLOT);
|
||||
if (equipmentSlot != null) {
|
||||
tempSlot = equipmentSlot;
|
||||
}
|
||||
if (tempSlot == null) {
|
||||
return;
|
||||
}
|
||||
ItemStack itemStack = player.getInventory().getItem(tempSlot);
|
||||
if (itemStack.getType() == Material.AIR || itemStack.getAmount() == 0)
|
||||
return;
|
||||
if (itemStack.getItemMeta() == null)
|
||||
return;
|
||||
if (amount > 0) {
|
||||
plugin.getItemManager().decreaseDamage(context.holder(), itemStack, amount);
|
||||
} else {
|
||||
plugin.getItemManager().increaseDamage(context.holder(), itemStack, -amount);
|
||||
}
|
||||
};
|
||||
}, "durability");
|
||||
registerAction((args, chance) -> {
|
||||
if (args instanceof Section section) {
|
||||
String id = section.getString("item");
|
||||
int amount = section.getInt("amount", 1);
|
||||
boolean toInventory = section.getBoolean("to-inventory", false);
|
||||
return context -> {
|
||||
if (Math.random() > chance) return;
|
||||
Player player = context.holder();
|
||||
if (player == null) return;
|
||||
ItemStack itemStack = plugin.getItemManager().build(context.holder(), id);
|
||||
if (itemStack != null) {
|
||||
int maxStack = itemStack.getMaxStackSize();
|
||||
int amountToGive = amount;
|
||||
while (amountToGive > 0) {
|
||||
int perStackSize = Math.min(maxStack, amountToGive);
|
||||
amountToGive -= perStackSize;
|
||||
ItemStack more = itemStack.clone();
|
||||
more.setAmount(perStackSize);
|
||||
if (toInventory) {
|
||||
PlayerUtils.giveItem(player, more, more.getAmount());
|
||||
} else {
|
||||
PlayerUtils.dropItem(player, more, true, true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at give-item action which is expected to be `Section`");
|
||||
return Action.empty();
|
||||
}
|
||||
}, "give-item");
|
||||
}
|
||||
|
||||
private void registerMoneyAction() {
|
||||
registerAction((args, chance) -> {
|
||||
MathValue<Player> value = MathValue.auto(args);
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
if (!VaultHook.isHooked()) return;
|
||||
VaultHook.deposit(context.holder(), value.evaluate(context));
|
||||
};
|
||||
}, "give-money");
|
||||
registerAction((args, chance) -> {
|
||||
MathValue<Player> value = MathValue.auto(args);
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
if (!VaultHook.isHooked()) return;
|
||||
VaultHook.withdraw(context.holder(), value.evaluate(context));
|
||||
};
|
||||
}, "take-money");
|
||||
}
|
||||
|
||||
private void registerPotionAction() {
|
||||
registerAction((args, chance) -> {
|
||||
if (args instanceof Section section) {
|
||||
PotionEffect potionEffect = new PotionEffect(
|
||||
Objects.requireNonNull(PotionEffectType.getByName(section.getString("type", "BLINDNESS").toUpperCase(Locale.ENGLISH))),
|
||||
section.getInt("duration", 20),
|
||||
section.getInt("amplifier", 0)
|
||||
);
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
context.holder().addPotionEffect(potionEffect);
|
||||
};
|
||||
} else {
|
||||
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at potion-effect action which is expected to be `Section`");
|
||||
return Action.empty();
|
||||
}
|
||||
}, "potion-effect");
|
||||
}
|
||||
|
||||
private void registerSoundAction() {
|
||||
registerAction((args, chance) -> {
|
||||
if (args instanceof Section section) {
|
||||
Sound sound = Sound.sound(
|
||||
Key.key(section.getString("key")),
|
||||
Sound.Source.valueOf(section.getString("source", "PLAYER").toUpperCase(Locale.ENGLISH)),
|
||||
section.getDouble("volume", 1.0).floatValue(),
|
||||
section.getDouble("pitch", 1.0).floatValue()
|
||||
);
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
Audience audience = plugin.getSenderFactory().getAudience(context.holder());
|
||||
AdventureHelper.playSound(audience, sound);
|
||||
};
|
||||
} else {
|
||||
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at sound action which is expected to be `Section`");
|
||||
return Action.empty();
|
||||
}
|
||||
}, "sound");
|
||||
}
|
||||
|
||||
private void registerPluginExpAction() {
|
||||
registerAction((args, chance) -> {
|
||||
if (args instanceof Section section) {
|
||||
String pluginName = section.getString("plugin");
|
||||
MathValue<Player> value = MathValue.auto(section.get("exp"));
|
||||
String target = section.getString("target");
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
Optional.ofNullable(plugin.getIntegrationManager().getLevelerProvider(pluginName)).ifPresentOrElse(it -> {
|
||||
it.addXp(context.holder(), target, value.evaluate(context));
|
||||
}, () -> plugin.getPluginLogger().warn("Plugin (" + pluginName + "'s) level is not compatible. Please double check if it's a problem caused by pronunciation."));
|
||||
};
|
||||
} else {
|
||||
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at plugin-exp action which is expected to be `Section`");
|
||||
return Action.empty();
|
||||
}
|
||||
}, "plugin-exp");
|
||||
}
|
||||
|
||||
private void registerTitleAction() {
|
||||
registerAction((args, chance) -> {
|
||||
if (args instanceof Section section) {
|
||||
TextValue<Player> title = TextValue.auto(section.getString("title", ""));
|
||||
TextValue<Player> subtitle = TextValue.auto(section.getString("subtitle", ""));
|
||||
int fadeIn = section.getInt("fade-in", 20);
|
||||
int stay = section.getInt("stay", 30);
|
||||
int fadeOut = section.getInt("fade-out", 10);
|
||||
return context -> {
|
||||
if (Math.random() > chance) return;
|
||||
final Player player = context.holder();
|
||||
if (player == null) return;
|
||||
Audience audience = plugin.getSenderFactory().getAudience(player);
|
||||
AdventureHelper.sendTitle(audience,
|
||||
AdventureHelper.miniMessage(title.render(context)),
|
||||
AdventureHelper.miniMessage(subtitle.render(context)),
|
||||
fadeIn, stay, fadeOut
|
||||
);
|
||||
};
|
||||
} else {
|
||||
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at title action which is expected to be `Section`");
|
||||
return Action.empty();
|
||||
}
|
||||
}, "title");
|
||||
registerAction((args, chance) -> {
|
||||
if (args instanceof Section section) {
|
||||
List<String> titles = section.getStringList("titles");
|
||||
if (titles.isEmpty()) titles.add("");
|
||||
List<String> subtitles = section.getStringList("subtitles");
|
||||
if (subtitles.isEmpty()) subtitles.add("");
|
||||
int fadeIn = section.getInt("fade-in", 20);
|
||||
int stay = section.getInt("stay", 30);
|
||||
int fadeOut = section.getInt("fade-out", 10);
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
TextValue<Player> title = TextValue.auto(titles.get(RandomUtils.generateRandomInt(0, titles.size() - 1)));
|
||||
TextValue<Player> subtitle = TextValue.auto(subtitles.get(RandomUtils.generateRandomInt(0, subtitles.size() - 1)));
|
||||
final Player player = context.holder();
|
||||
Audience audience = plugin.getSenderFactory().getAudience(player);
|
||||
AdventureHelper.sendTitle(audience,
|
||||
AdventureHelper.miniMessage(title.render(context)),
|
||||
AdventureHelper.miniMessage(subtitle.render(context)),
|
||||
fadeIn, stay, fadeOut
|
||||
);
|
||||
};
|
||||
} else {
|
||||
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at random-title action which is expected to be `Section`");
|
||||
return Action.empty();
|
||||
}
|
||||
}, "random-title");
|
||||
}
|
||||
|
||||
private void registerHologramAction() {
|
||||
registerAction(((args, chance) -> {
|
||||
if (args instanceof Section section) {
|
||||
TextValue<Player> text = TextValue.auto(section.getString("text", ""));
|
||||
MathValue<Player> duration = MathValue.auto(section.get("duration", 20));
|
||||
boolean position = section.getString("position", "other").equals("other");
|
||||
MathValue<Player> x = MathValue.auto(section.get("x", 0));
|
||||
MathValue<Player> y = MathValue.auto(section.get("y", 0));
|
||||
MathValue<Player> z = MathValue.auto(section.get("z", 0));
|
||||
boolean applyCorrection = section.getBoolean("apply-correction", false);
|
||||
boolean onlyShowToOne = !section.getBoolean("visible-to-all", false);
|
||||
int range = section.getInt("range", 32);
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
Player owner = context.holder();
|
||||
Location location = position ? requireNonNull(context.arg(ContextKeys.LOCATION)).clone() : owner.getLocation().clone();
|
||||
location.add(x.evaluate(context), y.evaluate(context), z.evaluate(context));
|
||||
Optional<CustomCropsWorld<?>> optionalWorld = plugin.getWorldManager().getWorld(location.getWorld());
|
||||
if (optionalWorld.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Pos3 pos3 = Pos3.from(location);
|
||||
if (applyCorrection) {
|
||||
Optional<CustomCropsBlockState> optionalState = optionalWorld.get().getBlockState(pos3);
|
||||
if (optionalState.isPresent()) {
|
||||
if (optionalState.get().type() instanceof CropBlock cropBlock) {
|
||||
CropConfig config = cropBlock.config(optionalState.get());
|
||||
int point = cropBlock.point(optionalState.get());
|
||||
if (config != null) {
|
||||
int tempPoints = point;
|
||||
while (tempPoints >= 0) {
|
||||
Map.Entry<Integer, CropStageConfig> entry = config.getFloorStageEntry(tempPoints);
|
||||
CropStageConfig stage = entry.getValue();
|
||||
if (stage.stageID() != null) {
|
||||
location.add(0, stage.displayInfoOffset(), 0);
|
||||
break;
|
||||
}
|
||||
tempPoints = stage.point() - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ArrayList<Player> viewers = new ArrayList<>();
|
||||
if (onlyShowToOne) {
|
||||
if (owner == null) return;
|
||||
viewers.add(owner);
|
||||
} else {
|
||||
for (Player player : owner.getWorld().getPlayers()) {
|
||||
if (LocationUtils.getDistance(player.getLocation(), location) <= range) {
|
||||
viewers.add(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
Component component = AdventureHelper.miniMessage(text.render(context));
|
||||
for (Player viewer : viewers) {
|
||||
HologramManager.getInstance().showHologram(viewer, location, component, (int) (duration.evaluate(context) * 50));
|
||||
}
|
||||
};
|
||||
} else {
|
||||
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at hologram action which is expected to be `Section`");
|
||||
return Action.empty();
|
||||
}
|
||||
}), "hologram");
|
||||
}
|
||||
|
||||
private void registerSwingHandAction() {
|
||||
registerAction((args, chance) -> {
|
||||
boolean arg = (boolean) args;
|
||||
return context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
SparrowHeart.getInstance().swingHand(context.holder(), arg ? HandSlot.MAIN : HandSlot.OFF);
|
||||
};
|
||||
}, "swing-hand");
|
||||
}
|
||||
|
||||
private void registerForceTickAction() {
|
||||
registerAction((args, chance) -> context -> {
|
||||
if (context.holder() == null) return;
|
||||
if (Math.random() > chance) return;
|
||||
Location location = requireNonNull(context.arg(ContextKeys.LOCATION));
|
||||
Pos3 pos3 = Pos3.from(location);
|
||||
Optional<CustomCropsWorld<?>> optionalWorld = plugin.getWorldManager().getWorld(location.getWorld());
|
||||
optionalWorld.ifPresent(world -> world.getChunk(pos3.toChunkPos()).flatMap(chunk -> chunk.getBlockState(pos3)).ifPresent(state -> {
|
||||
state.type().randomTick(state, world, pos3);
|
||||
state.type().scheduledTick(state, world, pos3);
|
||||
}));
|
||||
}, "force-tick");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <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.customcrops.bukkit.command;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.common.command.AbstractCommandFeature;
|
||||
import net.momirealms.customcrops.common.command.CustomCropsCommandManager;
|
||||
import net.momirealms.customcrops.common.sender.SenderFactory;
|
||||
import net.momirealms.customcrops.common.util.Pair;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.incendo.cloud.bukkit.data.Selector;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public abstract class BukkitCommandFeature<C extends CommandSender> extends AbstractCommandFeature<C> {
|
||||
|
||||
public BukkitCommandFeature(CustomCropsCommandManager<C> commandManager) {
|
||||
super(commandManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected SenderFactory<?, C> getSenderFactory() {
|
||||
return (SenderFactory<?, C>) BukkitCustomCropsPlugin.getInstance().getSenderFactory();
|
||||
}
|
||||
|
||||
public Pair<TranslatableComponent.Builder, Component> resolveSelector(Selector<? extends Entity> selector, TranslatableComponent.Builder single, TranslatableComponent.Builder multiple) {
|
||||
Collection<? extends Entity> entities = selector.values();
|
||||
if (entities.size() == 1) {
|
||||
return Pair.of(single, Component.text(entities.iterator().next().getName()));
|
||||
} else {
|
||||
return Pair.of(multiple, Component.text(entities.size()));
|
||||
}
|
||||
}
|
||||
|
||||
public Pair<TranslatableComponent.Builder, Component> resolveSelector(Collection<? extends Entity> selector, TranslatableComponent.Builder single, TranslatableComponent.Builder multiple) {
|
||||
if (selector.size() == 1) {
|
||||
return Pair.of(single, Component.text(selector.iterator().next().getName()));
|
||||
} else {
|
||||
return Pair.of(multiple, Component.text(selector.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <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.customcrops.bukkit.command;
|
||||
|
||||
import net.kyori.adventure.util.Index;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.bukkit.command.feature.DebugDataCommand;
|
||||
import net.momirealms.customcrops.bukkit.command.feature.ReloadCommand;
|
||||
import net.momirealms.customcrops.common.command.AbstractCommandManager;
|
||||
import net.momirealms.customcrops.common.command.CommandFeature;
|
||||
import net.momirealms.customcrops.common.sender.Sender;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.incendo.cloud.SenderMapper;
|
||||
import org.incendo.cloud.bukkit.CloudBukkitCapabilities;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
import org.incendo.cloud.paper.LegacyPaperCommandManager;
|
||||
import org.incendo.cloud.setting.ManagerSetting;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BukkitCommandManager extends AbstractCommandManager<CommandSender> {
|
||||
|
||||
private final List<CommandFeature<CommandSender>> FEATURES = List.of(
|
||||
new ReloadCommand(this),
|
||||
new DebugDataCommand(this)
|
||||
);
|
||||
|
||||
private final Index<String, CommandFeature<CommandSender>> INDEX = Index.create(CommandFeature::getFeatureID, FEATURES);
|
||||
|
||||
public BukkitCommandManager(BukkitCustomCropsPlugin plugin) {
|
||||
super(plugin, new LegacyPaperCommandManager<>(
|
||||
plugin.getBoostrap(),
|
||||
ExecutionCoordinator.simpleCoordinator(),
|
||||
SenderMapper.identity()
|
||||
));
|
||||
final LegacyPaperCommandManager<CommandSender> manager = (LegacyPaperCommandManager<CommandSender>) getCommandManager();
|
||||
manager.settings().set(ManagerSetting.ALLOW_UNSAFE_REGISTRATION, true);
|
||||
if (manager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) {
|
||||
manager.registerBrigadier();
|
||||
manager.brigadierManager().setNativeNumberSuggestions(true);
|
||||
} else if (manager.hasCapability(CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)) {
|
||||
manager.registerAsynchronousCompletions();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sender wrapSender(CommandSender sender) {
|
||||
return ((BukkitCustomCropsPlugin) plugin).getSenderFactory().wrap(sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Index<String, CommandFeature<CommandSender>> getFeatures() {
|
||||
return INDEX;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <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.customcrops.bukkit.command.feature;
|
||||
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
|
||||
import net.momirealms.customcrops.api.core.world.Pos3;
|
||||
import net.momirealms.customcrops.bukkit.command.BukkitCommandFeature;
|
||||
import net.momirealms.customcrops.common.command.CustomCropsCommandManager;
|
||||
import net.momirealms.customcrops.common.helper.AdventureHelper;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class DebugDataCommand extends BukkitCommandFeature<CommandSender> {
|
||||
|
||||
public DebugDataCommand(CustomCropsCommandManager<CommandSender> commandManager) {
|
||||
super(commandManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
|
||||
return builder
|
||||
.senderType(Player.class)
|
||||
.flag(manager.flagBuilder("this").build())
|
||||
.handler(context -> {
|
||||
Player player = context.sender();
|
||||
Location location;
|
||||
if (context.flags().hasFlag("this")) {
|
||||
location = player.getLocation();
|
||||
} else {
|
||||
Block block = player.getTargetBlockExact(10);
|
||||
if (block == null) return;
|
||||
location = block.getLocation();
|
||||
}
|
||||
BukkitCustomCropsPlugin.getInstance().getWorldManager().getWorld(location.getWorld()).ifPresent(world -> {
|
||||
Optional<CustomCropsBlockState> state = world.getBlockState(Pos3.from(location));
|
||||
if (state.isPresent()) {
|
||||
BukkitCustomCropsPlugin.getInstance().getSenderFactory().wrap(player)
|
||||
.sendMessage(AdventureHelper.miniMessage(state.get().toString()));
|
||||
} else {
|
||||
BukkitCustomCropsPlugin.getInstance().getSenderFactory().wrap(player)
|
||||
.sendMessage(AdventureHelper.miniMessage("Data not found"));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFeatureID() {
|
||||
return "debug_data";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <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.customcrops.bukkit.command.feature;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.bukkit.command.BukkitCommandFeature;
|
||||
import net.momirealms.customcrops.common.command.CustomCropsCommandManager;
|
||||
import net.momirealms.customcrops.common.locale.MessageConstants;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.incendo.cloud.Command;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
|
||||
public class ReloadCommand extends BukkitCommandFeature<CommandSender> {
|
||||
|
||||
public ReloadCommand(CustomCropsCommandManager<CommandSender> commandManager) {
|
||||
super(commandManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command.Builder<? extends CommandSender> assembleCommand(CommandManager<CommandSender> manager, Command.Builder<CommandSender> builder) {
|
||||
return builder
|
||||
.flag(manager.flagBuilder("silent").withAliases("s"))
|
||||
.handler(context -> {
|
||||
long time1 = System.currentTimeMillis();
|
||||
BukkitCustomCropsPlugin.getInstance().reload();
|
||||
handleFeedback(context, MessageConstants.COMMAND_RELOAD_SUCCESS, Component.text(System.currentTimeMillis() - time1));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFeatureID() {
|
||||
return "reload";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,249 @@
|
||||
package net.momirealms.customcrops.bukkit.config;
|
||||
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
import dev.dejvokep.boostedyaml.dvs.versioning.BasicVersioning;
|
||||
import dev.dejvokep.boostedyaml.libs.org.snakeyaml.engine.v2.common.ScalarStyle;
|
||||
import dev.dejvokep.boostedyaml.libs.org.snakeyaml.engine.v2.exceptions.ConstructorException;
|
||||
import dev.dejvokep.boostedyaml.libs.org.snakeyaml.engine.v2.nodes.Tag;
|
||||
import dev.dejvokep.boostedyaml.settings.dumper.DumperSettings;
|
||||
import dev.dejvokep.boostedyaml.settings.general.GeneralSettings;
|
||||
import dev.dejvokep.boostedyaml.settings.loader.LoaderSettings;
|
||||
import dev.dejvokep.boostedyaml.settings.updater.UpdaterSettings;
|
||||
import dev.dejvokep.boostedyaml.utils.format.NodeRole;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.core.*;
|
||||
import net.momirealms.customcrops.api.core.block.CropConfig;
|
||||
import net.momirealms.customcrops.api.core.block.CropStageConfig;
|
||||
import net.momirealms.customcrops.api.core.block.PotConfig;
|
||||
import net.momirealms.customcrops.api.core.block.SprinklerConfig;
|
||||
import net.momirealms.customcrops.api.core.item.FertilizerConfig;
|
||||
import net.momirealms.customcrops.api.core.item.WateringCanConfig;
|
||||
import net.momirealms.customcrops.api.util.PluginUtils;
|
||||
import net.momirealms.customcrops.common.helper.AdventureHelper;
|
||||
import net.momirealms.customcrops.common.helper.VersionHelper;
|
||||
import net.momirealms.customcrops.common.locale.TranslationManager;
|
||||
import net.momirealms.customcrops.common.plugin.CustomCropsProperties;
|
||||
import net.momirealms.customcrops.common.util.ListUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Particle;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
public class BukkitConfigManager extends ConfigManager {
|
||||
|
||||
private static YamlDocument MAIN_CONFIG;
|
||||
|
||||
public static YamlDocument getMainConfig() {
|
||||
return MAIN_CONFIG;
|
||||
}
|
||||
|
||||
public BukkitConfigManager(BukkitCustomCropsPlugin plugin) {
|
||||
super(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
String configVersion = CustomCropsProperties.getValue("config");
|
||||
try (InputStream inputStream = new FileInputStream(resolveConfig("config.yml").toFile())) {
|
||||
MAIN_CONFIG = YamlDocument.create(
|
||||
inputStream,
|
||||
plugin.getResourceStream("config.yml"),
|
||||
GeneralSettings.builder()
|
||||
.setRouteSeparator('.')
|
||||
.setUseDefaults(false)
|
||||
.build(),
|
||||
LoaderSettings
|
||||
.builder()
|
||||
.setAutoUpdate(true)
|
||||
.build(),
|
||||
DumperSettings.builder()
|
||||
.setScalarFormatter((tag, value, role, def) -> {
|
||||
if (role == NodeRole.KEY) {
|
||||
return ScalarStyle.PLAIN;
|
||||
} else {
|
||||
return tag == Tag.STR ? ScalarStyle.DOUBLE_QUOTED : ScalarStyle.PLAIN;
|
||||
}
|
||||
})
|
||||
.build(),
|
||||
UpdaterSettings
|
||||
.builder()
|
||||
.setVersioning(new BasicVersioning("config-version"))
|
||||
.addIgnoredRoute(configVersion, "other-settings.placeholder-register", '.')
|
||||
.build()
|
||||
);
|
||||
MAIN_CONFIG.save(resolveConfig("config.yml").toFile());
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
this.loadSettings();
|
||||
this.loadConfigs();
|
||||
}
|
||||
|
||||
private void loadSettings() {
|
||||
YamlDocument config = getMainConfig();
|
||||
|
||||
TranslationManager.forceLocale(TranslationManager.parseLocale(config.getString("force-locale", "")));
|
||||
AdventureHelper.legacySupport = config.getBoolean("other-settings.legacy-color-code-support", true);
|
||||
|
||||
metrics = config.getBoolean("metrics", true);
|
||||
checkUpdate = config.getBoolean("update-checker", true);
|
||||
debug = config.getBoolean("debug", false);
|
||||
|
||||
protectOriginalLore = config.getBoolean("other-settings.protect-original-lore", false);
|
||||
doubleCheck = config.getBoolean("other-settings.double-check", false);
|
||||
|
||||
enableScarecrow = config.getBoolean("mechanics.scarecrow.enable", true);
|
||||
scarecrow = new HashSet<>(ListUtils.toList(config.get("mechanics.scarecrow.id")));
|
||||
scarecrowExistenceForm = CustomForm.valueOf(config.getString("mechanics.scarecrow.type", "ITEM_FRAME")).existenceForm();
|
||||
scarecrowRange = config.getInt("mechanics.scarecrow.range", 7);
|
||||
scarecrowProtectChunk = config.getBoolean("mechanics.scarecrow.protect-chunk", false);
|
||||
|
||||
enableGreenhouse = config.getBoolean("mechanics.greenhouse.enable", true);
|
||||
greenhouse = new HashSet<>(ListUtils.toList(config.get("mechanics.greenhouse.id")));
|
||||
greenhouseExistenceForm = CustomForm.valueOf(config.getString("mechanics.greenhouse.type", "CHORUS")).existenceForm();
|
||||
greenhouseRange = config.getInt("mechanics.greenhouse.range", 5);
|
||||
|
||||
syncSeasons = config.getBoolean("mechanics.sync-season.enable", false);
|
||||
referenceWorld = config.getString("mechanics.sync-season.reference", "world");
|
||||
|
||||
itemDetectOrder = config.getStringList("other-settings.item-detection-order").toArray(new String[0]);
|
||||
|
||||
absoluteWorldPath = config.getString("worlds.absolute-world-folder-path");
|
||||
|
||||
defaultQualityRatio = getQualityRatio(config.getString("mechanics.default-quality-ratio", "17/2/1"));
|
||||
|
||||
hasNamespace = PluginUtils.isEnabled("ItemsAdder");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveResource(String filePath) {
|
||||
File file = new File(plugin.getDataFolder(), filePath);
|
||||
if (!file.exists()) {
|
||||
plugin.getBoostrap().saveResource(filePath, false);
|
||||
addDefaultNamespace(file);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
this.clearConfigs();
|
||||
}
|
||||
|
||||
private void loadConfigs() {
|
||||
Deque<File> fileDeque = new ArrayDeque<>();
|
||||
for (ConfigType type : ConfigType.values()) {
|
||||
File typeFolder = new File(plugin.getDataFolder(), "contents" + File.separator + type.path());
|
||||
if (!typeFolder.exists()) {
|
||||
if (!typeFolder.mkdirs()) return;
|
||||
saveResource("contents" + File.separator + type.path() + File.separator + "default.yml");
|
||||
}
|
||||
fileDeque.push(typeFolder);
|
||||
while (!fileDeque.isEmpty()) {
|
||||
File file = fileDeque.pop();
|
||||
File[] files = file.listFiles();
|
||||
if (files == null) continue;
|
||||
for (File subFile : files) {
|
||||
if (subFile.isDirectory()) {
|
||||
fileDeque.push(subFile);
|
||||
} else if (subFile.isFile() && subFile.getName().endsWith(".yml")) {
|
||||
try {
|
||||
YamlDocument document = plugin.getConfigManager().loadData(subFile);
|
||||
boolean save = false;
|
||||
for (Map.Entry<String, Object> entry : document.getStringRouteMappedValues(false).entrySet()) {
|
||||
if (entry.getValue() instanceof Section section) {
|
||||
if (type.parse(this, entry.getKey(), section)) {
|
||||
save = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (save) {
|
||||
document.save(subFile);
|
||||
}
|
||||
} catch (ConstructorException e) {
|
||||
plugin.getPluginLogger().warn("Could not load config file: " + subFile.getAbsolutePath() + ". Is it a corrupted file?");
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void clearConfigs() {
|
||||
Registries.CROP.clear();
|
||||
Registries.SEED_TO_CROP.clear();
|
||||
Registries.STAGE_TO_CROP_UNSAFE.clear();
|
||||
|
||||
Registries.SPRINKLER.clear();
|
||||
Registries.ITEM_TO_SPRINKLER.clear();
|
||||
|
||||
Registries.POT.clear();
|
||||
Registries.ITEM_TO_POT.clear();
|
||||
|
||||
Registries.FERTILIZER.clear();
|
||||
Registries.ITEM_TO_SPRINKLER.clear();
|
||||
|
||||
Registries.WATERING_CAN.clear();
|
||||
|
||||
Registries.ITEMS.clear();
|
||||
Registries.BLOCKS.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerWateringCanConfig(WateringCanConfig config) {
|
||||
Registries.WATERING_CAN.register(config.id(), config);
|
||||
Registries.ITEMS.register(config.itemID(), BuiltInItemMechanics.WATERING_CAN.mechanic());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerFertilizerConfig(FertilizerConfig config) {
|
||||
Registries.FERTILIZER.register(config.id(), config);
|
||||
Registries.ITEM_TO_FERTILIZER.register(config.itemID(), config);
|
||||
Registries.ITEMS.register(config.itemID(), BuiltInItemMechanics.FERTILIZER.mechanic());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCropConfig(CropConfig config) {
|
||||
Registries.CROP.register(config.id(), config);
|
||||
Registries.SEED_TO_CROP.register(config.seed(), config);
|
||||
Registries.ITEMS.register(config.seed(), BuiltInItemMechanics.SEED.mechanic());
|
||||
for (CropStageConfig stageConfig : config.stages()) {
|
||||
String stageID = stageConfig.stageID();
|
||||
if (stageID != null) {
|
||||
List<CropConfig> list = Registries.STAGE_TO_CROP_UNSAFE.get(stageID);
|
||||
if (list != null) {
|
||||
list.add(config);
|
||||
} else {
|
||||
Registries.STAGE_TO_CROP_UNSAFE.register(stageID, new ArrayList<>(List.of(config)));
|
||||
Registries.BLOCKS.register(stageID, BuiltInBlockMechanics.CROP.mechanic());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerPotConfig(PotConfig config) {
|
||||
Registries.POT.register(config.id(), config);
|
||||
for (String pot : config.blocks()) {
|
||||
Registries.ITEM_TO_POT.register(pot, config);
|
||||
Registries.BLOCKS.register(pot, BuiltInBlockMechanics.POT.mechanic());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSprinklerConfig(SprinklerConfig config) {
|
||||
Registries.SPRINKLER.register(config.id(), config);
|
||||
for (String id : new HashSet<>(List.of(config.threeDItem(), config.threeDItemWithWater()))) {
|
||||
Registries.ITEM_TO_SPRINKLER.register(id, config);
|
||||
Registries.BLOCKS.register(id, BuiltInBlockMechanics.SPRINKLER.mechanic());
|
||||
}
|
||||
if (config.twoDItem() != null) {
|
||||
Registries.ITEM_TO_SPRINKLER.register(config.twoDItem(), config);
|
||||
Registries.ITEMS.register(config.twoDItem(), BuiltInItemMechanics.SPRINKLER_ITEM.mechanic());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <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.customcrops.bukkit.config;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.action.ActionManager;
|
||||
import net.momirealms.customcrops.api.core.ConfigManager;
|
||||
import net.momirealms.customcrops.api.core.CustomForm;
|
||||
import net.momirealms.customcrops.api.core.ExistenceForm;
|
||||
import net.momirealms.customcrops.api.core.Registries;
|
||||
import net.momirealms.customcrops.api.core.block.CropConfig;
|
||||
import net.momirealms.customcrops.api.core.block.CropStageConfig;
|
||||
import net.momirealms.customcrops.api.core.block.PotConfig;
|
||||
import net.momirealms.customcrops.api.core.block.SprinklerConfig;
|
||||
import net.momirealms.customcrops.api.core.item.FertilizerConfig;
|
||||
import net.momirealms.customcrops.api.core.item.FertilizerType;
|
||||
import net.momirealms.customcrops.api.core.item.WateringCanConfig;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
|
||||
import net.momirealms.customcrops.api.misc.WaterBar;
|
||||
import net.momirealms.customcrops.api.misc.value.TextValue;
|
||||
import net.momirealms.customcrops.api.requirement.RequirementManager;
|
||||
import net.momirealms.customcrops.common.util.Pair;
|
||||
import net.momirealms.customcrops.common.util.TriFunction;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Configuration types for various mechanics.
|
||||
*/
|
||||
public class ConfigType {
|
||||
|
||||
public static final ConfigType WATERING_CAN = of(
|
||||
"watering-cans",
|
||||
(manager, id, section) -> {
|
||||
|
||||
ActionManager<Player> pam = BukkitCustomCropsPlugin.getInstance().getActionManager(Player.class);
|
||||
|
||||
WateringCanConfig config = WateringCanConfig.builder()
|
||||
.id(id)
|
||||
.itemID(section.getString("item"))
|
||||
.storage(section.getInt("capacity", 3))
|
||||
.wateringAmount(section.getInt("water", 1))
|
||||
.infinite(section.getBoolean("infinite", false))
|
||||
.width(section.getInt("effective-range.width", 1))
|
||||
.length(section.getInt("effective-range.length", 1))
|
||||
.potWhitelist(new HashSet<>(section.getStringList("pot-whitelist")))
|
||||
.sprinklerWhitelist(new HashSet<>(section.getStringList("sprinkler-whitelist")))
|
||||
.dynamicLore(section.getBoolean("dynamic-lore"))
|
||||
.lore(section.getStringList("dynamic-lore.lore").stream().map(TextValue::<Player>auto).toList())
|
||||
.fillMethods(manager.getFillMethods(section.getSection("fill-method")))
|
||||
.requirements(BukkitCustomCropsPlugin.getInstance().getRequirementManager(Player.class).parseRequirements(section.getSection("requirements"), true))
|
||||
.fullActions(pam.parseActions(section.getSection("events.full")))
|
||||
.addWaterActions(pam.parseActions(section.getSection("events.add_water")))
|
||||
.consumeWaterActions(pam.parseActions(section.getSection("events.consume_water")))
|
||||
.runOutOfWaterActions(pam.parseActions(section.getSection("events.no_water")))
|
||||
.wrongPotActions(pam.parseActions(section.getSection("events.wrong_pot")))
|
||||
.wrongSprinklerActions(pam.parseActions(section.getSection("events.wrong_sprinkler")))
|
||||
.appearances(manager.getInt2IntMap(section.getSection("appearance")))
|
||||
.waterBar(section.contains("water-bar") ? WaterBar.of(
|
||||
section.getString("water-bar.left", ""),
|
||||
section.getString("water-bar.empty", ""),
|
||||
section.getString("water-bar.full", ""),
|
||||
section.getString("water-bar.right", "")
|
||||
) : null)
|
||||
.build();
|
||||
|
||||
manager.registerWateringCanConfig(config);
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
public static final ConfigType FERTILIZER = of(
|
||||
"fertilizers",
|
||||
(manager, id, section) -> {
|
||||
String typeName = Preconditions.checkNotNull(section.getString("type"), "Fertilizer type can't be null").toLowerCase(Locale.ENGLISH);
|
||||
FertilizerType type = Registries.FERTILIZER_TYPE.get(typeName);
|
||||
if (type == null) {
|
||||
BukkitCustomCropsPlugin.getInstance().getPluginLogger().warn("Fertilizer type " + typeName + " not found");
|
||||
return false;
|
||||
}
|
||||
FertilizerConfig config = type.parse(manager, id, section);
|
||||
manager.registerFertilizerConfig(config);
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
public static final ConfigType POT = of(
|
||||
"pots",
|
||||
(manager, id, section) -> {
|
||||
|
||||
ActionManager<Player> pam = BukkitCustomCropsPlugin.getInstance().getActionManager(Player.class);
|
||||
ActionManager<CustomCropsBlockState> bam = BukkitCustomCropsPlugin.getInstance().getActionManager(CustomCropsBlockState.class);
|
||||
RequirementManager<Player> prm = BukkitCustomCropsPlugin.getInstance().getRequirementManager(Player.class);
|
||||
|
||||
PotConfig config = PotConfig.builder()
|
||||
.id(id)
|
||||
.isRainDropAccepted(section.getBoolean("absorb-rainwater", false))
|
||||
.isNearbyWaterAccepted(section.getBoolean("absorb-nearby-water", false))
|
||||
.maxFertilizers(section.getInt("max-fertilizers", 1))
|
||||
.basicAppearance(Pair.of(section.getString("base.dry"), section.getString("base.wet")))
|
||||
.potAppearanceMap(manager.getFertilizedPotMap(section.getSection("fertilized-pots")))
|
||||
.wateringMethods(manager.getWateringMethods(section.getSection("fill-method")))
|
||||
.addWaterActions(pam.parseActions(section.getSection("events.add_water")))
|
||||
.placeActions(pam.parseActions(section.getSection("events.place")))
|
||||
.breakActions(pam.parseActions(section.getSection("events.break")))
|
||||
.interactActions(pam.parseActions(section.getSection("events.interact")))
|
||||
.reachLimitActions(pam.parseActions(section.getSection("events.reach_limit")))
|
||||
.fullWaterActions(pam.parseActions(section.getSection("events.full")))
|
||||
.tickActions(bam.parseActions(section.getSection("events.tick")))
|
||||
.useRequirements(prm.parseRequirements(section.getSection("requirements.use"), true))
|
||||
.placeRequirements(prm.parseRequirements(section.getSection("requirements.place"), true))
|
||||
.breakRequirements(prm.parseRequirements(section.getSection("requirements.break"), true))
|
||||
.waterBar(section.contains("water-bar") ? WaterBar.of(
|
||||
section.getString("water-bar.left", ""),
|
||||
section.getString("water-bar.empty", ""),
|
||||
section.getString("water-bar.full", ""),
|
||||
section.getString("water-bar.right", "")
|
||||
) : null)
|
||||
.build();
|
||||
|
||||
manager.registerPotConfig(config);
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
public static final ConfigType CROP = of(
|
||||
"crops",
|
||||
(manager, id, section) -> {
|
||||
|
||||
ActionManager<Player> pam = BukkitCustomCropsPlugin.getInstance().getActionManager(Player.class);
|
||||
ActionManager<CustomCropsBlockState> bam = BukkitCustomCropsPlugin.getInstance().getActionManager(CustomCropsBlockState.class);
|
||||
RequirementManager<Player> prm = BukkitCustomCropsPlugin.getInstance().getRequirementManager(Player.class);
|
||||
|
||||
boolean needUpdate = false;
|
||||
|
||||
ExistenceForm form = CustomForm.valueOf(section.getString("type").toUpperCase(Locale.ENGLISH)).existenceForm();
|
||||
|
||||
Section growConditionSection = section.getSection("grow-conditions");
|
||||
if (growConditionSection != null) {
|
||||
for (Map.Entry<String, Object> entry : growConditionSection.getStringRouteMappedValues(false).entrySet()) {
|
||||
if (entry.getValue() instanceof Section inner) {
|
||||
if (inner.contains("type")) {
|
||||
needUpdate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needUpdate) {
|
||||
section.remove("grow-conditions");
|
||||
section.set("grow-conditions.default.point", 1);
|
||||
Section newSection = section.createSection("grow-conditions.default.conditions");
|
||||
newSection.setValue(growConditionSection.getStoredValue());
|
||||
}
|
||||
|
||||
Section pointSection = section.getSection("points");
|
||||
if (pointSection == null) {
|
||||
BukkitCustomCropsPlugin.getInstance().getPluginLogger().warn("points section not found in crop[" + id + "]");
|
||||
return false;
|
||||
}
|
||||
|
||||
ArrayList<CropStageConfig.Builder> builders = new ArrayList<>();
|
||||
for (Map.Entry<String, Object> entry : pointSection.getStringRouteMappedValues(false).entrySet()) {
|
||||
if (entry.getValue() instanceof Section inner) {
|
||||
int point = Integer.parseInt(entry.getKey());
|
||||
CropStageConfig.Builder builder = CropStageConfig.builder()
|
||||
.point(point)
|
||||
.displayInfoOffset(inner.getDouble("hologram-offset-correction"))
|
||||
.stageID(inner.getString("model"))
|
||||
.breakRequirements(prm.parseRequirements(inner.getSection("requirements.break"), true))
|
||||
.interactRequirements(prm.parseRequirements(inner.getSection("requirements.interact"), true))
|
||||
.breakActions(pam.parseActions(inner.getSection("events.break")))
|
||||
.interactActions(pam.parseActions(inner.getSection("events.interact")))
|
||||
.growActions(bam.parseActions(inner.getSection("events.grow")));
|
||||
builders.add(builder);
|
||||
}
|
||||
}
|
||||
|
||||
CropConfig config = CropConfig.builder()
|
||||
.id(id)
|
||||
.seed(section.getString("seed"))
|
||||
.rotation(section.getBoolean("random-rotation", false))
|
||||
.maxPoints(section.getInt("max-points", 1))
|
||||
.potWhitelist(new HashSet<>(section.getStringList("pot-whitelist")))
|
||||
.wrongPotActions(pam.parseActions(section.getSection("events.wrong_pot")))
|
||||
.plantActions(pam.parseActions(section.getSection("events.plant")))
|
||||
.breakActions(pam.parseActions(section.getSection("events.break")))
|
||||
.interactActions(pam.parseActions(section.getSection("events.interact")))
|
||||
.reachLimitActions(pam.parseActions(section.getSection("events.reach_limit")))
|
||||
.interactRequirements(prm.parseRequirements(section.getSection("requirements.interact"), true))
|
||||
.plantRequirements(prm.parseRequirements(section.getSection("requirements.plant"), true))
|
||||
.breakRequirements(prm.parseRequirements(section.getSection("requirements.break"), true))
|
||||
.boneMeals(manager.getBoneMeals(section.getSection("custom-bone-meal")))
|
||||
.deathConditions(manager.getDeathConditions(section.getSection("death-conditions"), form))
|
||||
.growConditions(manager.getGrowConditions(section.getSection("grow-conditions")))
|
||||
.stages(builders)
|
||||
.build();
|
||||
|
||||
manager.registerCropConfig(config);
|
||||
return needUpdate;
|
||||
}
|
||||
);
|
||||
|
||||
public static final ConfigType SPRINKLER = of(
|
||||
"sprinklers",
|
||||
(manager, id, section) -> {
|
||||
int rangeValue = section.getInt("range",1);
|
||||
int workingMode = section.getInt("working-mode", 1);
|
||||
int[][] range;
|
||||
if (workingMode == 1) {
|
||||
int blocks = 4 * rangeValue * rangeValue + 4 * rangeValue + 1;
|
||||
range = new int[blocks][2];
|
||||
int index = 0;
|
||||
for (int i = -rangeValue; i <= rangeValue; i++) {
|
||||
for (int j = -rangeValue; j <= rangeValue; j++) {
|
||||
range[index++] = new int[]{i, j};
|
||||
}
|
||||
}
|
||||
} else if (workingMode == 2) {
|
||||
int blocks = (2 * rangeValue * rangeValue) + 2 * rangeValue + 1;
|
||||
range = new int[blocks][2];
|
||||
int index = 0;
|
||||
for (int i = -rangeValue; i <= rangeValue; i++) {
|
||||
for (int j = -rangeValue; j <= rangeValue; j++) {
|
||||
if (Math.abs(i) + Math.abs(j) <= rangeValue) {
|
||||
range[index++] = new int[]{i, j};
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unrecognized working mode: " + workingMode);
|
||||
}
|
||||
|
||||
ActionManager<Player> pam = BukkitCustomCropsPlugin.getInstance().getActionManager(Player.class);
|
||||
ActionManager<CustomCropsBlockState> bam = BukkitCustomCropsPlugin.getInstance().getActionManager(CustomCropsBlockState.class);
|
||||
RequirementManager<Player> prm = BukkitCustomCropsPlugin.getInstance().getRequirementManager(Player.class);
|
||||
|
||||
SprinklerConfig config = SprinklerConfig.builder()
|
||||
.id(id)
|
||||
.range(range)
|
||||
.storage(section.getInt("storage", 4))
|
||||
.infinite(section.getBoolean("infinite", false))
|
||||
.twoDItem(section.getString("2D-item"))
|
||||
.sprinklingAmount(section.getInt("water", 1))
|
||||
.threeDItem(section.getString("3D-item"))
|
||||
.threeDItemWithWater(section.getString("3D-item-with-water"))
|
||||
.wateringMethods(manager.getWateringMethods(section.getSection("fill-method")))
|
||||
.potWhitelist(new HashSet<>(section.getStringList("pot-whitelist")))
|
||||
.existenceForm(CustomForm.valueOf(section.getString("type", "ITEM_FRAME").toUpperCase(Locale.ENGLISH)).existenceForm())
|
||||
.addWaterActions(pam.parseActions(section.getSection("events.add_water")))
|
||||
.breakActions(pam.parseActions(section.getSection("events.break")))
|
||||
.placeActions(pam.parseActions(section.getSection("events.place")))
|
||||
.fullWaterActions(pam.parseActions(section.getSection("events.full")))
|
||||
.reachLimitActions(pam.parseActions(section.getSection("events.reach_limit")))
|
||||
.interactActions(pam.parseActions(section.getSection("events.interact")))
|
||||
.workActions(bam.parseActions(section.getSection("events.work")))
|
||||
.useRequirements(prm.parseRequirements(section.getSection("requirements.use"), true))
|
||||
.placeRequirements(prm.parseRequirements(section.getSection("requirements.place"), true))
|
||||
.breakRequirements(prm.parseRequirements(section.getSection("requirements.break"), true))
|
||||
.waterBar(section.contains("water-bar") ? WaterBar.of(
|
||||
section.getString("water-bar.left", ""),
|
||||
section.getString("water-bar.empty", ""),
|
||||
section.getString("water-bar.full", ""),
|
||||
section.getString("water-bar.right", "")
|
||||
) : null)
|
||||
.build();
|
||||
|
||||
manager.registerSprinklerConfig(config);
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
private static final ConfigType[] values = new ConfigType[] {CROP, SPRINKLER, WATERING_CAN, POT, FERTILIZER};
|
||||
|
||||
public static ConfigType[] values() {
|
||||
return values;
|
||||
}
|
||||
|
||||
private final String path;
|
||||
private final TriFunction<ConfigManager, String, Section, Boolean> argumentConsumer;
|
||||
|
||||
public ConfigType(String path, TriFunction<ConfigManager, String, Section, Boolean> argumentConsumer) {
|
||||
this.path = path;
|
||||
this.argumentConsumer = argumentConsumer;
|
||||
}
|
||||
|
||||
public static ConfigType of(String path, TriFunction<ConfigManager, String, Section, Boolean> argumentConsumer) {
|
||||
return new ConfigType(path, argumentConsumer);
|
||||
}
|
||||
|
||||
public String path() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public boolean parse(ConfigManager manager, String id, Section section) {
|
||||
return argumentConsumer.apply(manager, id, section);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) <2024> <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.customcrops.bukkit.integration;
|
||||
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.integration.IntegrationManager;
|
||||
import net.momirealms.customcrops.api.integration.ItemProvider;
|
||||
import net.momirealms.customcrops.api.integration.LevelerProvider;
|
||||
import net.momirealms.customcrops.api.integration.SeasonProvider;
|
||||
import net.momirealms.customcrops.bukkit.integration.item.*;
|
||||
import net.momirealms.customcrops.bukkit.integration.level.*;
|
||||
import net.momirealms.customcrops.bukkit.integration.papi.CustomCropsPapi;
|
||||
import net.momirealms.customcrops.bukkit.integration.season.AdvancedSeasonsProvider;
|
||||
import net.momirealms.customcrops.bukkit.integration.season.RealisticSeasonsProvider;
|
||||
import net.momirealms.customcrops.bukkit.item.BukkitItemManager;
|
||||
import net.momirealms.customcrops.bukkit.world.BukkitWorldManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class BukkitIntegrationManager implements IntegrationManager {
|
||||
|
||||
private final BukkitCustomCropsPlugin plugin;
|
||||
private final HashMap<String, LevelerProvider> levelerProviders = new HashMap<>();
|
||||
|
||||
public BukkitIntegrationManager(BukkitCustomCropsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
try {
|
||||
this.load();
|
||||
} catch (Exception e) {
|
||||
plugin.getPluginLogger().warn("Failed to load integrations", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
this.levelerProviders.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
if (isHooked("MMOItems")) {
|
||||
registerItemProvider(new MMOItemsItemProvider());
|
||||
}
|
||||
if (isHooked("Zaphkiel")) {
|
||||
registerItemProvider(new ZaphkielItemProvider());
|
||||
}
|
||||
if (isHooked("NeigeItems")) {
|
||||
registerItemProvider(new NeigeItemsItemProvider());
|
||||
}
|
||||
if (isHooked("CustomFishing", "2.2", "2.3", "2.4")) {
|
||||
registerItemProvider(new CustomFishingItemProvider());
|
||||
}
|
||||
if (isHooked("MythicMobs", "5")) {
|
||||
registerItemProvider(new MythicMobsItemProvider());
|
||||
}
|
||||
if (isHooked("EcoJobs")) {
|
||||
registerLevelerProvider(new EcoJobsLevelerProvider());
|
||||
}
|
||||
if (isHooked("EcoSkills")) {
|
||||
registerLevelerProvider(new EcoSkillsLevelerProvider());
|
||||
}
|
||||
if (isHooked("Jobs")) {
|
||||
registerLevelerProvider(new JobsRebornLevelerProvider());
|
||||
}
|
||||
if (isHooked("MMOCore")) {
|
||||
registerLevelerProvider(new MMOCoreLevelerProvider());
|
||||
}
|
||||
if (isHooked("mcMMO")) {
|
||||
registerLevelerProvider(new McMMOLevelerProvider());
|
||||
}
|
||||
if (isHooked("AureliumSkills")) {
|
||||
registerLevelerProvider(new AureliumSkillsProvider());
|
||||
}
|
||||
if (isHooked("AuraSkills")) {
|
||||
registerLevelerProvider(new AuraSkillsLevelerProvider());
|
||||
}
|
||||
if (isHooked("RealisticSeasons")) {
|
||||
registerSeasonProvider(new RealisticSeasonsProvider());
|
||||
} else if (isHooked("AdvancedSeasons", "1.4", "1.5", "1.6")) {
|
||||
registerSeasonProvider(new AdvancedSeasonsProvider());
|
||||
}
|
||||
if (isHooked("Vault")) {
|
||||
VaultHook.init();
|
||||
}
|
||||
if (isHooked("PlaceholderAPI")) {
|
||||
new CustomCropsPapi(plugin).load();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isHooked(String hooked) {
|
||||
if (Bukkit.getPluginManager().getPlugin(hooked) != null) {
|
||||
plugin.getPluginLogger().info(hooked + " hooked!");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private boolean isHooked(String hooked, String... versionPrefix) {
|
||||
Plugin p = Bukkit.getPluginManager().getPlugin(hooked);
|
||||
if (p != null) {
|
||||
String ver = p.getDescription().getVersion();
|
||||
for (String prefix : versionPrefix) {
|
||||
if (ver.startsWith(prefix)) {
|
||||
plugin.getPluginLogger().info(hooked + " hooked!");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerLevelerProvider(@NotNull LevelerProvider leveler) {
|
||||
if (levelerProviders.containsKey(leveler.identifier())) return false;
|
||||
levelerProviders.put(leveler.identifier(), leveler);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregisterLevelerProvider(@NotNull String id) {
|
||||
return levelerProviders.remove(id) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public LevelerProvider getLevelerProvider(String plugin) {
|
||||
return levelerProviders.get(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSeasonProvider(@NotNull SeasonProvider season) {
|
||||
((BukkitWorldManager) plugin.getWorldManager()).seasonProvider(season);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerItemProvider(@NotNull ItemProvider item) {
|
||||
return ((BukkitItemManager) plugin.getItemManager()).registerItemProvider(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregisterItemProvider(@NotNull String id) {
|
||||
return ((BukkitItemManager) plugin.getItemManager()).unregisterItemProvider(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
package net.momirealms.customcrops.bukkit.integration.adaptor;
|
||||
|
||||
import com.flowpowered.nbt.CompoundMap;
|
||||
import com.flowpowered.nbt.CompoundTag;
|
||||
import com.flowpowered.nbt.stream.NBTInputStream;
|
||||
import com.flowpowered.nbt.stream.NBTOutputStream;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.core.ConfigManager;
|
||||
import net.momirealms.customcrops.api.core.Registries;
|
||||
import net.momirealms.customcrops.api.core.block.CustomCropsBlock;
|
||||
import net.momirealms.customcrops.api.core.world.*;
|
||||
import net.momirealms.customcrops.api.core.world.adaptor.AbstractWorldAdaptor;
|
||||
import net.momirealms.customcrops.api.util.StringUtils;
|
||||
import net.momirealms.customcrops.common.helper.GsonHelper;
|
||||
import net.momirealms.customcrops.common.helper.VersionHelper;
|
||||
import net.momirealms.customcrops.common.util.Key;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.NamespacedKey;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.persistence.PersistentDataType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class BukkitWorldAdaptor extends AbstractWorldAdaptor<World> {
|
||||
|
||||
private static BiFunction<World, RegionPos, File> regionFileProvider;
|
||||
private static Function<World, File> worldFolderProvider;
|
||||
private static final NamespacedKey WORLD_DATA = new NamespacedKey(BukkitCustomCropsPlugin.getInstance().getBoostrap(), "data");
|
||||
private static final String DATA_FILE = "customcrops.dat";
|
||||
|
||||
public BukkitWorldAdaptor() {
|
||||
worldFolderProvider = (world -> {
|
||||
if (ConfigManager.absoluteWorldPath().isEmpty()) {
|
||||
return world.getWorldFolder();
|
||||
} else {
|
||||
return new File(ConfigManager.absoluteWorldPath(), world.getName());
|
||||
}
|
||||
});
|
||||
regionFileProvider = (world, pos) -> new File(worldFolderProvider.apply(world), "customcrops" + File.separator + getRegionDataFile(pos));
|
||||
|
||||
}
|
||||
|
||||
public static void regionFileProvider(BiFunction<World, RegionPos, File> regionFileProvider) {
|
||||
BukkitWorldAdaptor.regionFileProvider = regionFileProvider;
|
||||
}
|
||||
|
||||
public static void worldFolderProvider(Function<World, File> worldFolderProvider) {
|
||||
BukkitWorldAdaptor.worldFolderProvider = worldFolderProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public World getWorld(String worldName) {
|
||||
return Bukkit.getWorld(worldName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomCropsWorld<World> adapt(Object world) {
|
||||
return CustomCropsWorld.create((World) world, this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
@Override
|
||||
public WorldExtraData loadExtraData(World world) {
|
||||
if (VersionHelper.isVersionNewerThan1_18()) {
|
||||
// init world basic info
|
||||
String json = world.getPersistentDataContainer().get(WORLD_DATA, PersistentDataType.STRING);
|
||||
WorldExtraData data = (json == null || json.equals("null")) ? WorldExtraData.empty() : GsonHelper.get().fromJson(json, WorldExtraData.class);
|
||||
if (data == null) data = WorldExtraData.empty();
|
||||
return data;
|
||||
} else {
|
||||
File data = new File(getWorldFolder(world), DATA_FILE);
|
||||
if (data.exists()) {
|
||||
byte[] fileBytes = new byte[(int) data.length()];
|
||||
try (FileInputStream fis = new FileInputStream(data)) {
|
||||
fis.read(fileBytes);
|
||||
} catch (IOException e) {
|
||||
BukkitCustomCropsPlugin.getInstance().getPluginLogger().severe("[" + world.getName() + "] Failed to load extra data from " + data.getAbsolutePath(), e);
|
||||
}
|
||||
String jsonContent = new String(fileBytes, StandardCharsets.UTF_8);
|
||||
return GsonHelper.get().fromJson(jsonContent, WorldExtraData.class);
|
||||
} else {
|
||||
return WorldExtraData.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveExtraData(CustomCropsWorld<World> world) {
|
||||
if (VersionHelper.isVersionNewerThan1_18()) {
|
||||
world.world().getPersistentDataContainer().set(WORLD_DATA, PersistentDataType.STRING,
|
||||
GsonHelper.get().toJson(world.extraData()));
|
||||
} else {
|
||||
File data = new File(getWorldFolder(world.world()), DATA_FILE);
|
||||
try (FileWriter file = new FileWriter(data)) {
|
||||
GsonHelper.get().toJson(world.extraData(), file);
|
||||
} catch (IOException e) {
|
||||
BukkitCustomCropsPlugin.getInstance().getPluginLogger().severe("[" + world.worldName() + "] Failed to save extra data to " + data.getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CustomCropsRegion loadRegion(CustomCropsWorld<World> world, RegionPos pos, boolean createIfNotExist) {
|
||||
File data = getRegionDataFile(world.world(), pos);
|
||||
// if the data file not exists
|
||||
if (!data.exists()) {
|
||||
return createIfNotExist ? world.createRegion(pos) : null;
|
||||
} else {
|
||||
// load region from local files
|
||||
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(data))) {
|
||||
DataInputStream dataStream = new DataInputStream(bis);
|
||||
CustomCropsRegion region = deserializeRegion(world, dataStream, pos);
|
||||
dataStream.close();
|
||||
return region;
|
||||
} catch (Exception e) {
|
||||
BukkitCustomCropsPlugin.getInstance().getPluginLogger().severe("[" + world.worldName() + "] Failed to load CustomCrops region data at " + pos + ". Deleting the corrupted region.", e);
|
||||
boolean success = data.delete();
|
||||
if (success) {
|
||||
return createIfNotExist ? world.createRegion(pos) : null;
|
||||
} else {
|
||||
throw new RuntimeException("[" + world.worldName() + "] Failed to delete corrupted CustomCrops region data at " + pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CustomCropsChunk loadChunk(CustomCropsWorld<World> world, ChunkPos pos, boolean createIfNotExist) {
|
||||
CustomCropsRegion region = world.getOrCreateRegion(pos.toRegionPos());
|
||||
// In order to reduce frequent disk reads to determine whether a region exists, we read the region into the cache
|
||||
if (!region.isLoaded()) {
|
||||
region.load();
|
||||
}
|
||||
byte[] bytes = region.getCachedChunkBytes(pos);
|
||||
if (bytes == null) {
|
||||
return createIfNotExist ? world.createChunk(pos) : null;
|
||||
} else {
|
||||
try {
|
||||
long time1 = System.currentTimeMillis();
|
||||
DataInputStream dataStream = new DataInputStream(new ByteArrayInputStream(bytes));
|
||||
CustomCropsChunk chunk = deserializeChunk(world, dataStream);
|
||||
dataStream.close();
|
||||
long time2 = System.currentTimeMillis();
|
||||
BukkitCustomCropsPlugin.getInstance().debug("[" + world.worldName() + "] Took " + (time2-time1) + "ms to load chunk " + pos + " from cached region");
|
||||
return chunk;
|
||||
} catch (IOException e) {
|
||||
BukkitCustomCropsPlugin.getInstance().getPluginLogger().severe("[" + world.worldName() + "] Failed to load CustomCrops data at " + pos, e);
|
||||
region.removeCachedChunk(pos);
|
||||
return createIfNotExist ? world.createChunk(pos) : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveRegion(CustomCropsWorld<World> world, CustomCropsRegion region) {
|
||||
File file = getRegionDataFile(world.world(), region.regionPos());
|
||||
long time1 = System.currentTimeMillis();
|
||||
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file))) {
|
||||
bos.write(serializeRegion(region));
|
||||
long time2 = System.currentTimeMillis();
|
||||
BukkitCustomCropsPlugin.getInstance().debug("[" + world.worldName() + "] Took " + (time2-time1) + "ms to save region " + region.regionPos());
|
||||
} catch (IOException e) {
|
||||
BukkitCustomCropsPlugin.getInstance().getPluginLogger().severe("[" + world.worldName() + "] Failed to save CustomCrops region data." + region.regionPos(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveChunk(CustomCropsWorld<World> world, CustomCropsChunk chunk) {
|
||||
RegionPos pos = chunk.chunkPos().toRegionPos();
|
||||
Optional<CustomCropsRegion> region = world.getLoadedRegion(pos);
|
||||
if (region.isEmpty()) {
|
||||
BukkitCustomCropsPlugin.getInstance().getPluginLogger().severe("[" + world.worldName() + "] Region " + pos + " unloaded before chunk " + chunk.chunkPos() + " saving.");
|
||||
} else {
|
||||
CustomCropsRegion cropsRegion = region.get();
|
||||
SerializableChunk serializableChunk = toSerializableChunk(chunk);
|
||||
if (serializableChunk.canPrune()) {
|
||||
cropsRegion.removeCachedChunk(chunk.chunkPos());
|
||||
} else {
|
||||
cropsRegion.setCachedChunk(chunk.chunkPos(), serializeChunk(serializableChunk));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName(World world) {
|
||||
return world.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getWorldFullTime(World world) {
|
||||
return world.getFullTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int priority() {
|
||||
return BUKKIT_WORLD_PRIORITY;
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
private CustomCropsRegion deserializeRegion(CustomCropsWorld<World> world, DataInputStream dataStream, RegionPos pos) throws IOException {
|
||||
int regionVersion = dataStream.readByte();
|
||||
int regionX = dataStream.readInt();
|
||||
int regionZ = dataStream.readInt();
|
||||
RegionPos regionPos = RegionPos.of(regionX, regionZ);
|
||||
ConcurrentHashMap<ChunkPos, byte[]> map = new ConcurrentHashMap<>();
|
||||
int chunkAmount = dataStream.readInt();
|
||||
for (int i = 0; i < chunkAmount; i++) {
|
||||
int chunkX = dataStream.readInt();
|
||||
int chunkZ = dataStream.readInt();
|
||||
ChunkPos chunkPos = ChunkPos.of(chunkX, chunkZ);
|
||||
byte[] chunkData = new byte[dataStream.readInt()];
|
||||
dataStream.read(chunkData);
|
||||
map.put(chunkPos, chunkData);
|
||||
}
|
||||
return world.restoreRegion(pos, map);
|
||||
}
|
||||
|
||||
private byte[] serializeRegion(CustomCropsRegion region) {
|
||||
ByteArrayOutputStream outByteStream = new ByteArrayOutputStream();
|
||||
DataOutputStream outStream = new DataOutputStream(outByteStream);
|
||||
try {
|
||||
outStream.writeByte(REGION_VERSION);
|
||||
outStream.writeInt(region.regionPos().x());
|
||||
outStream.writeInt(region.regionPos().z());
|
||||
Map<ChunkPos, byte[]> map = region.dataToSave();
|
||||
outStream.writeInt(map.size());
|
||||
for (Map.Entry<ChunkPos, byte[]> entry : map.entrySet()) {
|
||||
outStream.writeInt(entry.getKey().x());
|
||||
outStream.writeInt(entry.getKey().z());
|
||||
byte[] dataArray = entry.getValue();
|
||||
outStream.writeInt(dataArray.length);
|
||||
outStream.write(dataArray);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
BukkitCustomCropsPlugin.getInstance().getPluginLogger().severe("Failed to serialize CustomCrops region data." + region.regionPos(), e);
|
||||
}
|
||||
return outByteStream.toByteArray();
|
||||
}
|
||||
|
||||
private CustomCropsChunk deserializeChunk(CustomCropsWorld<World> world, DataInputStream dataStream) throws IOException {
|
||||
int chunkVersion = dataStream.readByte();
|
||||
byte[] blockData = readCompressedBytes(dataStream);
|
||||
return deserializeChunk(world, blockData, chunkVersion);
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
private byte[] readCompressedBytes(DataInputStream dataStream) throws IOException {
|
||||
int compressedLength = dataStream.readInt();
|
||||
int decompressedLength = dataStream.readInt();
|
||||
byte[] compressedData = new byte[compressedLength];
|
||||
byte[] decompressedData = new byte[decompressedLength];
|
||||
|
||||
dataStream.read(compressedData);
|
||||
zstdDecompress(decompressedData, compressedData);
|
||||
return decompressedData;
|
||||
}
|
||||
|
||||
private File getWorldFolder(World world) {
|
||||
return worldFolderProvider.apply(world);
|
||||
}
|
||||
|
||||
private File getRegionDataFile(World world, RegionPos regionPos) {
|
||||
return regionFileProvider.apply(world, regionPos);
|
||||
}
|
||||
|
||||
private String getRegionDataFile(RegionPos regionPos) {
|
||||
return "r." + regionPos.x() + "." + regionPos.z() + ".mcc";
|
||||
}
|
||||
|
||||
private byte[] serializeChunk(SerializableChunk serializableChunk) {
|
||||
ByteArrayOutputStream outByteStream = new ByteArrayOutputStream();
|
||||
DataOutputStream outStream = new DataOutputStream(outByteStream);
|
||||
try {
|
||||
outStream.writeByte(CHUNK_VERSION);
|
||||
byte[] serializedSections = toBytes(serializableChunk);
|
||||
byte[] compressed = zstdCompress(serializedSections);
|
||||
outStream.writeInt(compressed.length);
|
||||
outStream.writeInt(serializedSections.length);
|
||||
outStream.write(compressed);
|
||||
} catch (IOException e) {
|
||||
BukkitCustomCropsPlugin.getInstance().getPluginLogger().severe("Failed to serialize chunk " + ChunkPos.of(serializableChunk.x(), serializableChunk.z()));
|
||||
}
|
||||
return outByteStream.toByteArray();
|
||||
}
|
||||
|
||||
private byte[] toBytes(SerializableChunk chunk) throws IOException {
|
||||
ByteArrayOutputStream outByteStream = new ByteArrayOutputStream(16384);
|
||||
DataOutputStream outStream = new DataOutputStream(outByteStream);
|
||||
outStream.writeInt(chunk.x());
|
||||
outStream.writeInt(chunk.z());
|
||||
outStream.writeInt(chunk.loadedSeconds());
|
||||
outStream.writeLong(chunk.lastLoadedTime());
|
||||
// write queue
|
||||
int[] queue = chunk.queuedTasks();
|
||||
outStream.writeInt(queue.length / 2);
|
||||
for (int i : queue) {
|
||||
outStream.writeInt(i);
|
||||
}
|
||||
// write ticked blocks
|
||||
int[] tickedSet = chunk.ticked();
|
||||
outStream.writeInt(tickedSet.length);
|
||||
for (int i : tickedSet) {
|
||||
outStream.writeInt(i);
|
||||
}
|
||||
// write block data
|
||||
List<SerializableSection> sectionsToSave = chunk.sections();
|
||||
outStream.writeInt(sectionsToSave.size());
|
||||
for (SerializableSection section : sectionsToSave) {
|
||||
outStream.writeInt(section.sectionID());
|
||||
byte[] blockData = toBytes(section.blocks());
|
||||
outStream.writeInt(blockData.length);
|
||||
outStream.write(blockData);
|
||||
}
|
||||
return outByteStream.toByteArray();
|
||||
}
|
||||
|
||||
private byte[] toBytes(Collection<CompoundTag> blocks) throws IOException {
|
||||
ByteArrayOutputStream outByteStream = new ByteArrayOutputStream(16384);
|
||||
DataOutputStream outStream = new DataOutputStream(outByteStream);
|
||||
outStream.writeInt(blocks.size());
|
||||
for (CompoundTag block : blocks) {
|
||||
byte[] blockData = toBytes(block);
|
||||
outStream.writeInt(blockData.length);
|
||||
outStream.write(blockData);
|
||||
}
|
||||
return outByteStream.toByteArray();
|
||||
}
|
||||
|
||||
private byte[] toBytes(CompoundTag tag) throws IOException {
|
||||
if (tag == null || tag.getValue().isEmpty())
|
||||
return new byte[0];
|
||||
ByteArrayOutputStream outByteStream = new ByteArrayOutputStream();
|
||||
NBTOutputStream outStream = new NBTOutputStream(
|
||||
outByteStream,
|
||||
NBTInputStream.NO_COMPRESSION,
|
||||
ByteOrder.BIG_ENDIAN
|
||||
);
|
||||
outStream.writeTag(tag);
|
||||
return outByteStream.toByteArray();
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private CustomCropsChunk deserializeChunk(CustomCropsWorld world, byte[] bytes, int chunkVersion) throws IOException {
|
||||
Function<String, Key> keyFunction = chunkVersion < 2 ?
|
||||
(s) -> {
|
||||
return Key.key("customcrops", StringUtils.toLowerCase(s));
|
||||
} : s -> {
|
||||
return Key.key(s);
|
||||
};
|
||||
DataInputStream chunkData = new DataInputStream(new ByteArrayInputStream(bytes));
|
||||
// read coordinate
|
||||
int x = chunkData.readInt();
|
||||
int z = chunkData.readInt();
|
||||
ChunkPos coordinate = new ChunkPos(x, z);
|
||||
// read loading info
|
||||
int loadedSeconds = chunkData.readInt();
|
||||
long lastLoadedTime = chunkData.readLong();
|
||||
// read task queue
|
||||
int tasksSize = chunkData.readInt();
|
||||
PriorityQueue<DelayedTickTask> queue = new PriorityQueue<>(Math.max(11, tasksSize));
|
||||
for (int i = 0; i < tasksSize; i++) {
|
||||
int time = chunkData.readInt();
|
||||
BlockPos pos = new BlockPos(chunkData.readInt());
|
||||
queue.add(new DelayedTickTask(time, pos));
|
||||
}
|
||||
// read ticked blocks
|
||||
int tickedSize = chunkData.readInt();
|
||||
HashSet<BlockPos> tickedSet = new HashSet<>(Math.max(11, tickedSize));
|
||||
for (int i = 0; i < tickedSize; i++) {
|
||||
tickedSet.add(new BlockPos(chunkData.readInt()));
|
||||
}
|
||||
// read block data
|
||||
ConcurrentHashMap<Integer, CustomCropsSection> sectionMap = new ConcurrentHashMap<>();
|
||||
int sections = chunkData.readInt();
|
||||
// read sections
|
||||
for (int i = 0; i < sections; i++) {
|
||||
ConcurrentHashMap<BlockPos, CustomCropsBlockState> blockMap = new ConcurrentHashMap<>();
|
||||
int sectionID = chunkData.readInt();
|
||||
byte[] sectionBytes = new byte[chunkData.readInt()];
|
||||
chunkData.read(sectionBytes);
|
||||
DataInputStream sectionData = new DataInputStream(new ByteArrayInputStream(sectionBytes));
|
||||
int blockAmount = sectionData.readInt();
|
||||
// read blocks
|
||||
for (int j = 0; j < blockAmount; j++){
|
||||
byte[] blockData = new byte[sectionData.readInt()];
|
||||
sectionData.read(blockData);
|
||||
CompoundMap block = readCompound(blockData).getValue();
|
||||
Key key = keyFunction.apply((String) block.get("type").getValue());
|
||||
CompoundMap data = (CompoundMap) block.get("data").getValue();
|
||||
CustomCropsBlock customBlock = Registries.BLOCK.get(key);
|
||||
if (customBlock == null) {
|
||||
BukkitCustomCropsPlugin.getInstance().getInstance().getPluginLogger().warn("[" + world.worldName() + "] Unrecognized custom block " + key + " has been removed from chunk " + ChunkPos.of(x, z));
|
||||
continue;
|
||||
}
|
||||
for (int pos : (int[]) block.get("pos").getValue()) {
|
||||
BlockPos blockPos = new BlockPos(pos);
|
||||
blockMap.put(blockPos, CustomCropsBlockState.create(customBlock, data));
|
||||
}
|
||||
}
|
||||
sectionMap.put(sectionID, CustomCropsSection.restore(sectionID, blockMap));
|
||||
}
|
||||
return world.restoreChunk(coordinate, loadedSeconds, lastLoadedTime, sectionMap, queue, tickedSet);
|
||||
}
|
||||
|
||||
private CompoundTag readCompound(byte[] bytes) throws IOException {
|
||||
if (bytes.length == 0)
|
||||
return null;
|
||||
NBTInputStream nbtInputStream = new NBTInputStream(
|
||||
new ByteArrayInputStream(bytes),
|
||||
NBTInputStream.NO_COMPRESSION,
|
||||
ByteOrder.BIG_ENDIAN
|
||||
);
|
||||
return (CompoundTag) nbtInputStream.readTag();
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package net.momirealms.customcrops.mechanic.item.factory;
|
||||
package net.momirealms.customcrops.bukkit.item;
|
||||
|
||||
import com.saicone.rtag.RtagItem;
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.mechanic.item.factory.impl.ComponentItemFactory;
|
||||
import net.momirealms.customcrops.mechanic.item.factory.impl.UniversalItemFactory;
|
||||
import net.momirealms.customcrops.common.item.Item;
|
||||
import net.momirealms.customcrops.common.item.ItemFactory;
|
||||
import net.momirealms.customcrops.common.plugin.CustomCropsPlugin;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Objects;
|
||||
@@ -83,4 +83,9 @@ public abstract class BukkitItemFactory extends ItemFactory<CustomCropsPlugin, R
|
||||
protected ItemStack loadCopy(RtagItem item) {
|
||||
return item.loadCopy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean unbreakable(RtagItem item) {
|
||||
return item.isUnbreakable();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,442 @@
|
||||
package net.momirealms.customcrops.bukkit.item;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.sound.Sound;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.core.*;
|
||||
import net.momirealms.customcrops.api.core.block.BreakReason;
|
||||
import net.momirealms.customcrops.api.core.block.CustomCropsBlock;
|
||||
import net.momirealms.customcrops.api.core.item.CustomCropsItem;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsWorld;
|
||||
import net.momirealms.customcrops.api.core.wrapper.WrappedBreakEvent;
|
||||
import net.momirealms.customcrops.api.core.wrapper.WrappedInteractAirEvent;
|
||||
import net.momirealms.customcrops.api.core.wrapper.WrappedInteractEvent;
|
||||
import net.momirealms.customcrops.api.core.wrapper.WrappedPlaceEvent;
|
||||
import net.momirealms.customcrops.api.integration.ItemProvider;
|
||||
import net.momirealms.customcrops.api.util.EventUtils;
|
||||
import net.momirealms.customcrops.api.util.LocationUtils;
|
||||
import net.momirealms.customcrops.api.util.PluginUtils;
|
||||
import net.momirealms.customcrops.api.util.StringUtils;
|
||||
import net.momirealms.customcrops.common.item.Item;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.ItemFrame;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.player.PlayerItemDamageEvent;
|
||||
import org.bukkit.inventory.EquipmentSlot;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.*;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
|
||||
public class BukkitItemManager extends AbstractItemManager {
|
||||
|
||||
private final BukkitCustomCropsPlugin plugin;
|
||||
private CustomItemProvider provider;
|
||||
private AbstractCustomEventListener eventListener;
|
||||
private final HashMap<String, ItemProvider> itemProviders = new HashMap<>();
|
||||
private ItemProvider[] itemDetectArray = new ItemProvider[0];
|
||||
private final BukkitItemFactory factory;
|
||||
|
||||
public BukkitItemManager(BukkitCustomCropsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
try {
|
||||
this.hookDefaultPlugins();
|
||||
} catch (ReflectiveOperationException e) {
|
||||
plugin.getPluginLogger().warn("Failed to load CustomItemProvider", e);
|
||||
}
|
||||
if (this.provider == null) {
|
||||
plugin.getPluginLogger().warn("ItemsAdder/Oraxen are not installed, which can cause problems unless you use the CustomCrops API.");
|
||||
}
|
||||
this.factory = BukkitItemFactory.create(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomEventListener(@NotNull AbstractCustomEventListener listener) {
|
||||
Objects.requireNonNull(listener, "listener cannot be null");
|
||||
if (this.eventListener != null) {
|
||||
HandlerList.unregisterAll(this.eventListener);
|
||||
}
|
||||
this.eventListener = listener;
|
||||
Bukkit.getPluginManager().registerEvents(this.eventListener, plugin.getBoostrap());
|
||||
plugin.debug("Custom event listener set to " + listener.getClass().getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomItemProvider(@NotNull CustomItemProvider provider) {
|
||||
Objects.requireNonNull(provider, "provider cannot be null");
|
||||
this.provider = provider;
|
||||
plugin.debug("Custom item provider set to " + provider.getClass().getName());
|
||||
}
|
||||
|
||||
public boolean registerItemProvider(ItemProvider item) {
|
||||
if (itemProviders.containsKey(item.identifier())) return false;
|
||||
itemProviders.put(item.identifier(), item);
|
||||
this.resetItemDetectionOrder();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean unregisterItemProvider(String id) {
|
||||
boolean success = itemProviders.remove(id) != null;
|
||||
if (success)
|
||||
this.resetItemDetectionOrder();
|
||||
return success;
|
||||
}
|
||||
|
||||
private void resetItemDetectionOrder() {
|
||||
ArrayList<ItemProvider> list = new ArrayList<>();
|
||||
for (String plugin : ConfigManager.itemDetectOrder()) {
|
||||
ItemProvider provider = itemProviders.get(plugin);
|
||||
if (provider != null)
|
||||
list.add(provider);
|
||||
}
|
||||
this.itemDetectArray = list.toArray(new ItemProvider[0]);
|
||||
}
|
||||
|
||||
private void hookDefaultPlugins() throws ReflectiveOperationException {
|
||||
if (PluginUtils.isEnabled("Oraxen")) {
|
||||
String rVersion;
|
||||
if (PluginUtils.getPluginVersion("Oraxen").startsWith("2")) {
|
||||
rVersion = "r2";
|
||||
} else {
|
||||
rVersion = "r1";
|
||||
}
|
||||
Class<?> oraxenProviderClass = Class.forName("net.momirealms.customcrops.bukkit.integration.custom.oraxen_" + rVersion + ".OraxenProvider");
|
||||
Constructor<?> oraxenProviderConstructor = oraxenProviderClass.getDeclaredConstructor();
|
||||
oraxenProviderConstructor.setAccessible(true);
|
||||
this.provider = (CustomItemProvider) oraxenProviderConstructor.newInstance();
|
||||
|
||||
Class<?> oraxenListenerClass = Class.forName("net.momirealms.customcrops.bukkit.integration.custom.oraxen_" + rVersion + ".OraxenListener");
|
||||
Constructor<?> oraxenListenerConstructor = oraxenListenerClass.getDeclaredConstructor(AbstractItemManager.class);
|
||||
oraxenListenerConstructor.setAccessible(true);
|
||||
this.setCustomEventListener((AbstractCustomEventListener) oraxenListenerConstructor.newInstance(this));
|
||||
} else if (PluginUtils.isEnabled("ItemsAdder")) {
|
||||
String rVersion = "r1";
|
||||
Class<?> itemsAdderProviderClass = Class.forName("net.momirealms.customcrops.bukkit.integration.custom.itemsadder_" + rVersion + ".ItemsAdderProvider");
|
||||
Constructor<?> itemsAdderProviderConstructor = itemsAdderProviderClass.getDeclaredConstructor();
|
||||
itemsAdderProviderConstructor.setAccessible(true);
|
||||
this.provider = (CustomItemProvider) itemsAdderProviderConstructor.newInstance();
|
||||
|
||||
Class<?> itemsAdderListenerClass = Class.forName("net.momirealms.customcrops.bukkit.integration.custom.itemsadder_" + rVersion + ".ItemsAdderListener");
|
||||
Constructor<?> itemsAdderListenerConstructor = itemsAdderListenerClass.getDeclaredConstructor(AbstractItemManager.class);
|
||||
itemsAdderListenerConstructor.setAccessible(true);
|
||||
this.setCustomEventListener((AbstractCustomEventListener) itemsAdderListenerConstructor.newInstance(this));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void place(@NotNull Location location, @NotNull ExistenceForm form, @NotNull String id, FurnitureRotation rotation) {
|
||||
switch (form) {
|
||||
case BLOCK -> placeBlock(location, id);
|
||||
case FURNITURE -> placeFurniture(location, id, rotation);
|
||||
case ANY -> throw new IllegalArgumentException("Invalid existence form: " + form);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FurnitureRotation remove(@NotNull Location location, @NotNull ExistenceForm form) {
|
||||
switch (form) {
|
||||
case BLOCK -> {
|
||||
this.removeBlock(location);
|
||||
return FurnitureRotation.NONE;
|
||||
}
|
||||
case FURNITURE -> {
|
||||
return this.removeFurniture(location);
|
||||
}
|
||||
case ANY -> {
|
||||
this.removeBlock(location);
|
||||
return this.removeFurniture(location);
|
||||
}
|
||||
}
|
||||
return FurnitureRotation.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void placeBlock(@NotNull Location location, @NotNull String id) {
|
||||
if (StringUtils.isCapitalLetter(id)) {
|
||||
location.getWorld().getBlockAt(location).setType(Material.valueOf(id), false);
|
||||
} else {
|
||||
this.provider.placeCustomBlock(location, id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void placeFurniture(@NotNull Location location, @NotNull String id, FurnitureRotation rotation) {
|
||||
Entity entity = this.provider.placeFurniture(location, id);
|
||||
if (entity != null) {
|
||||
if (entity instanceof ItemFrame itemFrame) {
|
||||
itemFrame.setRotation(rotation.getBukkitRotation());
|
||||
} else if (entity instanceof LivingEntity livingEntity) {
|
||||
livingEntity.setRotation(rotation.getYaw(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeBlock(@NotNull Location location) {
|
||||
if (!this.provider.removeCustomBlock(location)) {
|
||||
location.getBlock().setType(Material.AIR, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FurnitureRotation removeFurniture(@NotNull Location location) {
|
||||
Collection<Entity> entities = location.getWorld().getNearbyEntities(LocationUtils.toSurfaceCenterLocation(location), 0.5,0.25,0.5);
|
||||
FurnitureRotation rotation = null;
|
||||
for (Entity entity : entities) {
|
||||
if (this.provider.removeFurniture(entity) && rotation == null) {
|
||||
if (entity instanceof ItemFrame itemFrame) {
|
||||
rotation = FurnitureRotation.getByRotation(itemFrame.getRotation());
|
||||
} else {
|
||||
rotation = FurnitureRotation.getByYaw(entity.getYaw());
|
||||
}
|
||||
}
|
||||
}
|
||||
return rotation;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String blockID(@NotNull Block block) {
|
||||
String id = this.provider.blockID(block);
|
||||
if (id == null) {
|
||||
id = block.getType().toString();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String furnitureID(@NotNull Entity entity) {
|
||||
return this.provider.furnitureID(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String entityID(@NotNull Entity entity) {
|
||||
String id = furnitureID(entity);
|
||||
if (id == null) {
|
||||
id = entity.getType().toString();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String furnitureID(Location location) {
|
||||
Collection<Entity> entities = location.getWorld().getNearbyEntities(LocationUtils.toSurfaceCenterLocation(location), 0.5,0.25,0.5);
|
||||
for (Entity entity : entities) {
|
||||
if (provider.isFurniture(entity)) {
|
||||
return provider.furnitureID(entity);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String anyID(Location location) {
|
||||
Block block = location.getBlock();
|
||||
if (block.getType() == Material.AIR) {
|
||||
String id = furnitureID(location);
|
||||
if (id == null) {
|
||||
return "AIR";
|
||||
}
|
||||
return id;
|
||||
} else {
|
||||
return blockID(location);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String id(Location location, ExistenceForm form) {
|
||||
return switch (form) {
|
||||
case BLOCK -> blockID(location);
|
||||
case FURNITURE -> furnitureID(location);
|
||||
case ANY -> anyID(location);
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String id(@Nullable ItemStack itemStack) {
|
||||
if (itemStack == null || itemStack.getType() == Material.AIR) return "AIR";
|
||||
String id = provider.itemID(itemStack);
|
||||
if (id != null) return id;
|
||||
for (ItemProvider p : itemDetectArray) {
|
||||
id = p.itemID(itemStack);
|
||||
if (id != null) return p.identifier() + ":" + id;
|
||||
}
|
||||
return itemStack.getType().name();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ItemStack build(Player player, @NotNull String id) {
|
||||
ItemStack itemStack = provider.itemStack(player, id);
|
||||
if (itemStack != null) {
|
||||
return itemStack;
|
||||
}
|
||||
if (!id.contains(":")) {
|
||||
try {
|
||||
return new ItemStack(Material.valueOf(id.toUpperCase(Locale.ENGLISH)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
plugin.getPluginLogger().severe("Item " + id + " not exists", e);
|
||||
return new ItemStack(Material.PAPER);
|
||||
}
|
||||
} else {
|
||||
String[] split = id.split(":", 2);
|
||||
ItemProvider provider = requireNonNull(itemProviders.get(split[0]), "Item provider: " + split[0] + " not found");
|
||||
return requireNonNull(provider.buildItem(player, split[1]), "Item: " + split[0] + " not found");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item<ItemStack> wrap(ItemStack itemStack) {
|
||||
return factory.wrap(itemStack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decreaseDamage(Player player, ItemStack itemStack, int amount) {
|
||||
if (itemStack == null || itemStack.getType() == Material.AIR || itemStack.getAmount() == 0)
|
||||
return;
|
||||
Item<ItemStack> wrapped = factory.wrap(itemStack);
|
||||
if (wrapped.unbreakable()) return;
|
||||
wrapped.damage(Math.max(0, wrapped.damage().orElse(0) - amount));
|
||||
wrapped.load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void increaseDamage(Player player, ItemStack itemStack, int amount) {
|
||||
if (itemStack == null || itemStack.getType() == Material.AIR || itemStack.getAmount() == 0)
|
||||
return;
|
||||
Item<ItemStack> wrapped = factory.wrap(itemStack);
|
||||
if (wrapped.unbreakable())
|
||||
return;
|
||||
ItemMeta previousMeta = itemStack.getItemMeta().clone();
|
||||
PlayerItemDamageEvent itemDamageEvent = new PlayerItemDamageEvent(player, itemStack, amount);
|
||||
if (EventUtils.fireAndCheckCancel(itemDamageEvent)) {
|
||||
plugin.debug("Another plugin modified the item from `PlayerItemDamageEvent` called by CustomCrops");
|
||||
return;
|
||||
}
|
||||
if (!itemStack.getItemMeta().equals(previousMeta)) {
|
||||
return;
|
||||
}
|
||||
int damage = wrapped.damage().orElse(0);
|
||||
if (damage + amount >= wrapped.maxDamage().orElse((int) itemStack.getType().getMaxDurability())) {
|
||||
plugin.getSenderFactory().getAudience(player).playSound(Sound.sound(Key.key("minecraft:entity.item.break"), Sound.Source.PLAYER, 1, 1));
|
||||
itemStack.setAmount(0);
|
||||
return;
|
||||
}
|
||||
wrapped.damage(damage + amount);
|
||||
wrapped.load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePlayerInteractAir(Player player, EquipmentSlot hand, ItemStack itemInHand) {
|
||||
Optional<CustomCropsWorld<?>> optionalWorld = plugin.getWorldManager().getWorld(player.getWorld());
|
||||
if (optionalWorld.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String itemID = id(itemInHand);
|
||||
CustomCropsItem customCropsItem = Registries.ITEMS.get(itemID);
|
||||
if (customCropsItem != null) {
|
||||
customCropsItem.interactAir(new WrappedInteractAirEvent(
|
||||
optionalWorld.get(),
|
||||
player,
|
||||
hand,
|
||||
itemInHand,
|
||||
itemID
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePlayerInteractBlock(Player player, Block block, String blockID, BlockFace blockFace, EquipmentSlot hand, ItemStack itemInHand, Cancellable event) {
|
||||
Optional<CustomCropsWorld<?>> optionalWorld = plugin.getWorldManager().getWorld(player.getWorld());
|
||||
if (optionalWorld.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String itemID = id(itemInHand);
|
||||
CustomCropsWorld<?> world = optionalWorld.get();
|
||||
WrappedInteractEvent wrapped = new WrappedInteractEvent(ExistenceForm.BLOCK, player, world, block.getLocation(), blockID, itemInHand, itemID, hand, blockFace, event);
|
||||
|
||||
handleInteractEvent(blockID, itemID, wrapped);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePlayerInteractFurniture(Player player, Location location, String furnitureID, EquipmentSlot hand, ItemStack itemInHand, Cancellable event) {
|
||||
Optional<CustomCropsWorld<?>> optionalWorld = plugin.getWorldManager().getWorld(player.getWorld());
|
||||
if (optionalWorld.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String itemID = id(itemInHand);
|
||||
CustomCropsWorld<?> world = optionalWorld.get();
|
||||
WrappedInteractEvent wrapped = new WrappedInteractEvent(ExistenceForm.FURNITURE, player, world, location, furnitureID, itemInHand, itemID, hand, null, event);
|
||||
|
||||
handleInteractEvent(furnitureID, itemID, wrapped);
|
||||
}
|
||||
|
||||
private void handleInteractEvent(String blockID, String itemID, WrappedInteractEvent wrapped) {
|
||||
CustomCropsItem customCropsItem = Registries.ITEMS.get(itemID);
|
||||
if (customCropsItem != null) {
|
||||
InteractionResult result = customCropsItem.interactAt(wrapped);
|
||||
if (result != InteractionResult.PASS)
|
||||
return;
|
||||
}
|
||||
|
||||
if (wrapped.isCancelled()) return;
|
||||
|
||||
CustomCropsBlock customCropsBlock = Registries.BLOCKS.get(blockID);
|
||||
if (customCropsBlock != null) {
|
||||
customCropsBlock.onInteract(wrapped);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePlayerBreak(Player player, Location location, ItemStack itemInHand, String brokenID, Cancellable event) {
|
||||
Optional<CustomCropsWorld<?>> optionalWorld = plugin.getWorldManager().getWorld(player.getWorld());
|
||||
if (optionalWorld.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String itemID = id(itemInHand);
|
||||
CustomCropsWorld<?> world = optionalWorld.get();
|
||||
WrappedBreakEvent wrapped = new WrappedBreakEvent(player, null, world, location, brokenID, itemInHand, itemID, BreakReason.BREAK, event);
|
||||
CustomCropsBlock customCropsBlock = Registries.BLOCKS.get(brokenID);
|
||||
if (customCropsBlock != null) {
|
||||
customCropsBlock.onBreak(wrapped);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePlayerPlace(Player player, Location location, String placedID, EquipmentSlot hand, ItemStack itemInHand, Cancellable event) {
|
||||
Optional<CustomCropsWorld<?>> optionalWorld = plugin.getWorldManager().getWorld(player.getWorld());
|
||||
if (optionalWorld.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String itemID = id(itemInHand);
|
||||
CustomCropsWorld<?> world = optionalWorld.get();
|
||||
WrappedPlaceEvent wrapped = new WrappedPlaceEvent(player, world, location, placedID, hand, itemInHand, itemID, event);
|
||||
CustomCropsBlock customCropsBlock = Registries.BLOCKS.get(placedID);
|
||||
if (customCropsBlock != null) {
|
||||
customCropsBlock.onPlace(wrapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
package net.momirealms.customcrops.mechanic.item.factory.impl;
|
||||
package net.momirealms.customcrops.bukkit.item;
|
||||
|
||||
import com.saicone.rtag.RtagItem;
|
||||
import com.saicone.rtag.data.ComponentType;
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.mechanic.item.factory.BukkitItemFactory;
|
||||
import net.momirealms.customcrops.mechanic.item.factory.ComponentKeys;
|
||||
import net.momirealms.customcrops.common.item.ComponentKeys;
|
||||
import net.momirealms.customcrops.common.plugin.CustomCropsPlugin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -1,10 +1,7 @@
|
||||
package net.momirealms.customcrops.mechanic.item.factory.impl;
|
||||
|
||||
|
||||
package net.momirealms.customcrops.bukkit.item;
|
||||
|
||||
import com.saicone.rtag.RtagItem;
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.mechanic.item.factory.BukkitItemFactory;
|
||||
import net.momirealms.customcrops.common.plugin.CustomCropsPlugin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* 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.customcrops.bukkit.misc;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.common.helper.AdventureHelper;
|
||||
import net.momirealms.customcrops.common.helper.VersionHelper;
|
||||
import net.momirealms.customcrops.common.plugin.feature.Reloadable;
|
||||
import net.momirealms.customcrops.common.plugin.scheduler.SchedulerTask;
|
||||
import net.momirealms.customcrops.common.util.Pair;
|
||||
import net.momirealms.sparrow.heart.SparrowHeart;
|
||||
import net.momirealms.sparrow.heart.feature.entity.FakeEntity;
|
||||
import net.momirealms.sparrow.heart.feature.entity.armorstand.FakeArmorStand;
|
||||
import net.momirealms.sparrow.heart.feature.entity.display.FakeTextDisplay;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class HologramManager implements Listener, Reloadable {
|
||||
|
||||
private final ConcurrentHashMap<UUID, HologramCache> hologramMap = new ConcurrentHashMap<>();
|
||||
private final BukkitCustomCropsPlugin plugin;
|
||||
private SchedulerTask cacheCheckTask;
|
||||
private static HologramManager manager;
|
||||
|
||||
public static HologramManager getInstance() {
|
||||
return manager;
|
||||
}
|
||||
|
||||
public HologramManager(BukkitCustomCropsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
manager = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
|
||||
this.cacheCheckTask = plugin.getScheduler().asyncRepeating(() -> {
|
||||
ArrayList<UUID> removed = new ArrayList<>();
|
||||
long current = System.currentTimeMillis();
|
||||
for (Map.Entry<UUID, HologramCache> entry : hologramMap.entrySet()) {
|
||||
Player player = Bukkit.getPlayer(entry.getKey());
|
||||
if (player == null || !player.isOnline()) {
|
||||
removed.add(entry.getKey());
|
||||
} else {
|
||||
entry.getValue().removeOutDated(current, player);
|
||||
}
|
||||
}
|
||||
for (UUID uuid : removed) {
|
||||
hologramMap.remove(uuid);
|
||||
}
|
||||
}, 100, 100, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
HandlerList.unregisterAll(this);
|
||||
for (Map.Entry<UUID, HologramCache> entry : hologramMap.entrySet()) {
|
||||
Player player = Bukkit.getPlayer(entry.getKey());
|
||||
if (player != null && player.isOnline()) {
|
||||
entry.getValue().removeAll(player);
|
||||
}
|
||||
}
|
||||
if (cacheCheckTask != null) cacheCheckTask.cancel();
|
||||
this.hologramMap.clear();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(PlayerQuitEvent event) {
|
||||
this.hologramMap.remove(event.getPlayer().getUniqueId());
|
||||
}
|
||||
|
||||
public void showHologram(Player player, Location location, Component component, int millis) {
|
||||
HologramCache hologramCache = hologramMap.get(player.getUniqueId());
|
||||
if (hologramCache != null) {
|
||||
hologramCache.showHologram(player, location, component, millis);
|
||||
} else {
|
||||
hologramCache = new HologramCache();
|
||||
hologramCache.showHologram(player, location, component, millis);
|
||||
hologramMap.put(player.getUniqueId(), hologramCache);
|
||||
}
|
||||
}
|
||||
|
||||
public static class HologramCache {
|
||||
|
||||
private final ConcurrentHashMap<Location, Pair<FakeEntity, Long>> cache = new ConcurrentHashMap<>();
|
||||
|
||||
public void removeOutDated(long current, Player player) {
|
||||
ArrayList<Location> removed = new ArrayList<>();
|
||||
for (Map.Entry<Location, Pair<FakeEntity, Long>> entry : cache.entrySet()) {
|
||||
if (entry.getValue().right() < current) {
|
||||
entry.getValue().left().destroy(player);
|
||||
removed.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
for (Location location : removed) {
|
||||
cache.remove(location);
|
||||
}
|
||||
}
|
||||
|
||||
public void showHologram(Player player, Location location, Component component, int millis) {
|
||||
Pair<FakeEntity, Long> pair = cache.get(location);
|
||||
if (pair != null) {
|
||||
pair.left().destroy(player);
|
||||
pair.right(System.currentTimeMillis() + millis);
|
||||
if (VersionHelper.isVersionNewerThan1_19_4()) {
|
||||
FakeTextDisplay fakeEntity = SparrowHeart.getInstance().createFakeTextDisplay(location.clone().add(0,1.25,0));
|
||||
fakeEntity.name(AdventureHelper.componentToJson(component));
|
||||
fakeEntity.rgba(0, 0, 0, 0);
|
||||
fakeEntity.spawn(player);
|
||||
pair.left(fakeEntity);
|
||||
} else {
|
||||
FakeArmorStand fakeEntity = SparrowHeart.getInstance().createFakeArmorStand(location);
|
||||
fakeEntity.name(AdventureHelper.componentToJson(component));
|
||||
fakeEntity.small(true);
|
||||
fakeEntity.invisible(true);
|
||||
fakeEntity.spawn(player);
|
||||
pair.left(fakeEntity);
|
||||
}
|
||||
} else {
|
||||
long removeTime = System.currentTimeMillis() + millis;
|
||||
if (VersionHelper.isVersionNewerThan1_19_4()) {
|
||||
FakeTextDisplay fakeEntity = SparrowHeart.getInstance().createFakeTextDisplay(location.clone().add(0,1.25,0));
|
||||
fakeEntity.name(AdventureHelper.componentToJson(component));
|
||||
fakeEntity.rgba(0, 0, 0, 0);
|
||||
fakeEntity.spawn(player);
|
||||
this.cache.put(location, Pair.of(fakeEntity, removeTime));
|
||||
} else {
|
||||
FakeArmorStand fakeEntity = SparrowHeart.getInstance().createFakeArmorStand(location);
|
||||
fakeEntity.name(AdventureHelper.componentToJson(component));
|
||||
fakeEntity.small(true);
|
||||
fakeEntity.invisible(true);
|
||||
fakeEntity.spawn(player);
|
||||
this.cache.put(location, Pair.of(fakeEntity, removeTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAll(Player player) {
|
||||
for (Map.Entry<Location, Pair<FakeEntity, Long>> entry : this.cache.entrySet()) {
|
||||
entry.getValue().left().destroy(player);
|
||||
}
|
||||
cache.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package net.momirealms.customcrops.bukkit.requirement;
|
||||
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.action.ActionManager;
|
||||
import net.momirealms.customcrops.api.core.block.CropBlock;
|
||||
import net.momirealms.customcrops.api.core.world.CustomCropsBlockState;
|
||||
import net.momirealms.customcrops.api.requirement.AbstractRequirementManager;
|
||||
|
||||
public class BlockRequirementManager extends AbstractRequirementManager<CustomCropsBlockState> {
|
||||
|
||||
public BlockRequirementManager(BukkitCustomCropsPlugin plugin) {
|
||||
super(plugin, CustomCropsBlockState.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerBuiltInRequirements() {
|
||||
super.registerBuiltInRequirements();
|
||||
this.registerPointCondition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
loadExpansions(CustomCropsBlockState.class);
|
||||
}
|
||||
|
||||
private void registerPointCondition() {
|
||||
registerRequirement((args, actions, runActions) -> {
|
||||
int value = (int) args;
|
||||
return (context) -> {
|
||||
CustomCropsBlockState state = context.holder();
|
||||
if (state.type() instanceof CropBlock cropBlock) {
|
||||
int point = cropBlock.point(state);
|
||||
if (point > value) return true;
|
||||
}
|
||||
if (runActions) ActionManager.trigger(context, actions);
|
||||
return false;
|
||||
};
|
||||
}, "point_more_than", "point-more-than");
|
||||
registerRequirement((args, actions, runActions) -> {
|
||||
int value = (int) args;
|
||||
return (context) -> {
|
||||
CustomCropsBlockState state = context.holder();
|
||||
if (state.type() instanceof CropBlock cropBlock) {
|
||||
int point = cropBlock.point(state);
|
||||
if (point < value) return true;
|
||||
}
|
||||
if (runActions) ActionManager.trigger(context, actions);
|
||||
return false;
|
||||
};
|
||||
}, "point_less_than", "point-less-than");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
package net.momirealms.customcrops.bukkit.requirement;
|
||||
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.action.ActionManager;
|
||||
import net.momirealms.customcrops.api.integration.LevelerProvider;
|
||||
import net.momirealms.customcrops.api.misc.value.MathValue;
|
||||
import net.momirealms.customcrops.api.requirement.AbstractRequirementManager;
|
||||
import net.momirealms.customcrops.api.requirement.Requirement;
|
||||
import net.momirealms.customcrops.bukkit.integration.VaultHook;
|
||||
import net.momirealms.customcrops.common.util.ListUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class PlayerRequirementManager extends AbstractRequirementManager<Player> {
|
||||
|
||||
public PlayerRequirementManager(BukkitCustomCropsPlugin plugin) {
|
||||
super(plugin, Player.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerBuiltInRequirements() {
|
||||
super.registerBuiltInRequirements();
|
||||
this.registerItemInHandRequirement();
|
||||
this.registerPermissionRequirement();
|
||||
this.registerPluginLevelRequirement();
|
||||
this.registerCoolDownRequirement();
|
||||
this.registerLevelRequirement();
|
||||
this.registerMoneyRequirement();
|
||||
this.registerPotionEffectRequirement();
|
||||
this.registerSneakRequirement();
|
||||
this.registerGameModeRequirement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
loadExpansions(Player.class);
|
||||
}
|
||||
|
||||
private void registerItemInHandRequirement() {
|
||||
registerRequirement((args, actions, runActions) -> {
|
||||
if (args instanceof Section section) {
|
||||
boolean mainOrOff = section.getString("hand","main").equalsIgnoreCase("main");
|
||||
int amount = section.getInt("amount", 1);
|
||||
List<String> items = ListUtils.toList(section.get("item"));
|
||||
return context -> {
|
||||
if (context.holder() == null) return true;
|
||||
ItemStack itemStack = mainOrOff ?
|
||||
context.holder().getInventory().getItemInMainHand()
|
||||
: context.holder().getInventory().getItemInOffHand();
|
||||
String id = plugin.getItemManager().id(itemStack);
|
||||
if (items.contains(id) && itemStack.getAmount() >= amount) return true;
|
||||
if (runActions) ActionManager.trigger(context, actions);
|
||||
return false;
|
||||
};
|
||||
} else {
|
||||
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at item-in-hand requirement which is expected be `Section`");
|
||||
return Requirement.empty();
|
||||
}
|
||||
}, "item-in-hand");
|
||||
}
|
||||
|
||||
private void registerPluginLevelRequirement() {
|
||||
registerRequirement((args, actions, runActions) -> {
|
||||
if (args instanceof Section section) {
|
||||
String pluginName = section.getString("plugin");
|
||||
int level = section.getInt("level");
|
||||
String target = section.getString("target");
|
||||
return context -> {
|
||||
if (context.holder() == null) return true;
|
||||
LevelerProvider levelerProvider = plugin.getIntegrationManager().getLevelerProvider(pluginName);
|
||||
if (levelerProvider == null) {
|
||||
plugin.getPluginLogger().warn("Plugin (" + pluginName + "'s) level is not compatible. Please double check if it's a problem caused by pronunciation.");
|
||||
return true;
|
||||
}
|
||||
if (levelerProvider.getLevel(context.holder(), target) >= level)
|
||||
return true;
|
||||
if (runActions) ActionManager.trigger(context, actions);
|
||||
return false;
|
||||
};
|
||||
} else {
|
||||
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at plugin-level requirement which is expected be `Section`");
|
||||
return Requirement.empty();
|
||||
}
|
||||
}, "plugin-level");
|
||||
}
|
||||
|
||||
private void registerLevelRequirement() {
|
||||
registerRequirement((args, actions, runActions) -> {
|
||||
MathValue<Player> value = MathValue.auto(args);
|
||||
return context -> {
|
||||
if (context.holder() == null) return true;
|
||||
int current = context.holder().getLevel();
|
||||
if (current >= value.evaluate(context, true))
|
||||
return true;
|
||||
if (runActions) ActionManager.trigger(context, actions);
|
||||
return false;
|
||||
};
|
||||
}, "level");
|
||||
}
|
||||
|
||||
private void registerMoneyRequirement() {
|
||||
registerRequirement((args, actions, runActions) -> {
|
||||
MathValue<Player> value = MathValue.auto(args);
|
||||
return context -> {
|
||||
if (context.holder() == null) return true;
|
||||
double current = VaultHook.getBalance(context.holder());
|
||||
if (current >= value.evaluate(context, true))
|
||||
return true;
|
||||
if (runActions) ActionManager.trigger(context, actions);
|
||||
return false;
|
||||
};
|
||||
}, "money");
|
||||
}
|
||||
|
||||
private void registerCoolDownRequirement() {
|
||||
registerRequirement((args, actions, runActions) -> {
|
||||
if (args instanceof Section section) {
|
||||
String key = section.getString("key");
|
||||
int time = section.getInt("time");
|
||||
return context -> {
|
||||
if (context.holder() == null) return true;
|
||||
if (!plugin.getCoolDownManager().isCoolDown(context.holder().getUniqueId(), key, time))
|
||||
return true;
|
||||
if (runActions) ActionManager.trigger(context, actions);
|
||||
return false;
|
||||
};
|
||||
} else {
|
||||
plugin.getPluginLogger().warn("Invalid value type: " + args.getClass().getSimpleName() + " found at cooldown requirement which is expected be `Section`");
|
||||
return Requirement.empty();
|
||||
}
|
||||
}, "cooldown");
|
||||
}
|
||||
|
||||
private void registerPermissionRequirement() {
|
||||
registerRequirement((args, actions, runActions) -> {
|
||||
List<String> perms = ListUtils.toList(args);
|
||||
return context -> {
|
||||
if (context.holder() == null) return true;
|
||||
for (String perm : perms)
|
||||
if (context.holder().hasPermission(perm))
|
||||
return true;
|
||||
if (runActions) ActionManager.trigger(context, actions);
|
||||
return false;
|
||||
};
|
||||
}, "permission");
|
||||
registerRequirement((args, actions, runActions) -> {
|
||||
List<String> perms = ListUtils.toList(args);
|
||||
return context -> {
|
||||
if (context.holder() == null) return true;
|
||||
for (String perm : perms)
|
||||
if (context.holder().hasPermission(perm)) {
|
||||
if (runActions) ActionManager.trigger(context, actions);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}, "!permission");
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void registerPotionEffectRequirement() {
|
||||
registerRequirement((args, actions, runActions) -> {
|
||||
String potions = (String) args;
|
||||
String[] split = potions.split("(<=|>=|<|>|==)", 2);
|
||||
PotionEffectType type = PotionEffectType.getByName(split[0]);
|
||||
if (type == null) {
|
||||
plugin.getPluginLogger().warn("Potion effect doesn't exist: " + split[0]);
|
||||
return Requirement.empty();
|
||||
}
|
||||
int required = Integer.parseInt(split[1]);
|
||||
String operator = potions.substring(split[0].length(), potions.length() - split[1].length());
|
||||
return context -> {
|
||||
if (context.holder() == null) return true;
|
||||
int level = -1;
|
||||
PotionEffect potionEffect = context.holder().getPotionEffect(type);
|
||||
if (potionEffect != null) {
|
||||
level = potionEffect.getAmplifier();
|
||||
}
|
||||
boolean result = false;
|
||||
switch (operator) {
|
||||
case ">=" -> {
|
||||
if (level >= required) result = true;
|
||||
}
|
||||
case ">" -> {
|
||||
if (level > required) result = true;
|
||||
}
|
||||
case "==" -> {
|
||||
if (level == required) result = true;
|
||||
}
|
||||
case "!=" -> {
|
||||
if (level != required) result = true;
|
||||
}
|
||||
case "<=" -> {
|
||||
if (level <= required) result = true;
|
||||
}
|
||||
case "<" -> {
|
||||
if (level < required) result = true;
|
||||
}
|
||||
}
|
||||
if (result) {
|
||||
return true;
|
||||
}
|
||||
if (runActions) ActionManager.trigger(context, actions);
|
||||
return false;
|
||||
};
|
||||
}, "potion-effect");
|
||||
}
|
||||
|
||||
private void registerSneakRequirement() {
|
||||
registerRequirement((args, actions, advanced) -> {
|
||||
boolean sneak = (boolean) args;
|
||||
return context -> {
|
||||
if (context.holder() == null) return true;
|
||||
if (sneak) {
|
||||
if (context.holder().isSneaking())
|
||||
return true;
|
||||
} else {
|
||||
if (!context.holder().isSneaking())
|
||||
return true;
|
||||
}
|
||||
if (advanced) ActionManager.trigger(context, actions);
|
||||
return false;
|
||||
};
|
||||
}, "sneak");
|
||||
}
|
||||
|
||||
protected void registerGameModeRequirement() {
|
||||
registerRequirement((args, actions, advanced) -> {
|
||||
List<String> modes = ListUtils.toList(args);
|
||||
return context -> {
|
||||
if (context.holder() == null) return true;
|
||||
var name = context.holder().getGameMode().name().toLowerCase(Locale.ENGLISH);
|
||||
if (modes.contains(name)) {
|
||||
return true;
|
||||
}
|
||||
if (advanced) ActionManager.trigger(context, actions);
|
||||
return false;
|
||||
};
|
||||
}, "gamemode");
|
||||
}
|
||||
}
|
||||
@@ -23,30 +23,31 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.classpath;
|
||||
package net.momirealms.customcrops.bukkit.scheduler;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Path;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.bukkit.scheduler.impl.BukkitExecutor;
|
||||
import net.momirealms.customcrops.bukkit.scheduler.impl.FoliaExecutor;
|
||||
import net.momirealms.customcrops.common.helper.VersionHelper;
|
||||
import net.momirealms.customcrops.common.plugin.scheduler.AbstractJavaScheduler;
|
||||
import net.momirealms.customcrops.common.plugin.scheduler.RegionExecutor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
|
||||
public class ReflectionClassPathAppender implements ClassPathAppender {
|
||||
private final URLClassLoaderAccess classLoaderAccess;
|
||||
public class BukkitSchedulerAdapter extends AbstractJavaScheduler<Location, World> {
|
||||
protected RegionExecutor<Location, World> sync;
|
||||
|
||||
public ReflectionClassPathAppender(ClassLoader classLoader) throws IllegalStateException {
|
||||
if (classLoader instanceof URLClassLoader) {
|
||||
this.classLoaderAccess = URLClassLoaderAccess.create((URLClassLoader) classLoader);
|
||||
public BukkitSchedulerAdapter(BukkitCustomCropsPlugin plugin) {
|
||||
super(plugin);
|
||||
if (VersionHelper.isFolia()) {
|
||||
this.sync = new FoliaExecutor(plugin.getBoostrap());
|
||||
} else {
|
||||
throw new IllegalStateException("ClassLoader is not instance of URLClassLoader");
|
||||
this.sync = new BukkitExecutor(plugin.getBoostrap());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addJarToClasspath(Path file) {
|
||||
try {
|
||||
this.classLoaderAccess.addURL(file.toUri().toURL());
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
public RegionExecutor<Location, World> sync() {
|
||||
return this.sync;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package net.momirealms.customcrops.bukkit.scheduler;
|
||||
|
||||
import net.momirealms.customcrops.common.plugin.scheduler.SchedulerTask;
|
||||
|
||||
public class DummyTask implements SchedulerTask {
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.bukkit.scheduler.impl;
|
||||
|
||||
import net.momirealms.customcrops.bukkit.scheduler.DummyTask;
|
||||
import net.momirealms.customcrops.common.plugin.scheduler.RegionExecutor;
|
||||
import net.momirealms.customcrops.common.plugin.scheduler.SchedulerTask;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
public class BukkitExecutor implements RegionExecutor<Location, World> {
|
||||
|
||||
private final Plugin plugin;
|
||||
|
||||
public BukkitExecutor(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Runnable r, Location l) {
|
||||
if (Bukkit.isPrimaryThread()) {
|
||||
r.run();
|
||||
} else {
|
||||
Bukkit.getScheduler().runTask(plugin, r);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Runnable r, World world, int x, int z) {
|
||||
run(r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask runLater(Runnable r, long delayTicks, Location l) {
|
||||
if (delayTicks == 0) {
|
||||
if (Bukkit.isPrimaryThread()) {
|
||||
r.run();
|
||||
return new DummyTask();
|
||||
} else {
|
||||
return new BukkitCancellable(Bukkit.getScheduler().runTask(plugin, r));
|
||||
}
|
||||
}
|
||||
return new BukkitCancellable(Bukkit.getScheduler().runTaskLater(plugin, r, delayTicks));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask runRepeating(Runnable r, long delayTicks, long period, Location l) {
|
||||
return new BukkitCancellable(Bukkit.getScheduler().runTaskTimer(plugin, r, delayTicks, period));
|
||||
}
|
||||
|
||||
public static class BukkitCancellable implements SchedulerTask {
|
||||
|
||||
private final BukkitTask task;
|
||||
|
||||
public BukkitCancellable(BukkitTask task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.task.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.task.isCancelled();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.bukkit.scheduler.impl;
|
||||
|
||||
import io.papermc.paper.threadedregions.scheduler.ScheduledTask;
|
||||
import net.momirealms.customcrops.common.plugin.scheduler.RegionExecutor;
|
||||
import net.momirealms.customcrops.common.plugin.scheduler.SchedulerTask;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class FoliaExecutor implements RegionExecutor<Location, World> {
|
||||
|
||||
private final Plugin plugin;
|
||||
|
||||
public FoliaExecutor(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Runnable r, Location l) {
|
||||
Optional.ofNullable(l).ifPresentOrElse(loc -> Bukkit.getRegionScheduler().execute(plugin, loc, r), () -> Bukkit.getGlobalRegionScheduler().execute(plugin, r));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(Runnable r, World world, int x, int z) {
|
||||
Bukkit.getRegionScheduler().execute(plugin, world, x, z, r);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask runLater(Runnable r, long delayTicks, Location l) {
|
||||
if (l == null) {
|
||||
if (delayTicks == 0) {
|
||||
return new FoliaCancellable(Bukkit.getGlobalRegionScheduler().runDelayed(plugin, scheduledTask -> r.run(), delayTicks));
|
||||
} else {
|
||||
return new FoliaCancellable(Bukkit.getGlobalRegionScheduler().run(plugin, scheduledTask -> r.run()));
|
||||
}
|
||||
} else {
|
||||
if (delayTicks == 0) {
|
||||
return new FoliaCancellable(Bukkit.getRegionScheduler().run(plugin, l, scheduledTask -> r.run()));
|
||||
} else {
|
||||
return new FoliaCancellable(Bukkit.getRegionScheduler().runDelayed(plugin, l, scheduledTask -> r.run(), delayTicks));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SchedulerTask runRepeating(Runnable r, long delayTicks, long period, Location l) {
|
||||
if (l == null) {
|
||||
return new FoliaCancellable(Bukkit.getGlobalRegionScheduler().runAtFixedRate(plugin, scheduledTask -> r.run(), delayTicks, period));
|
||||
} else {
|
||||
return new FoliaCancellable(Bukkit.getRegionScheduler().runAtFixedRate(plugin, l, scheduledTask -> r.run(), delayTicks, period));
|
||||
}
|
||||
}
|
||||
|
||||
public static class FoliaCancellable implements SchedulerTask {
|
||||
|
||||
private final ScheduledTask task;
|
||||
|
||||
public FoliaCancellable(ScheduledTask task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.task.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.task.isCancelled();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.bukkit.sender;
|
||||
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.common.sender.Sender;
|
||||
import net.momirealms.customcrops.common.sender.SenderFactory;
|
||||
import net.momirealms.customcrops.common.util.Tristate;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.command.RemoteConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BukkitSenderFactory extends SenderFactory<BukkitCustomCropsPlugin, CommandSender> {
|
||||
private final BukkitAudiences audiences;
|
||||
|
||||
public BukkitSenderFactory(BukkitCustomCropsPlugin plugin) {
|
||||
super(plugin);
|
||||
this.audiences = BukkitAudiences.create(plugin.getBoostrap());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getName(CommandSender sender) {
|
||||
if (sender instanceof Player) {
|
||||
return sender.getName();
|
||||
}
|
||||
return Sender.CONSOLE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UUID getUniqueId(CommandSender sender) {
|
||||
if (sender instanceof Player) {
|
||||
return ((Player) sender).getUniqueId();
|
||||
}
|
||||
return Sender.CONSOLE_UUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Audience getAudience(CommandSender sender) {
|
||||
return this.audiences.sender(sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendMessage(CommandSender sender, Component message) {
|
||||
// we can safely send async for players and the console - otherwise, send it sync
|
||||
if (sender instanceof Player || sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender) {
|
||||
getAudience(sender).sendMessage(message);
|
||||
} else {
|
||||
getPlugin().getScheduler().executeSync(() -> getAudience(sender).sendMessage(message));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Tristate getPermissionValue(CommandSender sender, String node) {
|
||||
if (sender.hasPermission(node)) {
|
||||
return Tristate.TRUE;
|
||||
} else if (sender.isPermissionSet(node)) {
|
||||
return Tristate.FALSE;
|
||||
} else {
|
||||
return Tristate.UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasPermission(CommandSender sender, String node) {
|
||||
return sender.hasPermission(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCommand(CommandSender sender, String command) {
|
||||
getPlugin().getBoostrap().getServer().dispatchCommand(sender, command);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isConsole(CommandSender sender) {
|
||||
return sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
super.close();
|
||||
this.audiences.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
package net.momirealms.customcrops.bukkit.world;
|
||||
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import dev.dejvokep.boostedyaml.block.implementation.Section;
|
||||
import net.momirealms.customcrops.api.BukkitCustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.core.ConfigManager;
|
||||
import net.momirealms.customcrops.api.core.world.*;
|
||||
import net.momirealms.customcrops.api.core.world.adaptor.WorldAdaptor;
|
||||
import net.momirealms.customcrops.api.integration.SeasonProvider;
|
||||
import net.momirealms.customcrops.bukkit.config.BukkitConfigManager;
|
||||
import net.momirealms.customcrops.bukkit.integration.adaptor.BukkitWorldAdaptor;
|
||||
import net.momirealms.customcrops.bukkit.integration.adaptor.asp_r1.SlimeWorldAdaptorR1;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class BukkitWorldManager implements WorldManager, Listener {
|
||||
|
||||
private final BukkitCustomCropsPlugin plugin;
|
||||
private final Set<WorldAdaptor<?>> adaptors = new TreeSet<>();
|
||||
private final ConcurrentHashMap<String, CustomCropsWorld<?>> worlds = new ConcurrentHashMap<>();
|
||||
private final HashMap<String, WorldSetting> worldSettings = new HashMap<>();
|
||||
private WorldSetting defaultWorldSetting;
|
||||
private MatchRule matchRule;
|
||||
private HashSet<String> worldList;
|
||||
private SeasonProvider seasonProvider;
|
||||
|
||||
public BukkitWorldManager(BukkitCustomCropsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
try {
|
||||
Class.forName("com.infernalsuite.aswm.api.SlimePlugin");
|
||||
adaptors.add(new SlimeWorldAdaptorR1(1));
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
}
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("SlimeWorldPlugin")) {
|
||||
adaptors.add(new SlimeWorldAdaptorR1(2));
|
||||
}
|
||||
this.adaptors.add(new BukkitWorldAdaptor());
|
||||
this.seasonProvider = new SeasonProvider() {
|
||||
@NotNull
|
||||
@Override
|
||||
public Season getSeason(@NotNull World world) {
|
||||
return BukkitWorldManager.this.getWorld(world).map(w -> w.extraData().getSeason()).orElse(Season.DISABLE);
|
||||
}
|
||||
@Override
|
||||
public String identifier() {
|
||||
return "CustomCrops";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void seasonProvider(SeasonProvider seasonProvider) {
|
||||
this.seasonProvider = seasonProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Season getSeason(World world) {
|
||||
if (ConfigManager.syncSeasons()) {
|
||||
World reference = Bukkit.getWorld(ConfigManager.referenceWorld());
|
||||
if (reference != null) {
|
||||
return seasonProvider.getSeason(reference);
|
||||
} else {
|
||||
return Season.DISABLE;
|
||||
}
|
||||
} else {
|
||||
return seasonProvider.getSeason(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDate(World world) {
|
||||
if (ConfigManager.syncSeasons()) {
|
||||
World reference = Bukkit.getWorld(ConfigManager.referenceWorld());
|
||||
if (reference != null) {
|
||||
return getWorld(reference).map(w -> w.extraData().getDate()).orElse(-1);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return getWorld(world).map(w -> w.extraData().getDate()).orElse(-1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
this.loadConfig();
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin.getBoostrap());
|
||||
// load and unload worlds
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
if (isMechanicEnabled(world)) {
|
||||
loadWorld(world);
|
||||
} else {
|
||||
unloadWorld(world);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadConfig() {
|
||||
YamlDocument config = BukkitConfigManager.getMainConfig();
|
||||
|
||||
Section section = config.getSection("worlds");
|
||||
if (section == null) {
|
||||
plugin.getPluginLogger().warn("worlds section should not be null");
|
||||
return;
|
||||
}
|
||||
|
||||
this.matchRule = MatchRule.valueOf(section.getString("mode", "blacklist").toUpperCase(Locale.ENGLISH));
|
||||
this.worldList = new HashSet<>(section.getStringList("list"));
|
||||
|
||||
Section settingSection = section.getSection("settings");
|
||||
if (settingSection == null) {
|
||||
plugin.getPluginLogger().warn("worlds.settings section should not be null");
|
||||
return;
|
||||
}
|
||||
|
||||
Section defaultSection = settingSection.getSection("_DEFAULT_");
|
||||
if (defaultSection == null) {
|
||||
plugin.getPluginLogger().warn("worlds.settings._DEFAULT_ section should not be null");
|
||||
return;
|
||||
}
|
||||
|
||||
this.defaultWorldSetting = sectionToWorldSetting(defaultSection);
|
||||
|
||||
Section worldSection = settingSection.getSection("_WORLDS_");
|
||||
if (worldSection != null) {
|
||||
for (Map.Entry<String, Object> entry : worldSection.getStringRouteMappedValues(false).entrySet()) {
|
||||
if (entry.getValue() instanceof Section inner) {
|
||||
this.worldSettings.put(entry.getKey(), sectionToWorldSetting(inner));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
HandlerList.unregisterAll(this);
|
||||
this.worldSettings.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
this.unload();
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
unloadWorld(world);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomCropsWorld<?> loadWorld(World world) {
|
||||
Optional<CustomCropsWorld<?>> optionalWorld = getWorld(world);
|
||||
if (optionalWorld.isPresent()) {
|
||||
CustomCropsWorld<?> customCropsWorld = optionalWorld.get();
|
||||
customCropsWorld.setting(Optional.ofNullable(worldSettings.get(world.getName())).orElse(defaultWorldSetting));
|
||||
return customCropsWorld;
|
||||
}
|
||||
CustomCropsWorld<?> adaptedWorld = adapt(world);
|
||||
adaptedWorld.setting(Optional.ofNullable(worldSettings.get(world.getName())).orElse(defaultWorldSetting));
|
||||
adaptedWorld.setTicking(true);
|
||||
this.worlds.put(world.getName(), adaptedWorld);
|
||||
for (Chunk chunk : world.getLoadedChunks()) {
|
||||
loadLoadedChunk(adaptedWorld, ChunkPos.fromBukkitChunk(chunk));
|
||||
}
|
||||
return adaptedWorld;
|
||||
}
|
||||
|
||||
// Before using the method, make sure that the bukkit chunk is loaded
|
||||
public void loadLoadedChunk(CustomCropsWorld<?> world, ChunkPos pos) {
|
||||
if (world.isChunkLoaded(pos)) return;
|
||||
Optional<CustomCropsChunk> customChunk = world.getChunk(pos);
|
||||
// don't load bukkit chunk again since it has been loaded
|
||||
customChunk.ifPresent(customCropsChunk -> customCropsChunk.load(false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unloadWorld(World world) {
|
||||
CustomCropsWorld<?> removedWorld = worlds.remove(world.getName());
|
||||
if (removedWorld == null) {
|
||||
return false;
|
||||
}
|
||||
removedWorld.setTicking(false);
|
||||
removedWorld.save();
|
||||
return true;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onWorldSave(WorldSaveEvent event) {
|
||||
final World world = event.getWorld();
|
||||
getWorld(world).ifPresent(CustomCropsWorld::save);
|
||||
}
|
||||
|
||||
@EventHandler (priority = EventPriority.HIGH)
|
||||
public void onWorldLoad(WorldLoadEvent event) {
|
||||
World world = event.getWorld();
|
||||
if (!isMechanicEnabled(world)) return;
|
||||
loadWorld(world);
|
||||
}
|
||||
|
||||
@EventHandler (priority = EventPriority.LOW)
|
||||
public void onWorldUnload(WorldUnloadEvent event) {
|
||||
World world = event.getWorld();
|
||||
if (!isMechanicEnabled(world)) return;
|
||||
unloadWorld(world);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChunkUnload(ChunkUnloadEvent event) {
|
||||
final Chunk chunk = event.getChunk();
|
||||
final World world = event.getWorld();
|
||||
this.getWorld(world)
|
||||
.flatMap(customWorld -> customWorld.getLoadedChunk(ChunkPos.fromBukkitChunk(chunk)))
|
||||
.ifPresent(customChunk -> customChunk.unload(true));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChunkLoad(ChunkLoadEvent event) {
|
||||
final Chunk chunk = event.getChunk();
|
||||
final World world = event.getWorld();
|
||||
this.getWorld(world).ifPresent(customWorld -> loadLoadedChunk(customWorld, ChunkPos.fromBukkitChunk(chunk)));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEntitiesLoad(EntitiesLoadEvent event) {
|
||||
|
||||
}
|
||||
|
||||
public boolean isMechanicEnabled(World world) {
|
||||
if (matchRule == MatchRule.WHITELIST) {
|
||||
return worldList.contains(world.getName());
|
||||
} else if (matchRule == MatchRule.BLACKLIST) {
|
||||
return !worldList.contains(world.getName());
|
||||
} else {
|
||||
for (String regex : worldList) {
|
||||
if (world.getName().matches(regex)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<CustomCropsWorld<?>> getWorld(World world) {
|
||||
return getWorld(world.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<CustomCropsWorld<?>> getWorld(String world) {
|
||||
return Optional.ofNullable(worlds.get(world));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWorldLoaded(World world) {
|
||||
return worlds.containsKey(world.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<WorldAdaptor<?>> adaptors() {
|
||||
return adaptors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomCropsWorld<?> adapt(World world) {
|
||||
return adapt(world.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomCropsWorld<?> adapt(String name) {
|
||||
for (WorldAdaptor<?> adaptor : adaptors) {
|
||||
Object world = adaptor.getWorld(name);
|
||||
if (world != null) {
|
||||
return adaptor.adapt(world);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Unable to adapt world " + name);
|
||||
}
|
||||
|
||||
public enum MatchRule {
|
||||
|
||||
BLACKLIST,
|
||||
WHITELIST,
|
||||
REGEX
|
||||
}
|
||||
|
||||
private static WorldSetting sectionToWorldSetting(Section section) {
|
||||
return WorldSetting.of(
|
||||
section.getBoolean("enable", true),
|
||||
section.getInt("min-tick-unit", 300),
|
||||
getRandomTickModeByString(section.getString("crop.mode")),
|
||||
section.getInt("crop.tick-interval", 1),
|
||||
getRandomTickModeByString(section.getString("pot.mode")),
|
||||
section.getInt("pot.tick-interval", 2),
|
||||
getRandomTickModeByString(section.getString("sprinkler.mode")),
|
||||
section.getInt("sprinkler.tick-interval", 2),
|
||||
section.getBoolean("offline-tick.enable", false),
|
||||
section.getInt("offline-tick.max-offline-seconds", 1200),
|
||||
section.getBoolean("season.enable", false),
|
||||
section.getBoolean("season.auto-alternation", false),
|
||||
section.getInt("season.duration", 28),
|
||||
section.getInt("crop.max-per-chunk", 128),
|
||||
section.getInt("pot.max-per-chunk", -1),
|
||||
section.getInt("sprinkler.max-per-chunk", 32),
|
||||
section.getInt("random-tick-speed", 0)
|
||||
);
|
||||
}
|
||||
|
||||
private static boolean getRandomTickModeByString(String str) {
|
||||
if (str == null) {
|
||||
return false;
|
||||
}
|
||||
if (str.equalsIgnoreCase("RANDOM_TICK")) {
|
||||
return true;
|
||||
}
|
||||
if (str.equalsIgnoreCase("SCHEDULED_TICK")) {
|
||||
return false;
|
||||
}
|
||||
throw new IllegalArgumentException("Invalid mode found when loading world settings: " + str);
|
||||
}
|
||||
}
|
||||
@@ -1,153 +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.customcrops.compatibility;
|
||||
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.integration.LevelInterface;
|
||||
import net.momirealms.customcrops.api.integration.SeasonInterface;
|
||||
import net.momirealms.customcrops.api.manager.IntegrationManager;
|
||||
import net.momirealms.customcrops.api.util.LogUtils;
|
||||
import net.momirealms.customcrops.compatibility.item.MMOItemsItemImpl;
|
||||
import net.momirealms.customcrops.compatibility.item.MythicMobsItemImpl;
|
||||
import net.momirealms.customcrops.compatibility.item.NeigeItemsItemImpl;
|
||||
import net.momirealms.customcrops.compatibility.item.ZaphkielItemImpl;
|
||||
import net.momirealms.customcrops.compatibility.level.*;
|
||||
import net.momirealms.customcrops.compatibility.quest.BattlePassHook;
|
||||
import net.momirealms.customcrops.compatibility.quest.BetonQuestHook;
|
||||
import net.momirealms.customcrops.compatibility.quest.ClueScrollsHook;
|
||||
import net.momirealms.customcrops.compatibility.season.AdvancedSeasonsImpl;
|
||||
import net.momirealms.customcrops.compatibility.season.InBuiltSeason;
|
||||
import net.momirealms.customcrops.compatibility.season.RealisticSeasonsImpl;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class IntegrationManagerImpl implements IntegrationManager {
|
||||
|
||||
private final CustomCropsPlugin plugin;
|
||||
private final HashMap<String, LevelInterface> levelPluginMap;
|
||||
private SeasonInterface seasonInterface;
|
||||
|
||||
public IntegrationManagerImpl(CustomCropsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.levelPluginMap = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
if (plugin.doesHookedPluginExist("MMOItems")) {
|
||||
plugin.getItemManager().registerItemLibrary(new MMOItemsItemImpl());
|
||||
hookMessage("MMOItems");
|
||||
}
|
||||
if (plugin.doesHookedPluginExist("Zaphkiel")) {
|
||||
plugin.getItemManager().registerItemLibrary(new ZaphkielItemImpl());
|
||||
hookMessage("Zaphkiel");
|
||||
}
|
||||
if (plugin.doesHookedPluginExist("NeigeItems")) {
|
||||
plugin.getItemManager().registerItemLibrary(new NeigeItemsItemImpl());
|
||||
hookMessage("NeigeItems");
|
||||
}
|
||||
if (plugin.doesHookedPluginExist("MythicMobs")) {
|
||||
plugin.getItemManager().registerItemLibrary(new MythicMobsItemImpl());
|
||||
hookMessage("MythicMobs");
|
||||
}
|
||||
if (plugin.doesHookedPluginExist("EcoJobs")) {
|
||||
registerLevelPlugin("EcoJobs", new EcoJobsImpl());
|
||||
hookMessage("EcoJobs");
|
||||
}
|
||||
if (plugin.doesHookedPluginExist("Jobs")) {
|
||||
registerLevelPlugin("JobsReborn", new JobsRebornImpl());
|
||||
hookMessage("JobsReborn");
|
||||
}
|
||||
if (plugin.doesHookedPluginExist("AureliumSkills")) {
|
||||
registerLevelPlugin("AureliumSkills", new AureliumSkillsImpl());
|
||||
hookMessage("AureliumSkills");
|
||||
}
|
||||
if (plugin.doesHookedPluginExist("EcoSkills")) {
|
||||
registerLevelPlugin("EcoSkills", new EcoSkillsImpl());
|
||||
hookMessage("EcoSkills");
|
||||
}
|
||||
if (plugin.doesHookedPluginExist("mcMMO")) {
|
||||
registerLevelPlugin("mcMMO", new McMMOImpl());
|
||||
hookMessage("mcMMO");
|
||||
}
|
||||
if (plugin.doesHookedPluginExist("MMOCore")) {
|
||||
registerLevelPlugin("MMOCore", new MMOCoreImpl());
|
||||
hookMessage("MMOCore");
|
||||
}
|
||||
if (plugin.doesHookedPluginExist("AuraSkills")) {
|
||||
registerLevelPlugin("AuraSkills", new AuraSkillsImpl());
|
||||
hookMessage("AuraSkills");
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("BattlePass")){
|
||||
BattlePassHook battlePassHook = new BattlePassHook();
|
||||
battlePassHook.register();
|
||||
hookMessage("BattlePass");
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("ClueScrolls")) {
|
||||
ClueScrollsHook clueScrollsHook = new ClueScrollsHook();
|
||||
clueScrollsHook.register();
|
||||
hookMessage("ClueScrolls");
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("BetonQuest")) {
|
||||
BetonQuestHook.register();
|
||||
hookMessage("BetonQuest");
|
||||
}
|
||||
if (plugin.isHookedPluginEnabled("RealisticSeasons")) {
|
||||
this.seasonInterface = new RealisticSeasonsImpl();
|
||||
hookMessage("RealisticSeasons");
|
||||
} else if (plugin.isHookedPluginEnabled("AdvancedSeasons", "1.4", "1.5")) {
|
||||
this.seasonInterface = new AdvancedSeasonsImpl();
|
||||
hookMessage("AdvancedSeasons");
|
||||
} else {
|
||||
this.seasonInterface = new InBuiltSeason(plugin.getWorldManager());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerLevelPlugin(String plugin, LevelInterface level) {
|
||||
if (levelPluginMap.containsKey(plugin)) return false;
|
||||
levelPluginMap.put(plugin, level);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregisterLevelPlugin(String plugin) {
|
||||
return levelPluginMap.remove(plugin) != null;
|
||||
}
|
||||
|
||||
private void hookMessage(String plugin) {
|
||||
LogUtils.info( plugin + " hooked!");
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public LevelInterface getLevelPlugin(String plugin) {
|
||||
return levelPluginMap.get(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeasonInterface getSeasonInterface() {
|
||||
return seasonInterface;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +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.customcrops.compatibility;
|
||||
|
||||
import net.milkbowl.vault.economy.Economy;
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
|
||||
public class VaultHook {
|
||||
|
||||
private static Economy economy;
|
||||
|
||||
public static boolean initialize() {
|
||||
RegisteredServiceProvider<Economy> rsp = CustomCropsPlugin.getInstance().getServer().getServicesManager().getRegistration(Economy.class);
|
||||
if (rsp == null) {
|
||||
return false;
|
||||
}
|
||||
economy = rsp.getProvider();
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Economy getEconomy() {
|
||||
return economy;
|
||||
}
|
||||
}
|
||||
@@ -1,51 +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.customcrops.compatibility.item;
|
||||
|
||||
import io.lumine.mythic.lib.api.item.NBTItem;
|
||||
import net.Indyuce.mmoitems.MMOItems;
|
||||
import net.Indyuce.mmoitems.api.Type;
|
||||
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
|
||||
import net.momirealms.customcrops.api.integration.ItemLibrary;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class MMOItemsItemImpl implements ItemLibrary {
|
||||
|
||||
@Override
|
||||
public String identification() {
|
||||
return "MMOItems";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack buildItem(Player player, String id) {
|
||||
String[] split = id.split(":");
|
||||
MMOItem mmoItem = MMOItems.plugin.getMMOItem(Type.get(split[0]), split[1].toUpperCase(Locale.ENGLISH));
|
||||
return mmoItem == null ? new ItemStack(Material.AIR) : mmoItem.newBuilder().build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemID(ItemStack itemStack) {
|
||||
NBTItem nbtItem = NBTItem.get(itemStack);
|
||||
if (!nbtItem.hasTag("MMOITEMS_ITEM_ID")) return null;
|
||||
return nbtItem.getString("MMOITEMS_ITEM_TYPE") + ":" + nbtItem.getString("MMOITEMS_ITEM_ID");
|
||||
}
|
||||
}
|
||||
@@ -1,50 +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.customcrops.compatibility.item;
|
||||
|
||||
import io.lumine.mythic.bukkit.MythicBukkit;
|
||||
import net.momirealms.customcrops.api.integration.ItemLibrary;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class MythicMobsItemImpl implements ItemLibrary {
|
||||
|
||||
private MythicBukkit mythicBukkit;
|
||||
|
||||
public MythicMobsItemImpl() {
|
||||
this.mythicBukkit = MythicBukkit.inst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String identification() {
|
||||
return "MythicMobs";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack buildItem(Player player, String id) {
|
||||
if (mythicBukkit == null || mythicBukkit.isClosed()) {
|
||||
this.mythicBukkit = MythicBukkit.inst();
|
||||
}
|
||||
return mythicBukkit.getItemManager().getItemStack(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemID(ItemStack itemStack) {
|
||||
return mythicBukkit.getItemManager().getMythicTypeFromItem(itemStack);
|
||||
}
|
||||
}
|
||||
@@ -1,47 +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.customcrops.compatibility.item;
|
||||
|
||||
import net.momirealms.customcrops.api.integration.ItemLibrary;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import pers.neige.neigeitems.item.ItemInfo;
|
||||
import pers.neige.neigeitems.manager.ItemManager;
|
||||
import pers.neige.neigeitems.utils.ItemUtils;
|
||||
|
||||
public class NeigeItemsItemImpl implements ItemLibrary {
|
||||
|
||||
@Override
|
||||
public String identification() {
|
||||
return "NeigeItems";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack buildItem(Player player, String id) {
|
||||
return ItemManager.INSTANCE.getItemStack(id, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemID(ItemStack itemStack) {
|
||||
ItemInfo itemInfo = ItemUtils.isNiItem(itemStack);
|
||||
if (itemInfo != null) {
|
||||
return itemInfo.getId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,50 +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.customcrops.compatibility.item;
|
||||
|
||||
import ink.ptms.zaphkiel.ZapAPI;
|
||||
import ink.ptms.zaphkiel.Zaphkiel;
|
||||
import net.momirealms.customcrops.api.integration.ItemLibrary;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class ZaphkielItemImpl implements ItemLibrary {
|
||||
|
||||
private final ZapAPI zapAPI;
|
||||
|
||||
public ZaphkielItemImpl() {
|
||||
this.zapAPI = Zaphkiel.INSTANCE.api();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String identification() {
|
||||
return "Zaphkiel";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack buildItem(Player player, String id) {
|
||||
return zapAPI.getItemManager().generateItemStack(id, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemID(ItemStack itemStack) {
|
||||
if (itemStack == null || itemStack.getType() == Material.AIR) return null;
|
||||
return zapAPI.getItemHandler().getItemId(itemStack);
|
||||
}
|
||||
}
|
||||
@@ -1,40 +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.customcrops.compatibility.level;
|
||||
|
||||
import dev.aurelium.auraskills.api.AuraSkillsApi;
|
||||
import dev.aurelium.auraskills.api.registry.NamespacedId;
|
||||
import net.momirealms.customcrops.api.integration.LevelInterface;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class AuraSkillsImpl implements LevelInterface {
|
||||
|
||||
@Override
|
||||
public void addXp(Player player, String target, double amount) {
|
||||
AuraSkillsApi.get().getUser(player.getUniqueId())
|
||||
.addSkillXp(AuraSkillsApi.get().getGlobalRegistry().getSkill(NamespacedId.fromDefault(target)), amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLevel(Player player, String target) {
|
||||
return AuraSkillsApi.get().getUser(player.getUniqueId()).getSkillLevel(
|
||||
AuraSkillsApi.get().getGlobalRegistry().getSkill(NamespacedId.fromDefault(target))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +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.customcrops.compatibility.level;
|
||||
|
||||
import com.archyx.aureliumskills.api.AureliumAPI;
|
||||
import net.momirealms.customcrops.api.integration.LevelInterface;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class AureliumSkillsImpl implements LevelInterface {
|
||||
|
||||
@Override
|
||||
public void addXp(Player player, String target, double amount) {
|
||||
AureliumAPI.getPlugin().getLeveler().addXp(player, AureliumAPI.getPlugin().getSkillRegistry().getSkill(target), amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLevel(Player player, String target) {
|
||||
return AureliumAPI.getSkillLevel(player, AureliumAPI.getPlugin().getSkillRegistry().getSkill(target));
|
||||
}
|
||||
}
|
||||
@@ -1,43 +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.customcrops.compatibility.level;
|
||||
|
||||
import com.willfp.ecojobs.api.EcoJobsAPI;
|
||||
import com.willfp.ecojobs.jobs.Job;
|
||||
import com.willfp.ecojobs.jobs.Jobs;
|
||||
import net.momirealms.customcrops.api.integration.LevelInterface;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class EcoJobsImpl implements LevelInterface {
|
||||
|
||||
@Override
|
||||
public void addXp(Player player, String target, double amount) {
|
||||
for (Job job : EcoJobsAPI.getActiveJobs(player)) {
|
||||
if (job.getId().equals(target)) {
|
||||
EcoJobsAPI.giveJobExperience(player, job, amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLevel(Player player, String target) {
|
||||
Job job = Jobs.getByID(target);
|
||||
if (job == null) return 0;
|
||||
return EcoJobsAPI.getJobLevel(player, job);
|
||||
}
|
||||
}
|
||||
@@ -1,38 +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.customcrops.compatibility.level;
|
||||
|
||||
import com.willfp.ecoskills.api.EcoSkillsAPI;
|
||||
import com.willfp.ecoskills.skills.Skills;
|
||||
import net.momirealms.customcrops.api.integration.LevelInterface;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class EcoSkillsImpl implements LevelInterface {
|
||||
|
||||
@Override
|
||||
public void addXp(Player player, String target, double amount) {
|
||||
EcoSkillsAPI.gainSkillXP(player, Objects.requireNonNull(Skills.INSTANCE.getByID(target)), amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLevel(Player player, String target) {
|
||||
return EcoSkillsAPI.getSkillLevel(player, Objects.requireNonNull(Skills.INSTANCE.getByID(target)));
|
||||
}
|
||||
}
|
||||
@@ -1,55 +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.customcrops.compatibility.level;
|
||||
|
||||
import com.gamingmesh.jobs.Jobs;
|
||||
import com.gamingmesh.jobs.container.Job;
|
||||
import com.gamingmesh.jobs.container.JobProgression;
|
||||
import com.gamingmesh.jobs.container.JobsPlayer;
|
||||
import net.momirealms.customcrops.api.integration.LevelInterface;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class JobsRebornImpl implements LevelInterface {
|
||||
|
||||
@Override
|
||||
public void addXp(Player player, String target, double amount) {
|
||||
JobsPlayer jobsPlayer = Jobs.getPlayerManager().getJobsPlayer(player);
|
||||
if (jobsPlayer != null) {
|
||||
List<JobProgression> jobs = jobsPlayer.getJobProgression();
|
||||
Job job = Jobs.getJob(target);
|
||||
for (JobProgression progression : jobs)
|
||||
if (progression.getJob().equals(job))
|
||||
progression.addExperience(amount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLevel(Player player, String target) {
|
||||
JobsPlayer jobsPlayer = Jobs.getPlayerManager().getJobsPlayer(player);
|
||||
if (jobsPlayer != null) {
|
||||
List<JobProgression> jobs = jobsPlayer.getJobProgression();
|
||||
Job job = Jobs.getJob(target);
|
||||
for (JobProgression progression : jobs)
|
||||
if (progression.getJob().equals(job))
|
||||
return progression.getLevel();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,37 +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.customcrops.compatibility.level;
|
||||
|
||||
import net.Indyuce.mmocore.MMOCore;
|
||||
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||
import net.Indyuce.mmocore.experience.EXPSource;
|
||||
import net.momirealms.customcrops.api.integration.LevelInterface;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class MMOCoreImpl implements LevelInterface {
|
||||
|
||||
@Override
|
||||
public void addXp(Player player, String target, double amount) {
|
||||
MMOCore.plugin.professionManager.get(target).giveExperience(PlayerData.get(player), amount, null ,EXPSource.OTHER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLevel(Player player, String target) {
|
||||
return PlayerData.get(player).getCollectionSkills().getLevel(MMOCore.plugin.professionManager.get(target));
|
||||
}
|
||||
}
|
||||
@@ -1,36 +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.customcrops.compatibility.level;
|
||||
|
||||
import com.gmail.nossr50.api.ExperienceAPI;
|
||||
import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
|
||||
import net.momirealms.customcrops.api.integration.LevelInterface;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class McMMOImpl implements LevelInterface {
|
||||
|
||||
@Override
|
||||
public void addXp(Player player, String target, double amount) {
|
||||
ExperienceAPI.addRawXP(player, target, (float) amount, "UNKNOWN");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLevel(Player player, String target) {
|
||||
return ExperienceAPI.getLevel(player, PrimarySkillType.valueOf(target));
|
||||
}
|
||||
}
|
||||
@@ -1,103 +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.customcrops.compatibility.papi;
|
||||
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.manager.MessageManager;
|
||||
import net.momirealms.customcrops.api.util.LogUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class CCPapi extends PlaceholderExpansion {
|
||||
|
||||
private final CustomCropsPlugin plugin;
|
||||
|
||||
public CCPapi(CustomCropsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void load() {
|
||||
super.register();
|
||||
}
|
||||
|
||||
public void unload() {
|
||||
super.unregister();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getIdentifier() {
|
||||
return "customcrops";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getAuthor() {
|
||||
return "XiaoMoMi";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getVersion() {
|
||||
return "3.4";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean persist() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String onRequest(OfflinePlayer offlinePlayer, @NotNull String params) {
|
||||
String[] split = params.split("_", 2);
|
||||
|
||||
Player player = offlinePlayer.getPlayer();
|
||||
if (player == null)
|
||||
return null;
|
||||
|
||||
switch (split[0]) {
|
||||
case "season" -> {
|
||||
if (split.length == 1) {
|
||||
return MessageManager.seasonTranslation(plugin.getIntegrationManager().getSeasonInterface().getSeason(player.getWorld()));
|
||||
} else {
|
||||
try {
|
||||
return MessageManager.seasonTranslation(plugin.getIntegrationManager().getSeasonInterface().getSeason(Bukkit.getWorld(split[1])));
|
||||
} catch (NullPointerException e) {
|
||||
LogUtils.severe("World " + split[1] + " does not exist");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
case "date" -> {
|
||||
if (split.length == 1) {
|
||||
return String.valueOf(plugin.getIntegrationManager().getSeasonInterface().getDate(player.getWorld()));
|
||||
} else {
|
||||
try {
|
||||
return String.valueOf(plugin.getIntegrationManager().getSeasonInterface().getDate(Bukkit.getWorld(split[1])));
|
||||
} catch (NullPointerException e) {
|
||||
LogUtils.severe("World " + split[1] + " does not exist");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +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.customcrops.compatibility.papi;
|
||||
|
||||
import me.clip.placeholderapi.PlaceholderAPI;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class ParseUtils {
|
||||
|
||||
public static String setPlaceholders(Player player, String text) {
|
||||
return PlaceholderAPI.setPlaceholders(player, text);
|
||||
}
|
||||
|
||||
public static String setPlaceholders(OfflinePlayer player, String text) {
|
||||
return PlaceholderAPI.setPlaceholders(player, text);
|
||||
}
|
||||
}
|
||||
@@ -1,91 +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.customcrops.compatibility.quest;
|
||||
|
||||
import io.github.battlepass.BattlePlugin;
|
||||
import io.github.battlepass.api.events.server.PluginReloadEvent;
|
||||
import net.advancedplugins.bp.impl.actions.ActionRegistry;
|
||||
import net.advancedplugins.bp.impl.actions.external.executor.ActionQuestExecutor;
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.event.CropBreakEvent;
|
||||
import net.momirealms.customcrops.api.event.CropPlantEvent;
|
||||
import net.momirealms.customcrops.api.mechanic.item.Crop;
|
||||
import net.momirealms.customcrops.api.mechanic.world.level.WorldCrop;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class BattlePassHook implements Listener {
|
||||
|
||||
public BattlePassHook() {
|
||||
Bukkit.getPluginManager().registerEvents(this, CustomCropsPlugin.get());
|
||||
}
|
||||
|
||||
public void register() {
|
||||
ActionRegistry actionRegistry = BattlePlugin.getPlugin().getActionRegistry();
|
||||
actionRegistry.hook("customcrops", BPHarvestCropsQuest::new);
|
||||
}
|
||||
|
||||
@EventHandler(ignoreCancelled = true)
|
||||
public void onBattlePassReload(PluginReloadEvent event){
|
||||
register();
|
||||
}
|
||||
|
||||
private static class BPHarvestCropsQuest extends ActionQuestExecutor {
|
||||
public BPHarvestCropsQuest(JavaPlugin plugin) {
|
||||
super(plugin, "customcrops");
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onBreakCrop(CropBreakEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
if (player == null) return;
|
||||
|
||||
WorldCrop worldCrop = event.getWorldCrop();
|
||||
if (worldCrop == null) return;
|
||||
String id = worldCrop.getConfig().getStageItemByPoint(worldCrop.getPoint());
|
||||
|
||||
if (id.contains(":")) {
|
||||
id = id.split(":")[1];
|
||||
}
|
||||
|
||||
// Harvest crops
|
||||
this.executionBuilder("harvest")
|
||||
.player(player)
|
||||
.root(id)
|
||||
.progress(1)
|
||||
.buildAndExecute();
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onPlantCrop(CropPlantEvent event){
|
||||
Player player = event.getPlayer();
|
||||
|
||||
Crop crop = event.getCrop();
|
||||
|
||||
// Harvest crops
|
||||
this.executionBuilder("plant")
|
||||
.player(player)
|
||||
.root(crop.getKey())
|
||||
.progress(1)
|
||||
.buildAndExecute();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,199 +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.customcrops.compatibility.quest;
|
||||
|
||||
import net.momirealms.customcrops.api.event.CropBreakEvent;
|
||||
import net.momirealms.customcrops.api.event.CropPlantEvent;
|
||||
import net.momirealms.customcrops.api.mechanic.world.level.WorldCrop;
|
||||
import net.momirealms.customcrops.api.util.LogUtils;
|
||||
import org.betonquest.betonquest.BetonQuest;
|
||||
import org.betonquest.betonquest.Instruction;
|
||||
import org.betonquest.betonquest.api.CountingObjective;
|
||||
import org.betonquest.betonquest.api.config.quest.QuestPackage;
|
||||
import org.betonquest.betonquest.api.profiles.OnlineProfile;
|
||||
import org.betonquest.betonquest.api.profiles.Profile;
|
||||
import org.betonquest.betonquest.exceptions.InstructionParseException;
|
||||
import org.betonquest.betonquest.exceptions.QuestRuntimeException;
|
||||
import org.betonquest.betonquest.instruction.variable.VariableNumber;
|
||||
import org.betonquest.betonquest.instruction.variable.location.VariableLocation;
|
||||
import org.betonquest.betonquest.utils.PlayerConverter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
public class BetonQuestHook {
|
||||
|
||||
public static void register() {
|
||||
BetonQuest.getInstance().registerObjectives("customcrops_harvest", HarvestObjective.class);
|
||||
BetonQuest.getInstance().registerObjectives("customcrops_plant", PlantObjective.class);
|
||||
}
|
||||
|
||||
public static class HarvestObjective extends CountingObjective implements Listener {
|
||||
|
||||
private final VariableLocation playerLocation;
|
||||
private final VariableNumber rangeVar;
|
||||
private final HashSet<String> crop_ids;
|
||||
|
||||
public HarvestObjective(Instruction instruction) throws InstructionParseException {
|
||||
super(instruction, "crop_to_harvest");
|
||||
crop_ids = new HashSet<>();
|
||||
Collections.addAll(crop_ids, instruction.getArray());
|
||||
targetAmount = instruction.getVarNum(VariableNumber.NOT_LESS_THAN_ONE_CHECKER);
|
||||
final QuestPackage pack = instruction.getPackage();
|
||||
final String loc = instruction.getOptional("playerLocation");
|
||||
final String range = instruction.getOptional("range");
|
||||
if (loc != null && range != null) {
|
||||
playerLocation = new VariableLocation(BetonQuest.getInstance().getVariableProcessor(), pack, loc);
|
||||
rangeVar = new VariableNumber(BetonQuest.getInstance().getVariableProcessor(), pack, range);
|
||||
} else {
|
||||
playerLocation = null;
|
||||
rangeVar = null;
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onBreakCrop(CropBreakEvent event) {
|
||||
if (event.getPlayer() == null) {
|
||||
return;
|
||||
}
|
||||
WorldCrop crop = event.getWorldCrop();
|
||||
if (crop == null) return;
|
||||
|
||||
OnlineProfile onlineProfile = PlayerConverter.getID(event.getPlayer());
|
||||
if (!containsPlayer(onlineProfile)) {
|
||||
return;
|
||||
}
|
||||
if (isInvalidLocation(event, onlineProfile)) {
|
||||
return;
|
||||
}
|
||||
if (this.crop_ids.contains(crop.getConfig().getStageItemByPoint(crop.getPoint())) && this.checkConditions(onlineProfile)) {
|
||||
getCountingData(onlineProfile).progress(1);
|
||||
completeIfDoneOrNotify(onlineProfile);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInvalidLocation(CropBreakEvent event, final Profile profile) {
|
||||
if (playerLocation == null || rangeVar == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Location targetLocation;
|
||||
try {
|
||||
targetLocation = playerLocation.getValue(profile);
|
||||
} catch (final org.betonquest.betonquest.exceptions.QuestRuntimeException e) {
|
||||
LogUtils.warn(e.getMessage());
|
||||
return true;
|
||||
}
|
||||
int range;
|
||||
try {
|
||||
range = rangeVar.getValue(profile).intValue();
|
||||
} catch (QuestRuntimeException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
final Location playerLoc = event.getPlayer().getLocation();
|
||||
return !playerLoc.getWorld().equals(targetLocation.getWorld()) || targetLocation.distanceSquared(playerLoc) > range * range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
Bukkit.getPluginManager().registerEvents(this, BetonQuest.getInstance());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
HandlerList.unregisterAll(this);
|
||||
}
|
||||
}
|
||||
|
||||
public static class PlantObjective extends CountingObjective implements Listener {
|
||||
|
||||
private final VariableLocation playerLocation;
|
||||
private final VariableNumber rangeVar;
|
||||
private final HashSet<String> crops;
|
||||
|
||||
public PlantObjective(Instruction instruction) throws InstructionParseException {
|
||||
super(instruction, "crop_to_plant");
|
||||
crops = new HashSet<>();
|
||||
Collections.addAll(crops, instruction.getArray());
|
||||
targetAmount = instruction.getVarNum(VariableNumber.NOT_LESS_THAN_ONE_CHECKER);
|
||||
final QuestPackage pack = instruction.getPackage();
|
||||
final String loc = instruction.getOptional("playerLocation");
|
||||
final String range = instruction.getOptional("range");
|
||||
if (loc != null && range != null) {
|
||||
playerLocation = new VariableLocation(BetonQuest.getInstance().getVariableProcessor(), pack, loc);
|
||||
rangeVar = new VariableNumber(BetonQuest.getInstance().getVariableProcessor(), pack, range);
|
||||
} else {
|
||||
playerLocation = null;
|
||||
rangeVar = null;
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onPlantCrop(CropPlantEvent event) {
|
||||
OnlineProfile onlineProfile = PlayerConverter.getID(event.getPlayer());
|
||||
if (!containsPlayer(onlineProfile)) {
|
||||
return;
|
||||
}
|
||||
if (isInvalidLocation(event, onlineProfile)) {
|
||||
return;
|
||||
}
|
||||
if (this.crops.contains(event.getCrop().getKey()) && this.checkConditions(onlineProfile)) {
|
||||
getCountingData(onlineProfile).progress(1);
|
||||
completeIfDoneOrNotify(onlineProfile);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInvalidLocation(CropPlantEvent event, final Profile profile) {
|
||||
if (playerLocation == null || rangeVar == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final Location targetLocation;
|
||||
try {
|
||||
targetLocation = playerLocation.getValue(profile);
|
||||
} catch (final org.betonquest.betonquest.exceptions.QuestRuntimeException e) {
|
||||
LogUtils.warn(e.getMessage());
|
||||
return true;
|
||||
}
|
||||
int range;
|
||||
try {
|
||||
range = rangeVar.getValue(profile).intValue();
|
||||
} catch (QuestRuntimeException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
final Location playerLoc = event.getPlayer().getLocation();
|
||||
return !playerLoc.getWorld().equals(targetLocation.getWorld()) || targetLocation.distanceSquared(playerLoc) > range * range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
Bukkit.getPluginManager().registerEvents(this, BetonQuest.getInstance());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
HandlerList.unregisterAll(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,67 +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.customcrops.compatibility.quest;
|
||||
|
||||
import com.electro2560.dev.cluescrolls.api.*;
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.event.CropBreakEvent;
|
||||
import net.momirealms.customcrops.api.event.CropPlantEvent;
|
||||
import net.momirealms.customcrops.api.mechanic.world.level.WorldCrop;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
public class ClueScrollsHook implements Listener {
|
||||
|
||||
private final CustomClue harvestClue;
|
||||
private final CustomClue plantClue;
|
||||
|
||||
public ClueScrollsHook() {
|
||||
harvestClue = ClueScrollsAPI.getInstance().registerCustomClue(CustomCropsPlugin.getInstance(), "harvest", new ClueConfigData("id", DataType.STRING));
|
||||
plantClue = ClueScrollsAPI.getInstance().registerCustomClue(CustomCropsPlugin.getInstance(), "plant", new ClueConfigData("id", DataType.STRING));
|
||||
}
|
||||
|
||||
public void register() {
|
||||
Bukkit.getPluginManager().registerEvents(this, CustomCropsPlugin.get());
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onBreakCrop(CropBreakEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
if (player == null) return;
|
||||
|
||||
WorldCrop crop = event.getWorldCrop();
|
||||
if (crop == null) return;
|
||||
|
||||
harvestClue.handle(
|
||||
player,
|
||||
1,
|
||||
new ClueDataPair("id", crop.getConfig().getStageItemByPoint(crop.getPoint()))
|
||||
);
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onPlantCrop(CropPlantEvent event) {
|
||||
plantClue.handle(
|
||||
event.getPlayer(),
|
||||
1,
|
||||
new ClueDataPair("id", event.getCrop().getKey())
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,62 +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.customcrops.compatibility.season;
|
||||
|
||||
import net.advancedplugins.seasons.Core;
|
||||
import net.momirealms.customcrops.api.integration.SeasonInterface;
|
||||
import net.momirealms.customcrops.api.mechanic.world.season.Season;
|
||||
import org.bukkit.World;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AdvancedSeasonsImpl implements SeasonInterface {
|
||||
|
||||
@Override
|
||||
public Season getSeason(@NotNull World world) {
|
||||
net.advancedplugins.seasons.enums.Season season = Core.getSeasonHandler().getSeason(world);
|
||||
if (season == null) {
|
||||
return null;
|
||||
}
|
||||
return switch (season.getType()) {
|
||||
case SPRING -> Season.SPRING;
|
||||
case WINTER -> Season.WINTER;
|
||||
case SUMMER -> Season.SUMMER;
|
||||
case FALL -> Season.AUTUMN;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDate(World world) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSeason(World world, Season season) {
|
||||
String seasonName = switch (season) {
|
||||
case AUTUMN -> "FALL";
|
||||
case WINTER -> "WINTER";
|
||||
case SUMMER -> "SUMMER";
|
||||
case SPRING -> "SPRING";
|
||||
};
|
||||
Core.getSeasonHandler().setSeason(net.advancedplugins.seasons.enums.Season.valueOf(seasonName), world.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDate(World world, int date) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,74 +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.customcrops.compatibility.season;
|
||||
|
||||
import net.momirealms.customcrops.api.integration.SeasonInterface;
|
||||
import net.momirealms.customcrops.api.manager.ConfigManager;
|
||||
import net.momirealms.customcrops.api.manager.WorldManager;
|
||||
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld;
|
||||
import net.momirealms.customcrops.api.mechanic.world.level.WorldInfoData;
|
||||
import net.momirealms.customcrops.api.mechanic.world.season.Season;
|
||||
import org.bukkit.World;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class InBuiltSeason implements SeasonInterface {
|
||||
|
||||
private final WorldManager worldManager;
|
||||
|
||||
public InBuiltSeason(WorldManager worldManager) {
|
||||
this.worldManager = worldManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Season getSeason(World world) {
|
||||
return worldManager
|
||||
.getCustomCropsWorld(world)
|
||||
.map(CustomCropsWorld::getSeason)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDate(World world) {
|
||||
if (ConfigManager.syncSeasons())
|
||||
world = ConfigManager.referenceWorld();
|
||||
if (world == null)
|
||||
return 0;
|
||||
return worldManager
|
||||
.getCustomCropsWorld(world)
|
||||
.map(CustomCropsWorld::getDate)
|
||||
.orElse(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSeason(World world, Season season) {
|
||||
worldManager.getCustomCropsWorld(world)
|
||||
.ifPresent(customWorld -> {
|
||||
WorldInfoData infoData = customWorld.getInfoData();
|
||||
infoData.setSeason(season);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDate(World world, int date) {
|
||||
worldManager.getCustomCropsWorld(world)
|
||||
.ifPresent(customWorld -> {
|
||||
WorldInfoData infoData = customWorld.getInfoData();
|
||||
infoData.setDate(date);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,67 +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.customcrops.compatibility.season;
|
||||
|
||||
import me.casperge.realisticseasons.api.SeasonsAPI;
|
||||
import me.casperge.realisticseasons.calendar.Date;
|
||||
import net.momirealms.customcrops.api.integration.SeasonInterface;
|
||||
import net.momirealms.customcrops.api.mechanic.world.season.Season;
|
||||
import org.bukkit.World;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class RealisticSeasonsImpl implements SeasonInterface {
|
||||
|
||||
private final SeasonsAPI api;
|
||||
|
||||
public RealisticSeasonsImpl() {
|
||||
this.api = SeasonsAPI.getInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Season getSeason(World world) {
|
||||
return switch (api.getSeason(world)) {
|
||||
case WINTER -> Season.WINTER;
|
||||
case SPRING -> Season.SPRING;
|
||||
case SUMMER -> Season.SUMMER;
|
||||
case FALL -> Season.AUTUMN;
|
||||
case DISABLED, RESTORE -> null;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDate(World world) {
|
||||
return api.getDate(world).getDay();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSeason(World world, Season season) {
|
||||
me.casperge.realisticseasons.season.Season rsSeason = switch (season) {
|
||||
case AUTUMN -> me.casperge.realisticseasons.season.Season.FALL;
|
||||
case SUMMER -> me.casperge.realisticseasons.season.Season.SUMMER;
|
||||
case WINTER -> me.casperge.realisticseasons.season.Season.WINTER;
|
||||
case SPRING -> me.casperge.realisticseasons.season.Season.SPRING;
|
||||
};
|
||||
api.setSeason(world, rsSeason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDate(World world, int date) {
|
||||
Date rsDate = api.getDate(world);
|
||||
api.setDate(world, new Date(date, rsDate.getMonth(), rsDate.getYear()));
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.classpath;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Interface which allows access to add URLs to the plugin classpath at runtime.
|
||||
*/
|
||||
public interface ClassPathAppender extends AutoCloseable {
|
||||
|
||||
void addJarToClasspath(Path file);
|
||||
|
||||
@Override
|
||||
default void close() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.classpath;
|
||||
|
||||
import net.momirealms.customcrops.libraries.loader.JarInJarClassLoader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class JarInJarClassPathAppender implements ClassPathAppender {
|
||||
private final JarInJarClassLoader classLoader;
|
||||
|
||||
public JarInJarClassPathAppender(ClassLoader classLoader) {
|
||||
if (!(classLoader instanceof JarInJarClassLoader)) {
|
||||
throw new IllegalArgumentException("Loader is not a JarInJarClassLoader: " + classLoader.getClass().getName());
|
||||
}
|
||||
this.classLoader = (JarInJarClassLoader) classLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addJarToClasspath(Path file) {
|
||||
try {
|
||||
this.classLoader.addJarToClasspath(file.toUri().toURL());
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
this.classLoader.deleteJarResource();
|
||||
try {
|
||||
this.classLoader.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,190 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.classpath;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Provides access to {@link URLClassLoader}#addURL.
|
||||
*/
|
||||
public abstract class URLClassLoaderAccess {
|
||||
|
||||
/**
|
||||
* Creates a {@link URLClassLoaderAccess} for the given class loader.
|
||||
*
|
||||
* @param classLoader the class loader
|
||||
* @return the access object
|
||||
*/
|
||||
public static URLClassLoaderAccess create(URLClassLoader classLoader) {
|
||||
if (Reflection.isSupported()) {
|
||||
return new Reflection(classLoader);
|
||||
} else if (Unsafe.isSupported()) {
|
||||
return new Unsafe(classLoader);
|
||||
} else {
|
||||
return Noop.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
private final URLClassLoader classLoader;
|
||||
|
||||
protected URLClassLoaderAccess(URLClassLoader classLoader) {
|
||||
this.classLoader = classLoader;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the given URL to the class loader.
|
||||
*
|
||||
* @param url the URL to add
|
||||
*/
|
||||
public abstract void addURL(@NonNull URL url);
|
||||
|
||||
private static void throwError(Throwable cause) throws UnsupportedOperationException {
|
||||
throw new UnsupportedOperationException("CustomCrops is unable to inject into the plugin URLClassLoader.\n" +
|
||||
"You may be able to fix this problem by adding the following command-line argument " +
|
||||
"directly after the 'java' command in your start script: \n'--add-opens java.base/java.lang=ALL-UNNAMED'", cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Accesses using reflection, not supported on Java 9+.
|
||||
*/
|
||||
private static class Reflection extends URLClassLoaderAccess {
|
||||
private static final Method ADD_URL_METHOD;
|
||||
|
||||
static {
|
||||
Method addUrlMethod;
|
||||
try {
|
||||
addUrlMethod = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||
addUrlMethod.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
addUrlMethod = null;
|
||||
}
|
||||
ADD_URL_METHOD = addUrlMethod;
|
||||
}
|
||||
|
||||
private static boolean isSupported() {
|
||||
return ADD_URL_METHOD != null;
|
||||
}
|
||||
|
||||
Reflection(URLClassLoader classLoader) {
|
||||
super(classLoader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addURL(@NonNull URL url) {
|
||||
try {
|
||||
ADD_URL_METHOD.invoke(super.classLoader, url);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
URLClassLoaderAccess.throwError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Accesses using sun.misc.Unsafe, supported on Java 9+.
|
||||
*
|
||||
* @author Vaishnav Anil (https://github.com/slimjar/slimjar)
|
||||
*/
|
||||
private static class Unsafe extends URLClassLoaderAccess {
|
||||
private static final sun.misc.Unsafe UNSAFE;
|
||||
|
||||
static {
|
||||
sun.misc.Unsafe unsafe;
|
||||
try {
|
||||
Field unsafeField = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
unsafe = (sun.misc.Unsafe) unsafeField.get(null);
|
||||
} catch (Throwable t) {
|
||||
unsafe = null;
|
||||
}
|
||||
UNSAFE = unsafe;
|
||||
}
|
||||
|
||||
private static boolean isSupported() {
|
||||
return UNSAFE != null;
|
||||
}
|
||||
|
||||
private final Collection<URL> unopenedURLs;
|
||||
private final Collection<URL> pathURLs;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Unsafe(URLClassLoader classLoader) {
|
||||
super(classLoader);
|
||||
|
||||
Collection<URL> unopenedURLs;
|
||||
Collection<URL> pathURLs;
|
||||
try {
|
||||
Object ucp = fetchField(URLClassLoader.class, classLoader, "ucp");
|
||||
unopenedURLs = (Collection<URL>) fetchField(ucp.getClass(), ucp, "unopenedUrls");
|
||||
pathURLs = (Collection<URL>) fetchField(ucp.getClass(), ucp, "path");
|
||||
} catch (Throwable e) {
|
||||
unopenedURLs = null;
|
||||
pathURLs = null;
|
||||
}
|
||||
|
||||
this.unopenedURLs = unopenedURLs;
|
||||
this.pathURLs = pathURLs;
|
||||
}
|
||||
|
||||
private static Object fetchField(final Class<?> clazz, final Object object, final String name) throws NoSuchFieldException {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
long offset = UNSAFE.objectFieldOffset(field);
|
||||
return UNSAFE.getObject(object, offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addURL(@NonNull URL url) {
|
||||
if (this.unopenedURLs == null || this.pathURLs == null) {
|
||||
URLClassLoaderAccess.throwError(new NullPointerException("unopenedURLs or pathURLs"));
|
||||
}
|
||||
|
||||
synchronized (this.unopenedURLs) {
|
||||
this.unopenedURLs.add(url);
|
||||
this.pathURLs.add(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class Noop extends URLClassLoaderAccess {
|
||||
private static final Noop INSTANCE = new Noop();
|
||||
|
||||
private Noop() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addURL(@NonNull URL url) {
|
||||
URLClassLoaderAccess.throwError(null);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.dependencies;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.momirealms.customcrops.libraries.dependencies.relocation.Relocation;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* The dependencies used by CustomCrops.
|
||||
*/
|
||||
public enum Dependency {
|
||||
|
||||
ASM(
|
||||
"org.ow2.asm",
|
||||
"asm",
|
||||
"9.7",
|
||||
null,
|
||||
"asm"
|
||||
),
|
||||
ASM_COMMONS(
|
||||
"org.ow2.asm",
|
||||
"asm-commons",
|
||||
"9.7",
|
||||
null,
|
||||
"asm-commons"
|
||||
),
|
||||
JAR_RELOCATOR(
|
||||
"me.lucko",
|
||||
"jar-relocator",
|
||||
"1.7",
|
||||
null,
|
||||
"jar-relocator"
|
||||
),
|
||||
COMMAND_API(
|
||||
"dev{}jorel",
|
||||
"commandapi-bukkit-shade",
|
||||
"9.5.3",
|
||||
null,
|
||||
"commandapi-bukkit",
|
||||
Relocation.of("commandapi", "dev{}jorel{}commandapi")
|
||||
),
|
||||
COMMAND_API_MOJMAP(
|
||||
"dev{}jorel",
|
||||
"commandapi-bukkit-shade-mojang-mapped",
|
||||
"9.5.3",
|
||||
null,
|
||||
"commandapi-bukkit-mojang-mapped",
|
||||
Relocation.of("commandapi", "dev{}jorel{}commandapi")
|
||||
),
|
||||
BOOSTED_YAML(
|
||||
"dev{}dejvokep",
|
||||
"boosted-yaml",
|
||||
"1.3.6",
|
||||
null,
|
||||
"boosted-yaml",
|
||||
Relocation.of("boostedyaml", "dev{}dejvokep{}boostedyaml")
|
||||
),
|
||||
H2_DRIVER(
|
||||
"com.h2database",
|
||||
"h2",
|
||||
"2.2.224",
|
||||
null,
|
||||
"h2database"
|
||||
),
|
||||
SQLITE_DRIVER(
|
||||
"org.xerial",
|
||||
"sqlite-jdbc",
|
||||
"3.45.1.0",
|
||||
null,
|
||||
"sqlite-jdbc"
|
||||
),
|
||||
SLF4J_SIMPLE(
|
||||
"org.slf4j",
|
||||
"slf4j-simple",
|
||||
"2.0.12",
|
||||
null,
|
||||
"slf4j-simple"
|
||||
),
|
||||
SLF4J_API(
|
||||
"org.slf4j",
|
||||
"slf4j-api",
|
||||
"2.0.12",
|
||||
null,
|
||||
"slf4j-api"
|
||||
),
|
||||
BSTATS_BASE(
|
||||
"org{}bstats",
|
||||
"bstats-base",
|
||||
"3.0.2",
|
||||
null,
|
||||
"bstats-base",
|
||||
Relocation.of("bstats", "org{}bstats")
|
||||
),
|
||||
BSTATS_BUKKIT(
|
||||
"org{}bstats",
|
||||
"bstats-bukkit",
|
||||
"3.0.2",
|
||||
null,
|
||||
"bstats-bukkit",
|
||||
Relocation.of("bstats", "org{}bstats")
|
||||
),
|
||||
GSON(
|
||||
"com.google.code.gson",
|
||||
"gson",
|
||||
"2.10.1",
|
||||
null,
|
||||
"gson"
|
||||
),
|
||||
EXP4J(
|
||||
"net{}objecthunter",
|
||||
"exp4j",
|
||||
"0.4.8",
|
||||
null,
|
||||
"exp4j",
|
||||
Relocation.of("exp4j", "net{}objecthunter{}exp4j")
|
||||
);
|
||||
|
||||
private final String mavenRepoPath;
|
||||
private final String version;
|
||||
private final List<Relocation> relocations;
|
||||
private final String repo;
|
||||
private final String artifact;
|
||||
|
||||
private static final String MAVEN_FORMAT = "%s/%s/%s/%s-%s.jar";
|
||||
|
||||
Dependency(String groupId, String artifactId, String version, String repo, String artifact) {
|
||||
this(groupId, artifactId, version, repo, artifact, new Relocation[0]);
|
||||
}
|
||||
|
||||
Dependency(String groupId, String artifactId, String version, String repo, String artifact, Relocation... relocations) {
|
||||
this.mavenRepoPath = String.format(MAVEN_FORMAT,
|
||||
rewriteEscaping(groupId).replace(".", "/"),
|
||||
rewriteEscaping(artifactId),
|
||||
version,
|
||||
rewriteEscaping(artifactId),
|
||||
version
|
||||
);
|
||||
this.version = version;
|
||||
this.relocations = ImmutableList.copyOf(relocations);
|
||||
this.repo = repo;
|
||||
this.artifact = artifact;
|
||||
}
|
||||
|
||||
private static String rewriteEscaping(String s) {
|
||||
return s.replace("{}", ".");
|
||||
}
|
||||
|
||||
public String getFileName(String classifier) {
|
||||
String name = artifact.toLowerCase(Locale.ROOT).replace('_', '-');
|
||||
String extra = classifier == null || classifier.isEmpty()
|
||||
? ""
|
||||
: "-" + classifier;
|
||||
return name + "-" + this.version + extra + ".jar";
|
||||
}
|
||||
|
||||
String getMavenRepoPath() {
|
||||
return this.mavenRepoPath;
|
||||
}
|
||||
|
||||
public List<Relocation> getRelocations() {
|
||||
return this.relocations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link MessageDigest} suitable for computing the checksums
|
||||
* of dependencies.
|
||||
*
|
||||
* @return the digest
|
||||
*/
|
||||
public static MessageDigest createDigest() {
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA-256");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getRepo() {
|
||||
return repo;
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.dependencies;
|
||||
|
||||
/**
|
||||
* Exception thrown if a dependency cannot be downloaded.
|
||||
*/
|
||||
public class DependencyDownloadException extends Exception {
|
||||
|
||||
public DependencyDownloadException() {
|
||||
|
||||
}
|
||||
|
||||
public DependencyDownloadException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public DependencyDownloadException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public DependencyDownloadException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.dependencies;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Loads and manages runtime dependencies for the plugin.
|
||||
*/
|
||||
public interface DependencyManager extends AutoCloseable {
|
||||
|
||||
/**
|
||||
* Loads dependencies.
|
||||
*
|
||||
* @param dependencies the dependencies to load
|
||||
*/
|
||||
void loadDependencies(Collection<Dependency> dependencies);
|
||||
|
||||
/**
|
||||
* Obtains an isolated classloader containing the given dependencies.
|
||||
*
|
||||
* @param dependencies the dependencies
|
||||
* @return the classloader
|
||||
*/
|
||||
ClassLoader obtainClassLoaderWith(Set<Dependency> dependencies);
|
||||
|
||||
@Override
|
||||
void close();
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.dependencies;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import net.momirealms.customcrops.CustomCropsPluginImpl;
|
||||
import net.momirealms.customcrops.api.util.LogUtils;
|
||||
import net.momirealms.customcrops.libraries.classpath.ClassPathAppender;
|
||||
import net.momirealms.customcrops.libraries.dependencies.classloader.IsolatedClassLoader;
|
||||
import net.momirealms.customcrops.libraries.dependencies.relocation.Relocation;
|
||||
import net.momirealms.customcrops.libraries.dependencies.relocation.RelocationHandler;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
/**
|
||||
* Loads and manages runtime dependencies for the plugin.
|
||||
*/
|
||||
public class DependencyManagerImpl implements DependencyManager {
|
||||
|
||||
/** A registry containing plugin specific behaviour for dependencies. */
|
||||
private final DependencyRegistry registry;
|
||||
/** The path where library jars are cached. */
|
||||
private final Path cacheDirectory;
|
||||
/** The classpath appender to preload dependencies into */
|
||||
private final ClassPathAppender classPathAppender;
|
||||
/** A map of dependencies which have already been loaded. */
|
||||
private final EnumMap<Dependency, Path> loaded = new EnumMap<>(Dependency.class);
|
||||
/** A map of isolated classloaders which have been created. */
|
||||
private final Map<ImmutableSet<Dependency>, IsolatedClassLoader> loaders = new HashMap<>();
|
||||
/** Cached relocation handler instance. */
|
||||
private @MonotonicNonNull RelocationHandler relocationHandler = null;
|
||||
|
||||
public DependencyManagerImpl(CustomCropsPluginImpl plugin, ClassPathAppender classPathAppender) {
|
||||
this.registry = new DependencyRegistry();
|
||||
this.cacheDirectory = setupCacheDirectory(plugin);
|
||||
this.classPathAppender = classPathAppender;
|
||||
this.relocationHandler = new RelocationHandler(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClassLoader obtainClassLoaderWith(Set<Dependency> dependencies) {
|
||||
ImmutableSet<Dependency> set = ImmutableSet.copyOf(dependencies);
|
||||
|
||||
for (Dependency dependency : dependencies) {
|
||||
if (!this.loaded.containsKey(dependency)) {
|
||||
throw new IllegalStateException("Dependency " + dependency + " is not loaded.");
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (this.loaders) {
|
||||
IsolatedClassLoader classLoader = this.loaders.get(set);
|
||||
if (classLoader != null) {
|
||||
return classLoader;
|
||||
}
|
||||
|
||||
URL[] urls = set.stream()
|
||||
.map(this.loaded::get)
|
||||
.map(file -> {
|
||||
try {
|
||||
return file.toUri().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
})
|
||||
.toArray(URL[]::new);
|
||||
|
||||
classLoader = new IsolatedClassLoader(urls);
|
||||
this.loaders.put(set, classLoader);
|
||||
return classLoader;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadDependencies(Collection<Dependency> dependencies) {
|
||||
CountDownLatch latch = new CountDownLatch(dependencies.size());
|
||||
|
||||
for (Dependency dependency : dependencies) {
|
||||
if (this.loaded.containsKey(dependency)) {
|
||||
latch.countDown();
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
loadDependency(dependency);
|
||||
} catch (Throwable e) {
|
||||
new RuntimeException("Unable to load dependency " + dependency.name(), e).printStackTrace();
|
||||
} finally {
|
||||
latch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
private void loadDependency(Dependency dependency) throws Exception {
|
||||
if (this.loaded.containsKey(dependency)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Path file = remapDependency(dependency, downloadDependency(dependency));
|
||||
|
||||
this.loaded.put(dependency, file);
|
||||
|
||||
if (this.classPathAppender != null && this.registry.shouldAutoLoad(dependency)) {
|
||||
this.classPathAppender.addJarToClasspath(file);
|
||||
}
|
||||
}
|
||||
|
||||
private Path downloadDependency(Dependency dependency) throws DependencyDownloadException {
|
||||
Path file = this.cacheDirectory.resolve(dependency.getFileName(null));
|
||||
|
||||
// if the file already exists, don't attempt to re-download it.
|
||||
if (Files.exists(file)) {
|
||||
return file;
|
||||
}
|
||||
|
||||
DependencyDownloadException lastError = null;
|
||||
String fileName = dependency.getFileName(null);
|
||||
String forceRepo = dependency.getRepo();
|
||||
if (forceRepo == null) {
|
||||
// attempt to download the dependency from each repo in order.
|
||||
for (DependencyRepository repo : DependencyRepository.values()) {
|
||||
try {
|
||||
LogUtils.info("Downloading dependency(" + fileName + ") from " + repo.getUrl() + dependency.getMavenRepoPath());
|
||||
repo.download(dependency, file);
|
||||
LogUtils.info("Successfully downloaded " + fileName);
|
||||
return file;
|
||||
} catch (DependencyDownloadException e) {
|
||||
lastError = e;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DependencyRepository repository = DependencyRepository.getByID(forceRepo);
|
||||
if (repository != null) {
|
||||
try {
|
||||
LogUtils.info("Downloading dependency(" + fileName + ") from " + repository.getUrl() + dependency.getMavenRepoPath());
|
||||
repository.download(dependency, file);
|
||||
LogUtils.info("Successfully downloaded " + fileName);
|
||||
return file;
|
||||
} catch (DependencyDownloadException e) {
|
||||
lastError = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw Objects.requireNonNull(lastError);
|
||||
}
|
||||
|
||||
private Path remapDependency(Dependency dependency, Path normalFile) throws Exception {
|
||||
List<Relocation> rules = new ArrayList<>(dependency.getRelocations());
|
||||
if (rules.isEmpty()) {
|
||||
return normalFile;
|
||||
}
|
||||
|
||||
Path remappedFile = this.cacheDirectory.resolve(dependency.getFileName(DependencyRegistry.isGsonRelocated() ? "remapped-legacy" : "remapped"));
|
||||
|
||||
// if the remapped source exists already, just use that.
|
||||
if (Files.exists(remappedFile)) {
|
||||
return remappedFile;
|
||||
}
|
||||
|
||||
LogUtils.info("Remapping " + dependency.getFileName(null));
|
||||
relocationHandler.remap(normalFile, remappedFile, rules);
|
||||
LogUtils.info("Successfully remapped " + dependency.getFileName(null));
|
||||
return remappedFile;
|
||||
}
|
||||
|
||||
private static Path setupCacheDirectory(CustomCropsPluginImpl plugin) {
|
||||
File folder = new File(plugin.getDataFolder(), "libs");
|
||||
folder.mkdirs();
|
||||
return folder.toPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
IOException firstEx = null;
|
||||
|
||||
for (IsolatedClassLoader loader : this.loaders.values()) {
|
||||
try {
|
||||
loader.close();
|
||||
} catch (IOException ex) {
|
||||
if (firstEx == null) {
|
||||
firstEx = ex;
|
||||
} else {
|
||||
firstEx.addSuppressed(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (firstEx != null) {
|
||||
firstEx.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.dependencies;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
/**
|
||||
* Applies CustomCrops specific behaviour for {@link Dependency}s.
|
||||
*/
|
||||
public class DependencyRegistry {
|
||||
|
||||
public boolean shouldAutoLoad(Dependency dependency) {
|
||||
return switch (dependency) {
|
||||
// all used within 'isolated' classloaders, and are therefore not
|
||||
// relocated.
|
||||
case ASM, ASM_COMMONS, JAR_RELOCATOR, H2_DRIVER, SQLITE_DRIVER -> false;
|
||||
default -> true;
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public static boolean isGsonRelocated() {
|
||||
return JsonElement.class.getName().startsWith("net.momirealms");
|
||||
}
|
||||
|
||||
private static boolean classExists(String className) {
|
||||
try {
|
||||
Class.forName(className);
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean slf4jPresent() {
|
||||
return classExists("org.slf4j.Logger") && classExists("org.slf4j.LoggerFactory");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.dependencies;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Represents a repository which contains {@link Dependency}s.
|
||||
*/
|
||||
public enum DependencyRepository {
|
||||
|
||||
/**
|
||||
* Maven Central
|
||||
*/
|
||||
MAVEN_CENTRAL("maven", "https://repo1.maven.org/maven2/") {
|
||||
@Override
|
||||
protected URLConnection openConnection(Dependency dependency) throws IOException {
|
||||
URLConnection connection = super.openConnection(dependency);
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setReadTimeout(5000);
|
||||
return connection;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Maven Central Mirror
|
||||
*/
|
||||
MAVEN_CENTRAL_MIRROR("aliyun", "https://maven.aliyun.com/repository/public/"),
|
||||
/**
|
||||
* Code MC
|
||||
*/
|
||||
CODE_MC("codemc", "https://repo.codemc.io/repository/maven-public/"),
|
||||
/**
|
||||
* Jitpack
|
||||
*/
|
||||
JITPACK("jitpack", "https://jitpack.io/");
|
||||
|
||||
private final String url;
|
||||
private final String id;
|
||||
|
||||
DependencyRepository(String id, String url) {
|
||||
this.url = url;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public static DependencyRepository getByID(String id) {
|
||||
for (DependencyRepository repository : values()) {
|
||||
if (id.equals(repository.id)) {
|
||||
return repository;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a connection to the given {@code dependency}.
|
||||
*
|
||||
* @param dependency the dependency to download
|
||||
* @return the connection
|
||||
* @throws IOException if unable to open a connection
|
||||
*/
|
||||
protected URLConnection openConnection(Dependency dependency) throws IOException {
|
||||
URL dependencyUrl = new URL(this.url + dependency.getMavenRepoPath());
|
||||
return dependencyUrl.openConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the raw bytes of the {@code dependency}.
|
||||
*
|
||||
* @param dependency the dependency to download
|
||||
* @return the downloaded bytes
|
||||
* @throws DependencyDownloadException if unable to download
|
||||
*/
|
||||
public byte[] downloadRaw(Dependency dependency) throws DependencyDownloadException {
|
||||
try {
|
||||
URLConnection connection = openConnection(dependency);
|
||||
try (InputStream in = connection.getInputStream()) {
|
||||
byte[] bytes = ByteStreams.toByteArray(in);
|
||||
if (bytes.length == 0) {
|
||||
throw new DependencyDownloadException("Empty stream");
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new DependencyDownloadException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param dependency the dependency to download
|
||||
* @return the downloaded bytes
|
||||
* @throws DependencyDownloadException if unable to download
|
||||
*/
|
||||
public byte[] download(Dependency dependency) throws DependencyDownloadException {
|
||||
return downloadRaw(dependency);
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads the the {@code dependency} to the {@code file}, ensuring the
|
||||
* downloaded bytes match the checksum.
|
||||
*
|
||||
* @param dependency the dependency to download
|
||||
* @param file the file to write to
|
||||
* @throws DependencyDownloadException if unable to download
|
||||
*/
|
||||
public void download(Dependency dependency, Path file) throws DependencyDownloadException {
|
||||
try {
|
||||
Files.write(file, download(dependency));
|
||||
} catch (IOException e) {
|
||||
throw new DependencyDownloadException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.dependencies.classloader;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
/**
|
||||
* A classloader "isolated" from the rest of the Minecraft server.
|
||||
*
|
||||
* <p>Used to load specific CustomCrops dependencies without causing conflicts
|
||||
* with other plugins, or libraries provided by the server implementation.</p>
|
||||
*/
|
||||
public class IsolatedClassLoader extends URLClassLoader {
|
||||
static {
|
||||
ClassLoader.registerAsParallelCapable();
|
||||
}
|
||||
|
||||
public IsolatedClassLoader(URL[] urls) {
|
||||
/*
|
||||
* ClassLoader#getSystemClassLoader returns the AppClassLoader
|
||||
*
|
||||
* Calling #getParent on this returns the ExtClassLoader (Java 8) or
|
||||
* the PlatformClassLoader (Java 9). Since we want this classloader to
|
||||
* be isolated from the Minecraft server (the app), we set the parent
|
||||
* to be the platform class loader.
|
||||
*/
|
||||
super(urls, ClassLoader.getSystemClassLoader().getParent());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.dependencies.relocation;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public final class Relocation {
|
||||
private static final String RELOCATION_PREFIX = "net.momirealms.customcrops.libraries.";
|
||||
|
||||
public static Relocation of(String id, String pattern) {
|
||||
return new Relocation(pattern.replace("{}", "."), RELOCATION_PREFIX + id);
|
||||
}
|
||||
|
||||
private final String pattern;
|
||||
private final String relocatedPattern;
|
||||
|
||||
private Relocation(String pattern, String relocatedPattern) {
|
||||
this.pattern = pattern;
|
||||
this.relocatedPattern = relocatedPattern;
|
||||
}
|
||||
|
||||
public String getPattern() {
|
||||
return this.pattern;
|
||||
}
|
||||
|
||||
public String getRelocatedPattern() {
|
||||
return this.relocatedPattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Relocation that = (Relocation) o;
|
||||
return Objects.equals(this.pattern, that.pattern) &&
|
||||
Objects.equals(this.relocatedPattern, that.relocatedPattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.pattern, this.relocatedPattern);
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.dependencies.relocation;
|
||||
|
||||
import net.momirealms.customcrops.libraries.dependencies.Dependency;
|
||||
import net.momirealms.customcrops.libraries.dependencies.DependencyManager;
|
||||
import net.momirealms.customcrops.libraries.dependencies.classloader.IsolatedClassLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Handles class runtime relocation of packages in downloaded dependencies
|
||||
*/
|
||||
public class RelocationHandler {
|
||||
public static final Set<Dependency> DEPENDENCIES = EnumSet.of(Dependency.ASM, Dependency.ASM_COMMONS, Dependency.JAR_RELOCATOR);
|
||||
private static final String JAR_RELOCATOR_CLASS = "me.lucko.jarrelocator.JarRelocator";
|
||||
private static final String JAR_RELOCATOR_RUN_METHOD = "run";
|
||||
|
||||
private final Constructor<?> jarRelocatorConstructor;
|
||||
private final Method jarRelocatorRunMethod;
|
||||
|
||||
public RelocationHandler(DependencyManager dependencyManager) {
|
||||
ClassLoader classLoader = null;
|
||||
try {
|
||||
// download the required dependencies for remapping
|
||||
dependencyManager.loadDependencies(DEPENDENCIES);
|
||||
// get a classloader containing the required dependencies as sources
|
||||
classLoader = dependencyManager.obtainClassLoaderWith(DEPENDENCIES);
|
||||
|
||||
// load the relocator class
|
||||
Class<?> jarRelocatorClass = classLoader.loadClass(JAR_RELOCATOR_CLASS);
|
||||
|
||||
// prepare the the reflected constructor & method instances
|
||||
this.jarRelocatorConstructor = jarRelocatorClass.getDeclaredConstructor(File.class, File.class, Map.class);
|
||||
this.jarRelocatorConstructor.setAccessible(true);
|
||||
|
||||
this.jarRelocatorRunMethod = jarRelocatorClass.getDeclaredMethod(JAR_RELOCATOR_RUN_METHOD);
|
||||
this.jarRelocatorRunMethod.setAccessible(true);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
if (classLoader instanceof IsolatedClassLoader) {
|
||||
((IsolatedClassLoader) classLoader).close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
e.addSuppressed(ex);
|
||||
}
|
||||
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void remap(Path input, Path output, List<Relocation> relocations) throws Exception {
|
||||
Map<String, String> mappings = new HashMap<>();
|
||||
for (Relocation relocation : relocations) {
|
||||
mappings.put(relocation.getPattern(), relocation.getRelocatedPattern());
|
||||
}
|
||||
|
||||
// create and invoke a new relocator
|
||||
Object relocator = this.jarRelocatorConstructor.newInstance(input.toFile(), output.toFile(), mappings);
|
||||
this.jarRelocatorRunMethod.invoke(relocator);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.dependencies.relocation;
|
||||
|
||||
public final class RelocationHelper {
|
||||
|
||||
// screw maven shade
|
||||
public static final String OKIO_STRING = String.valueOf(new char[]{'o', 'k', 'i', 'o'});
|
||||
public static final String OKHTTP3_STRING = String.valueOf(new char[]{'o', 'k', 'h', 't', 't', 'p', '3'});
|
||||
|
||||
private RelocationHelper() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.loader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
/**
|
||||
* Classloader that can load a jar from within another jar file.
|
||||
*
|
||||
* <p>The "loader" jar contains the loading code & public API classes,
|
||||
* and is class-loaded by the platform.</p>
|
||||
*
|
||||
* <p>The inner "plugin" jar contains the plugin itself, and is class-loaded
|
||||
* by the loading code & this classloader.</p>
|
||||
*/
|
||||
public class JarInJarClassLoader extends URLClassLoader {
|
||||
static {
|
||||
ClassLoader.registerAsParallelCapable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new jar-in-jar class loader.
|
||||
*
|
||||
* @param loaderClassLoader the loader plugin's classloader (setup and created by the platform)
|
||||
* @param jarResourcePath the path to the jar-in-jar resource within the loader jar
|
||||
* @throws LoadingException if something unexpectedly bad happens
|
||||
*/
|
||||
public JarInJarClassLoader(ClassLoader loaderClassLoader, String jarResourcePath) throws LoadingException {
|
||||
super(new URL[]{extractJar(loaderClassLoader, jarResourcePath)}, loaderClassLoader);
|
||||
}
|
||||
|
||||
public void addJarToClasspath(URL url) {
|
||||
addURL(url);
|
||||
}
|
||||
|
||||
public void deleteJarResource() {
|
||||
URL[] urls = getURLs();
|
||||
if (urls.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Path path = Paths.get(urls[0].toURI());
|
||||
Files.deleteIfExists(path);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new plugin instance.
|
||||
*
|
||||
* @param bootstrapClass the name of the bootstrap plugin class
|
||||
* @param loaderPluginType the type of the loader plugin, the only parameter of the bootstrap
|
||||
* plugin constructor
|
||||
* @param loaderPlugin the loader plugin instance
|
||||
* @param <T> the type of the loader plugin
|
||||
* @return the instantiated bootstrap plugin
|
||||
*/
|
||||
public <T> LoaderBootstrap instantiatePlugin(String bootstrapClass, Class<T> loaderPluginType, T loaderPlugin) throws LoadingException {
|
||||
Class<? extends LoaderBootstrap> plugin;
|
||||
try {
|
||||
plugin = loadClass(bootstrapClass).asSubclass(LoaderBootstrap.class);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new LoadingException("Unable to load bootstrap class", e);
|
||||
}
|
||||
|
||||
Constructor<? extends LoaderBootstrap> constructor;
|
||||
try {
|
||||
constructor = plugin.getConstructor(loaderPluginType);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new LoadingException("Unable to get bootstrap constructor", e);
|
||||
}
|
||||
|
||||
try {
|
||||
return constructor.newInstance(loaderPlugin);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new LoadingException("Unable to create bootstrap plugin instance", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the "jar-in-jar" from the loader plugin into a temporary file,
|
||||
* then returns a URL that can be used by the {@link JarInJarClassLoader}.
|
||||
*
|
||||
* @param loaderClassLoader the classloader for the "host" loader plugin
|
||||
* @param jarResourcePath the inner jar resource path
|
||||
* @return a URL to the extracted file
|
||||
*/
|
||||
private static URL extractJar(ClassLoader loaderClassLoader, String jarResourcePath) throws LoadingException {
|
||||
// get the jar-in-jar resource
|
||||
URL jarInJar = loaderClassLoader.getResource(jarResourcePath);
|
||||
if (jarInJar == null) {
|
||||
throw new LoadingException("Could not locate jar-in-jar");
|
||||
}
|
||||
|
||||
// create a temporary file
|
||||
// on posix systems by default this is only read/writable by the process owner
|
||||
Path path;
|
||||
try {
|
||||
path = Files.createTempFile("customcrops-jarinjar", ".jar.tmp");
|
||||
} catch (IOException e) {
|
||||
throw new LoadingException("Unable to create a temporary file", e);
|
||||
}
|
||||
|
||||
// mark that the file should be deleted on exit
|
||||
path.toFile().deleteOnExit();
|
||||
|
||||
// copy the jar-in-jar to the temporary file path
|
||||
try (InputStream in = jarInJar.openStream()) {
|
||||
Files.copy(in, path, StandardCopyOption.REPLACE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
throw new LoadingException("Unable to copy jar-in-jar to temporary path", e);
|
||||
}
|
||||
|
||||
try {
|
||||
return path.toUri().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new LoadingException("Unable to get URL from path", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.loader;
|
||||
|
||||
/**
|
||||
* Minimal bootstrap plugin, called by the loader plugin.
|
||||
*/
|
||||
public interface LoaderBootstrap {
|
||||
|
||||
void onLoad();
|
||||
|
||||
default void onEnable() {}
|
||||
|
||||
default void onDisable() {}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.momirealms.customcrops.libraries.loader;
|
||||
|
||||
/**
|
||||
* Runtime exception used if there is a problem during loading
|
||||
*/
|
||||
public class LoadingException extends RuntimeException {
|
||||
|
||||
public LoadingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public LoadingException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,214 +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.customcrops.manager;
|
||||
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||
import net.kyori.adventure.sound.Sound;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.title.Title;
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.manager.AdventureManager;
|
||||
import net.momirealms.customcrops.api.manager.ConfigManager;
|
||||
import net.momirealms.customcrops.api.manager.MessageManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
public class AdventureManagerImpl extends AdventureManager {
|
||||
|
||||
private final CustomCropsPlugin plugin;
|
||||
private BukkitAudiences audiences;
|
||||
|
||||
public AdventureManagerImpl(CustomCropsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
this.audiences = BukkitAudiences.create(plugin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
if (this.audiences != null)
|
||||
this.audiences.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMessage(CommandSender sender, String text) {
|
||||
if (text == null) return;
|
||||
if (sender instanceof Player player) sendPlayerMessage(player, text);
|
||||
else if (sender instanceof ConsoleCommandSender) sendConsoleMessage(text);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void sendMessageWithPrefix(CommandSender sender, String text) {
|
||||
if (text == null) return;
|
||||
if (sender instanceof Player player) sendPlayerMessage(player, MessageManager.prefix() + text);
|
||||
else if (sender instanceof ConsoleCommandSender) sendConsoleMessage(MessageManager.prefix() + text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendConsoleMessage(String text) {
|
||||
if (text == null) return;
|
||||
Audience au = audiences.sender(Bukkit.getConsoleSender());
|
||||
au.sendMessage(getComponentFromMiniMessage(text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendPlayerMessage(Player player, String text) {
|
||||
if (player == null) return;
|
||||
Audience au = audiences.player(player);
|
||||
au.sendMessage(getComponentFromMiniMessage(text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendActionbar(Player player, String text) {
|
||||
if (player == null) return;
|
||||
Audience au = audiences.player(player);
|
||||
au.sendActionBar(getComponentFromMiniMessage(text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSound(Player player, Sound.Source source, Key key, float pitch, float volume) {
|
||||
if (player == null) return;
|
||||
sendSound(player, Sound.sound(key, source, volume, pitch));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSound(Player player, Sound sound) {
|
||||
if (player == null) return;
|
||||
Audience au = audiences.player(player);
|
||||
au.playSound(sound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendTitle(Player player, String title, String subTitle, int fadeIn, int stay, int fadeOut) {
|
||||
if (player == null) return;
|
||||
Audience au = audiences.player(player);
|
||||
au.showTitle(Title.title(getComponentFromMiniMessage(title), getComponentFromMiniMessage(subTitle), Title.Times.times(
|
||||
Duration.ofMillis(fadeIn * 50L),
|
||||
Duration.ofMillis(stay * 50L),
|
||||
Duration.ofMillis(fadeOut * 50L)
|
||||
)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getComponentFromMiniMessage(String text) {
|
||||
if (text == null) {
|
||||
return Component.empty();
|
||||
}
|
||||
if (ConfigManager.legacyColorSupport()) {
|
||||
return MiniMessage.miniMessage().deserialize(legacyToMiniMessage(text));
|
||||
} else {
|
||||
return MiniMessage.miniMessage().deserialize(text);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String legacyToMiniMessage(String legacy) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
char[] chars = legacy.toCharArray();
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
if (!isColorCode(chars[i])) {
|
||||
stringBuilder.append(chars[i]);
|
||||
continue;
|
||||
}
|
||||
if (i + 1 >= chars.length) {
|
||||
stringBuilder.append(chars[i]);
|
||||
continue;
|
||||
}
|
||||
switch (chars[i+1]) {
|
||||
case '0' -> stringBuilder.append("<black>");
|
||||
case '1' -> stringBuilder.append("<dark_blue>");
|
||||
case '2' -> stringBuilder.append("<dark_green>");
|
||||
case '3' -> stringBuilder.append("<dark_aqua>");
|
||||
case '4' -> stringBuilder.append("<dark_red>");
|
||||
case '5' -> stringBuilder.append("<dark_purple>");
|
||||
case '6' -> stringBuilder.append("<gold>");
|
||||
case '7' -> stringBuilder.append("<gray>");
|
||||
case '8' -> stringBuilder.append("<dark_gray>");
|
||||
case '9' -> stringBuilder.append("<blue>");
|
||||
case 'a' -> stringBuilder.append("<green>");
|
||||
case 'b' -> stringBuilder.append("<aqua>");
|
||||
case 'c' -> stringBuilder.append("<red>");
|
||||
case 'd' -> stringBuilder.append("<light_purple>");
|
||||
case 'e' -> stringBuilder.append("<yellow>");
|
||||
case 'f' -> stringBuilder.append("<white>");
|
||||
case 'r' -> stringBuilder.append("<reset>");
|
||||
case 'l' -> stringBuilder.append("<b>");
|
||||
case 'm' -> stringBuilder.append("<st>");
|
||||
case 'o' -> stringBuilder.append("<i>");
|
||||
case 'n' -> stringBuilder.append("<u>");
|
||||
case 'k' -> stringBuilder.append("<obf>");
|
||||
case 'x' -> {
|
||||
if (i + 13 >= chars.length
|
||||
|| !isColorCode(chars[i+2])
|
||||
|| !isColorCode(chars[i+4])
|
||||
|| !isColorCode(chars[i+6])
|
||||
|| !isColorCode(chars[i+8])
|
||||
|| !isColorCode(chars[i+10])
|
||||
|| !isColorCode(chars[i+12])) {
|
||||
stringBuilder.append(chars[i]);
|
||||
continue;
|
||||
}
|
||||
stringBuilder
|
||||
.append("<#")
|
||||
.append(chars[i+3])
|
||||
.append(chars[i+5])
|
||||
.append(chars[i+7])
|
||||
.append(chars[i+9])
|
||||
.append(chars[i+11])
|
||||
.append(chars[i+13])
|
||||
.append(">");
|
||||
i += 12;
|
||||
}
|
||||
default -> {
|
||||
stringBuilder.append(chars[i]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
|
||||
public boolean isColorCode(char c) {
|
||||
return c == '§' || c == '&';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int rgbaToDecimal(String rgba) {
|
||||
String[] split = rgba.split(",");
|
||||
int r = Integer.parseInt(split[0]);
|
||||
int g = Integer.parseInt(split[1]);
|
||||
int b = Integer.parseInt(split[2]);
|
||||
int a = Integer.parseInt(split[3]);
|
||||
return (a << 24) | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
}
|
||||
@@ -1,290 +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.customcrops.manager;
|
||||
|
||||
import dev.jorel.commandapi.*;
|
||||
import dev.jorel.commandapi.arguments.ArgumentSuggestions;
|
||||
import dev.jorel.commandapi.arguments.IntegerArgument;
|
||||
import dev.jorel.commandapi.arguments.StringArgument;
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.common.Initable;
|
||||
import net.momirealms.customcrops.api.integration.SeasonInterface;
|
||||
import net.momirealms.customcrops.api.manager.AdventureManager;
|
||||
import net.momirealms.customcrops.api.manager.ConfigManager;
|
||||
import net.momirealms.customcrops.api.manager.MessageManager;
|
||||
import net.momirealms.customcrops.api.mechanic.item.ItemType;
|
||||
import net.momirealms.customcrops.api.mechanic.world.ChunkPos;
|
||||
import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock;
|
||||
import net.momirealms.customcrops.api.mechanic.world.SimpleLocation;
|
||||
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsChunk;
|
||||
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsSection;
|
||||
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld;
|
||||
import net.momirealms.customcrops.api.mechanic.world.season.Season;
|
||||
import net.momirealms.customcrops.compatibility.season.InBuiltSeason;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.generator.WorldInfo;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
public class CommandManager implements Initable {
|
||||
|
||||
private final CustomCropsPlugin plugin;
|
||||
|
||||
public CommandManager(CustomCropsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
if (!CommandAPI.isLoaded())
|
||||
CommandAPI.onLoad(new CommandAPIBukkitConfig(plugin).silentLogs(true));
|
||||
new CommandAPICommand("customcrops")
|
||||
.withPermission("customcrops.admin")
|
||||
.withAliases("ccrops")
|
||||
.withSubcommands(
|
||||
getReloadCommand(),
|
||||
getAboutCommand(),
|
||||
getSeasonCommand(),
|
||||
getDateCommand(),
|
||||
getForceTickCommand(),
|
||||
getUnsafeCommand()
|
||||
)
|
||||
.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
CommandAPI.unregister("customcrops");
|
||||
}
|
||||
|
||||
private CommandAPICommand getReloadCommand() {
|
||||
return new CommandAPICommand("reload")
|
||||
.executes((sender, args) -> {
|
||||
long time1 = System.currentTimeMillis();
|
||||
plugin.reload();
|
||||
long time2 = System.currentTimeMillis();
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, MessageManager.reloadMessage().replace("{time}", String.valueOf(time2 - time1)));
|
||||
});
|
||||
}
|
||||
|
||||
private CommandAPICommand getUnsafeCommand() {
|
||||
return new CommandAPICommand("unsafe")
|
||||
.withSubcommands(
|
||||
new CommandAPICommand("delete-chunk-data").executesPlayer((player, args) -> {
|
||||
plugin.getWorldManager().getCustomCropsWorld(player.getWorld()).ifPresent(customCropsWorld -> {
|
||||
var optionalChunk = customCropsWorld.getLoadedChunkAt(ChunkPos.getByBukkitChunk(player.getChunk()));
|
||||
if (optionalChunk.isEmpty()) {
|
||||
AdventureManager.getInstance().sendMessageWithPrefix(player, "<white>This chunk doesn't have any data.");
|
||||
return;
|
||||
}
|
||||
customCropsWorld.deleteChunk(ChunkPos.getByBukkitChunk(player.getChunk()));
|
||||
AdventureManager.getInstance().sendMessageWithPrefix(player, "<white>Done.");
|
||||
});
|
||||
}),
|
||||
new CommandAPICommand("check-data").executesPlayer((player, args) -> {
|
||||
Block block = player.getTargetBlockExact(10);
|
||||
if (block != null) {
|
||||
Optional<CustomCropsBlock> customCropsBlock = plugin.getWorldManager().getBlockAt(SimpleLocation.of(block.getLocation()));
|
||||
if (customCropsBlock.isPresent()) {
|
||||
AdventureManager.getInstance().sendMessageWithPrefix(player, customCropsBlock.get().getType() + ":" + customCropsBlock.get().getCompoundMap());
|
||||
return;
|
||||
}
|
||||
}
|
||||
AdventureManager.getInstance().sendMessageWithPrefix(player, "Data not found");
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private CommandAPICommand getAboutCommand() {
|
||||
return new CommandAPICommand("about").executes((sender, args) -> {
|
||||
plugin.getAdventure().sendMessage(sender, "<#FFA500>⛈ CustomCrops <gray>- <#87CEEB>" + CustomCropsPlugin.getInstance().getVersionManager().getPluginVersion());
|
||||
plugin.getAdventure().sendMessage(sender, "<#FFFFE0>Ultra-customizable planting experience for Minecraft servers");
|
||||
plugin.getAdventure().sendMessage(sender, "<#DA70D6>\uD83E\uDDEA Author: <#FFC0CB>XiaoMoMi");
|
||||
plugin.getAdventure().sendMessage(sender, "<#FF7F50>\uD83D\uDD25 Contributors: <#FFA07A>Cha_Shao<white>, <#FFA07A>TopOrigin<white>, <#FFA07A>AmazingCat");
|
||||
plugin.getAdventure().sendMessage(sender, "<#FFD700>⭐ <click:open_url:https://mo-mi.gitbook.io/xiaomomi-plugins/plugin-wiki/customcrops>Document</click> <#A9A9A9>| <#FAFAD2>⛏ <click:open_url:https://github.com/Xiao-MoMi/Custom-Crops>Github</click> <#A9A9A9>| <#48D1CC>\uD83D\uDD14 <click:open_url:https://polymart.org/resource/customcrops.2625>Polymart</click>");
|
||||
});
|
||||
}
|
||||
|
||||
private CommandAPICommand getForceTickCommand() {
|
||||
return new CommandAPICommand("force-tick")
|
||||
.withArguments(new StringArgument("world").replaceSuggestions(ArgumentSuggestions.strings(commandSenderSuggestionInfo -> Bukkit.getWorlds().stream().map(WorldInfo::getName).toList().toArray(new String[0]))))
|
||||
.withArguments(new StringArgument("type").replaceSuggestions(ArgumentSuggestions.strings("sprinkler", "crop", "pot", "scarecrow", "greenhouse")))
|
||||
.executes((sender, args) -> {
|
||||
String worldName = (String) args.get("world");
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world == null) {
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, "CustomCrops is not enabled in that world");
|
||||
return;
|
||||
}
|
||||
ItemType itemType = ItemType.valueOf(((String) args.get("type")).toUpperCase(Locale.ENGLISH));
|
||||
Optional<CustomCropsWorld> customCropsWorld = plugin.getWorldManager().getCustomCropsWorld(world);
|
||||
if (customCropsWorld.isEmpty()) {
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, "CustomCrops is not enabled in that world");
|
||||
return;
|
||||
}
|
||||
plugin.getScheduler().runTaskAsync(() -> {
|
||||
for (CustomCropsChunk chunk : customCropsWorld.get().getChunkStorage()) {
|
||||
for (CustomCropsSection section : chunk.getSections()) {
|
||||
for (CustomCropsBlock block : section.getBlocks()) {
|
||||
if (block.getType() == itemType) {
|
||||
block.tick(1, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private CommandAPICommand getDateCommand() {
|
||||
return new CommandAPICommand("date")
|
||||
.withSubcommands(
|
||||
new CommandAPICommand("get")
|
||||
.withArguments(new StringArgument("world").replaceSuggestions(ArgumentSuggestions.strings(commandSenderSuggestionInfo -> plugin.getWorldManager().getCustomCropsWorlds().stream()
|
||||
.filter(customCropsWorld -> customCropsWorld.getWorldSetting().isEnableSeason())
|
||||
.map(CustomCropsWorld::getWorldName)
|
||||
.toList()
|
||||
.toArray(new String[0]))))
|
||||
.executes((sender, args) -> {
|
||||
String worldName = (String) args.get("world");
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world == null) {
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, "CustomCrops is not enabled in that world");
|
||||
return;
|
||||
}
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, String.valueOf(plugin.getIntegrationManager().getSeasonInterface().getDate(world)));
|
||||
}),
|
||||
new CommandAPICommand("set")
|
||||
.withArguments(new StringArgument("world").replaceSuggestions(ArgumentSuggestions.strings(commandSenderSuggestionInfo -> plugin.getWorldManager().getCustomCropsWorlds().stream()
|
||||
.filter(customCropsWorld -> customCropsWorld.getWorldSetting().isEnableSeason())
|
||||
.map(CustomCropsWorld::getWorldName)
|
||||
.toList()
|
||||
.toArray(new String[0]))))
|
||||
.withArguments(new IntegerArgument("date",1))
|
||||
.executes((sender, args) -> {
|
||||
String worldName = (String) args.get("world");
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world == null) {
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, "CustomCrops is not enabled in that world");
|
||||
return;
|
||||
}
|
||||
int date = (int) args.getOrDefault("date", 1);
|
||||
SeasonInterface seasonInterface = plugin.getIntegrationManager().getSeasonInterface();
|
||||
if (!(seasonInterface instanceof InBuiltSeason inBuiltSeason)) {
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, "Detected that you are using a season plugin. Please set date in that plugin.");
|
||||
return;
|
||||
}
|
||||
Optional<CustomCropsWorld> customCropsWorld = plugin.getWorldManager().getCustomCropsWorld(world);
|
||||
if (customCropsWorld.isEmpty()) {
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, "CustomCrops is not enabled in that world");
|
||||
return;
|
||||
}
|
||||
if (!customCropsWorld.get().getWorldSetting().isEnableSeason()) {
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, "Season is not enabled in that world");
|
||||
return;
|
||||
}
|
||||
if (date > customCropsWorld.get().getWorldSetting().getSeasonDuration()) {
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, "Date should be a value no higher than season duration");
|
||||
return;
|
||||
}
|
||||
String pre = String.valueOf(inBuiltSeason.getDate(world));
|
||||
customCropsWorld.get().getInfoData().setDate(date);
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, "Date in world("+world.getName()+"): " + pre + " -> " + date);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private CommandAPICommand getSeasonCommand() {
|
||||
return new CommandAPICommand("season")
|
||||
.withSubcommands(
|
||||
new CommandAPICommand("get")
|
||||
.withArguments(new StringArgument("world").replaceSuggestions(ArgumentSuggestions.strings(commandSenderSuggestionInfo -> plugin.getWorldManager().getCustomCropsWorlds().stream()
|
||||
.filter(customCropsWorld -> customCropsWorld.getWorldSetting().isEnableSeason())
|
||||
.map(CustomCropsWorld::getWorldName)
|
||||
.toList()
|
||||
.toArray(new String[0]))))
|
||||
.executes((sender, args) -> {
|
||||
String worldName = (String) args.get("world");
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world == null) {
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, "CustomCrops is not enabled in that world");
|
||||
return;
|
||||
}
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, MessageManager.seasonTranslation(plugin.getIntegrationManager().getSeasonInterface().getSeason(world)));
|
||||
}),
|
||||
new CommandAPICommand("set")
|
||||
.withArguments(new StringArgument("world").replaceSuggestions(ArgumentSuggestions.strings(commandSenderSuggestionInfo -> {
|
||||
if (ConfigManager.syncSeasons()) {
|
||||
return new String[]{ConfigManager.referenceWorld().getName()};
|
||||
}
|
||||
return plugin.getWorldManager().getCustomCropsWorlds().stream()
|
||||
.filter(customCropsWorld -> customCropsWorld.getWorldSetting().isEnableSeason())
|
||||
.map(CustomCropsWorld::getWorldName)
|
||||
.toList()
|
||||
.toArray(new String[0]);
|
||||
})))
|
||||
.withArguments(new StringArgument("season")
|
||||
.replaceSuggestions(ArgumentSuggestions.stringsWithTooltips(info ->
|
||||
new IStringTooltip[] {
|
||||
StringTooltip.ofString("Spring", MessageManager.seasonTranslation(Season.SPRING)),
|
||||
StringTooltip.ofString("Summer", MessageManager.seasonTranslation(Season.SUMMER)),
|
||||
StringTooltip.ofString("Autumn", MessageManager.seasonTranslation(Season.AUTUMN)),
|
||||
StringTooltip.ofString("Winter", MessageManager.seasonTranslation(Season.WINTER))
|
||||
}
|
||||
))
|
||||
)
|
||||
.executes((sender, args) -> {
|
||||
String worldName = (String) args.get("world");
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world == null) {
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, "CustomCrops is not enabled in that world");
|
||||
return;
|
||||
}
|
||||
String seasonName = (String) args.get("season");
|
||||
|
||||
SeasonInterface seasonInterface = plugin.getIntegrationManager().getSeasonInterface();
|
||||
if (!(seasonInterface instanceof InBuiltSeason inBuiltSeason)) {
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, "Detected that you are using a season plugin. Please set season in that plugin.");
|
||||
return;
|
||||
}
|
||||
String pre = MessageManager.seasonTranslation(inBuiltSeason.getSeason(world));
|
||||
Optional<CustomCropsWorld> customCropsWorld = plugin.getWorldManager().getCustomCropsWorld(world);
|
||||
if (customCropsWorld.isEmpty()) {
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, "CustomCrops is not enabled in that world");
|
||||
return;
|
||||
}
|
||||
if (!customCropsWorld.get().getWorldSetting().isEnableSeason()) {
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, "Season is not enabled in that world");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Season season = Season.valueOf(seasonName.toUpperCase(Locale.ENGLISH));
|
||||
customCropsWorld.get().getInfoData().setSeason(season);
|
||||
String next = MessageManager.seasonTranslation(season);
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, "Season in world("+world.getName()+"): " + pre + " -> " + next);
|
||||
} catch (IllegalArgumentException e) {
|
||||
plugin.getAdventure().sendMessageWithPrefix(sender, "That season doesn't exist");
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,277 +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.customcrops.manager;
|
||||
|
||||
import dev.dejvokep.boostedyaml.YamlDocument;
|
||||
import dev.dejvokep.boostedyaml.dvs.versioning.BasicVersioning;
|
||||
import dev.dejvokep.boostedyaml.settings.dumper.DumperSettings;
|
||||
import dev.dejvokep.boostedyaml.settings.general.GeneralSettings;
|
||||
import dev.dejvokep.boostedyaml.settings.loader.LoaderSettings;
|
||||
import dev.dejvokep.boostedyaml.settings.updater.UpdaterSettings;
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.manager.ConfigManager;
|
||||
import net.momirealms.customcrops.api.mechanic.item.ItemCarrier;
|
||||
import net.momirealms.customcrops.api.util.LogUtils;
|
||||
import net.momirealms.customcrops.util.ConfigUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ConfigManagerImpl extends ConfigManager {
|
||||
|
||||
public static final String configVersion = "37";
|
||||
private final CustomCropsPlugin plugin;
|
||||
private String lang;
|
||||
private int maximumPoolSize;
|
||||
private int corePoolSize;
|
||||
private int keepAliveTime;
|
||||
private boolean debug;
|
||||
private boolean metrics;
|
||||
private boolean legacyColorSupport;
|
||||
private boolean protectLore;
|
||||
private String[] itemDetectionOrder = new String[0];
|
||||
private boolean checkUpdate;
|
||||
private boolean disableMoisture;
|
||||
private boolean preventTrampling;
|
||||
private boolean greenhouse;
|
||||
private boolean scarecrow;
|
||||
private double[] defaultQualityRatio;
|
||||
private String greenhouseID;
|
||||
private String scarecrowID;
|
||||
private int greenhouseRange;
|
||||
private int scarecrowRange;
|
||||
private boolean syncSeasons;
|
||||
private WeakReference<World> referenceWorld;
|
||||
private boolean convertWorldOnLoad;
|
||||
private boolean scarecrowProtectChunk;
|
||||
private ItemCarrier scarecrowItemType;
|
||||
private ItemCarrier glassItemType;
|
||||
|
||||
public ConfigManagerImpl(CustomCropsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
if (!new File(plugin.getDataFolder(), "config.yml").exists())
|
||||
ConfigUtils.getConfig("config.yml");
|
||||
// update config version
|
||||
try {
|
||||
YamlDocument.create(
|
||||
new File(CustomCropsPlugin.getInstance().getDataFolder(), "config.yml"),
|
||||
Objects.requireNonNull(CustomCropsPlugin.getInstance().getResource("config.yml")),
|
||||
GeneralSettings.DEFAULT,
|
||||
LoaderSettings
|
||||
.builder()
|
||||
.setAutoUpdate(true)
|
||||
.build(),
|
||||
DumperSettings.DEFAULT,
|
||||
UpdaterSettings
|
||||
.builder()
|
||||
.setVersioning(new BasicVersioning("config-version"))
|
||||
.addIgnoredRoute(configVersion, "other-settings.placeholder-register", '.')
|
||||
.build()
|
||||
);
|
||||
} catch (IOException e) {
|
||||
LogUtils.warn(e.getMessage());
|
||||
}
|
||||
|
||||
YamlConfiguration config = ConfigUtils.getConfig("config.yml");
|
||||
|
||||
debug = config.getBoolean("debug");
|
||||
metrics = config.getBoolean("metrics");
|
||||
lang = config.getString("lang");
|
||||
checkUpdate = config.getBoolean("update-checker", true);
|
||||
|
||||
ConfigurationSection otherSettings = config.getConfigurationSection("other-settings");
|
||||
if (otherSettings == null) {
|
||||
LogUtils.severe("other-settings section should not be null");
|
||||
return;
|
||||
}
|
||||
|
||||
maximumPoolSize = otherSettings.getInt("thread-pool-settings.maximumPoolSize", 10);
|
||||
corePoolSize = otherSettings.getInt("thread-pool-settings.corePoolSize", 10);
|
||||
keepAliveTime = otherSettings.getInt("thread-pool-settings.keepAliveTime", 30);
|
||||
itemDetectionOrder = otherSettings.getStringList("item-detection-order").toArray(new String[0]);
|
||||
protectLore = otherSettings.getBoolean("protect-original-lore", false);
|
||||
legacyColorSupport = otherSettings.getBoolean("legacy-color-code-support", true);
|
||||
convertWorldOnLoad = otherSettings.getBoolean("convert-on-world-load", false);
|
||||
|
||||
ConfigurationSection mechanics = config.getConfigurationSection("mechanics");
|
||||
if (mechanics == null) {
|
||||
LogUtils.severe("mechanics section should not be null");
|
||||
return;
|
||||
}
|
||||
|
||||
defaultQualityRatio = ConfigUtils.getQualityRatio(mechanics.getString("default-quality-ratio", "17/2/1"));
|
||||
disableMoisture = mechanics.getBoolean("vanilla-farmland.disable-moisture-mechanic", false);
|
||||
preventTrampling = mechanics.getBoolean("vanilla-farmland.prevent-trampling", false);
|
||||
greenhouse = mechanics.getBoolean("greenhouse.enable", true);
|
||||
greenhouseID = mechanics.getString("greenhouse.id");
|
||||
greenhouseRange = mechanics.getInt("greenhouse.range", 5);
|
||||
glassItemType = ItemCarrier.valueOf(mechanics.getString("greenhouse.type", "CHORUS").toUpperCase(Locale.ENGLISH));
|
||||
|
||||
scarecrow = mechanics.getBoolean("scarecrow.enable", true);
|
||||
scarecrowID = mechanics.getString("scarecrow.id");
|
||||
scarecrowRange = mechanics.getInt("scarecrow.range", 7);
|
||||
scarecrowProtectChunk = mechanics.getBoolean("scarecrow.protect-chunk", false);
|
||||
scarecrowItemType = ItemCarrier.valueOf(mechanics.getString("scarecrow.type", "ITEM_FRAME").toUpperCase(Locale.ENGLISH));
|
||||
|
||||
syncSeasons = mechanics.getBoolean("sync-season.enable", true);
|
||||
if (syncSeasons) {
|
||||
referenceWorld = new WeakReference<>(Bukkit.getWorld(mechanics.getString("sync-season.reference", "world")));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLegacyColorSupport() {
|
||||
return legacyColorSupport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaximumPoolSize() {
|
||||
return maximumPoolSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCorePoolSize() {
|
||||
return corePoolSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getKeepAliveTime() {
|
||||
return keepAliveTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConvertWorldOnLoad() {
|
||||
return convertWorldOnLoad;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double[] getDefaultQualityRatio() {
|
||||
return defaultQualityRatio;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLang() {
|
||||
return lang;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getDebugMode() {
|
||||
return debug;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isProtectLore() {
|
||||
return protectLore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getItemDetectionOrder() {
|
||||
return itemDetectionOrder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMetrics() {
|
||||
return metrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCheckUpdate() {
|
||||
return checkUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisableMoisture() {
|
||||
return disableMoisture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPreventTrampling() {
|
||||
return preventTrampling;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGreenhouseEnabled() {
|
||||
return greenhouse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGreenhouseID() {
|
||||
return greenhouseID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGreenhouseRange() {
|
||||
return greenhouseRange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isScarecrowEnabled() {
|
||||
return scarecrow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getScarecrowID() {
|
||||
return scarecrowID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScarecrowRange() {
|
||||
return scarecrowRange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSyncSeasons() {
|
||||
return syncSeasons;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesScarecrowProtectChunk() {
|
||||
return scarecrowProtectChunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemCarrier getScarecrowItemCarrier() {
|
||||
return scarecrowItemType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemCarrier getGlassItemCarrier() {
|
||||
return glassItemType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public World getReferenceWorld() {
|
||||
return referenceWorld.get();
|
||||
}
|
||||
}
|
||||
@@ -1,182 +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.customcrops.manager;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.common.Reloadable;
|
||||
import net.momirealms.customcrops.api.common.Tuple;
|
||||
import net.momirealms.customcrops.api.manager.VersionManager;
|
||||
import net.momirealms.customcrops.api.scheduler.CancellableTask;
|
||||
import net.momirealms.customcrops.util.FakeEntityUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class HologramManager implements Listener, Reloadable {
|
||||
|
||||
private final ConcurrentHashMap<UUID, HologramCache> hologramMap;
|
||||
private final CustomCropsPlugin plugin;
|
||||
private CancellableTask cacheCheckTask;
|
||||
private static HologramManager manager;
|
||||
|
||||
public static HologramManager getInstance() {
|
||||
return manager;
|
||||
}
|
||||
|
||||
public HologramManager(CustomCropsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.hologramMap = new ConcurrentHashMap<>();
|
||||
manager = this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
Bukkit.getPluginManager().registerEvents(this, plugin);
|
||||
this.cacheCheckTask = plugin.getScheduler().runTaskAsyncTimer(() -> {
|
||||
ArrayList<UUID> removed = new ArrayList<>();
|
||||
long current = System.currentTimeMillis();
|
||||
for (Map.Entry<UUID, HologramCache> entry : hologramMap.entrySet()) {
|
||||
Player player = Bukkit.getPlayer(entry.getKey());
|
||||
if (player == null || !player.isOnline()) {
|
||||
removed.add(entry.getKey());
|
||||
} else {
|
||||
entry.getValue().removeOutDated(current, player);
|
||||
}
|
||||
}
|
||||
for (UUID uuid : removed) {
|
||||
hologramMap.remove(uuid);
|
||||
}
|
||||
}, 200, 200, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
HandlerList.unregisterAll(this);
|
||||
for (Map.Entry<UUID, HologramCache> entry : hologramMap.entrySet()) {
|
||||
Player player = Bukkit.getPlayer(entry.getKey());
|
||||
if (player != null && player.isOnline()) {
|
||||
entry.getValue().removeAll(player);
|
||||
}
|
||||
}
|
||||
if (cacheCheckTask != null) cacheCheckTask.cancel();
|
||||
this.hologramMap.clear();
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(PlayerQuitEvent event) {
|
||||
this.hologramMap.remove(event.getPlayer().getUniqueId());
|
||||
}
|
||||
|
||||
public void showHologram(Player player, Location location, Component component, int millis) {
|
||||
HologramCache hologramCache = hologramMap.get(player.getUniqueId());
|
||||
if (hologramCache != null) {
|
||||
hologramCache.showHologram(player, location, component, millis);
|
||||
} else {
|
||||
hologramCache = new HologramCache();
|
||||
hologramCache.showHologram(player, location, component, millis);
|
||||
hologramMap.put(player.getUniqueId(), hologramCache);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static class HologramCache {
|
||||
|
||||
private final Vector<Tuple<Location, Integer, Long>> tupleList;
|
||||
private Tuple<Location, Integer, Long>[] tuples;
|
||||
|
||||
public HologramCache() {
|
||||
this.tupleList = new Vector<>();
|
||||
this.tuples = new Tuple[0];
|
||||
}
|
||||
|
||||
public int push(Location new_loc, int time) {
|
||||
for (Tuple<Location, Integer, Long> tuple : tuples) {
|
||||
if (new_loc.equals(tuple.getLeft())) {
|
||||
tuple.setRight(System.currentTimeMillis() + time);
|
||||
return tuple.getMid();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void removeOutDated(long current, Player player) {
|
||||
for (Tuple<Location, Integer, Long> tuple : tuples) {
|
||||
if (tuple.getRight() < current) {
|
||||
tupleList.remove(tuple);
|
||||
this.tuples = tupleList.toArray(new Tuple[0]);
|
||||
PacketManager.getInstance().send(player, FakeEntityUtils.getDestroyPacket(tuple.getMid()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void showHologram(Player player, Location location, Component component, int millis) {
|
||||
int entity_id = push(location, millis);
|
||||
if (entity_id == 0) {
|
||||
int random = ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE);
|
||||
tupleList.add(Tuple.of(location, random, System.currentTimeMillis() + millis));
|
||||
this.tuples = tupleList.toArray(new Tuple[0]);
|
||||
if (VersionManager.isHigherThan1_20_R2()) {
|
||||
PacketManager.getInstance().send(player,
|
||||
FakeEntityUtils.getSpawnPacket(random, location.clone().add(0,1.25,0), EntityType.TEXT_DISPLAY),
|
||||
FakeEntityUtils.get1_20_2TextDisplayMetaPacket(random, component)
|
||||
);
|
||||
} else if (VersionManager.isHigherThan1_19_R3()) {
|
||||
PacketManager.getInstance().send(player,
|
||||
FakeEntityUtils.getSpawnPacket(random, location.clone().add(0,1.25,0), EntityType.TEXT_DISPLAY),
|
||||
FakeEntityUtils.get1_19_4TextDisplayMetaPacket(random, component)
|
||||
);
|
||||
} else {
|
||||
PacketManager.getInstance().send(player,
|
||||
FakeEntityUtils.getSpawnPacket(random, location, EntityType.ARMOR_STAND),
|
||||
FakeEntityUtils.getVanishArmorStandMetaPacket(random, component)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (VersionManager.isHigherThan1_20_R2()) {
|
||||
PacketManager.getInstance().send(player, FakeEntityUtils.get1_20_2TextDisplayMetaPacket(entity_id, component));
|
||||
} else if (VersionManager.isHigherThan1_19_R3()) {
|
||||
PacketManager.getInstance().send(player, FakeEntityUtils.get1_19_4TextDisplayMetaPacket(entity_id, component));
|
||||
} else {
|
||||
PacketManager.getInstance().send(player, FakeEntityUtils.getVanishArmorStandMetaPacket(entity_id, component));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAll(Player player) {
|
||||
for (Tuple<Location, Integer, Long> tuple : tuples) {
|
||||
PacketManager.getInstance().send(player, FakeEntityUtils.getDestroyPacket(tuple.getMid()));
|
||||
}
|
||||
this.tupleList.clear();
|
||||
this.tuples = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,99 +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.customcrops.manager;
|
||||
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.common.Reloadable;
|
||||
import net.momirealms.customcrops.api.manager.ConfigManager;
|
||||
import net.momirealms.customcrops.api.manager.MessageManager;
|
||||
import net.momirealms.customcrops.api.mechanic.world.season.Season;
|
||||
import net.momirealms.customcrops.api.util.LogUtils;
|
||||
import net.momirealms.customcrops.util.ConfigUtils;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class MessageManagerImpl extends MessageManager implements Reloadable {
|
||||
|
||||
private CustomCropsPlugin plugin;
|
||||
private String reload;
|
||||
private String prefix;
|
||||
private String spring;
|
||||
private String summer;
|
||||
private String autumn;
|
||||
private String winter;
|
||||
private String noSeason;
|
||||
|
||||
public MessageManagerImpl(CustomCropsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
YamlConfiguration config;
|
||||
try {
|
||||
config = ConfigUtils.getConfig("messages" + File.separator + ConfigManager.lang() + ".yml");
|
||||
} catch (Exception e) {
|
||||
LogUtils.warn(ConfigManager.lang() + ".yml doesn't exist. Using the default language file now.");
|
||||
config = ConfigUtils.getConfig("messages" + File.separator + "en" + ".yml");
|
||||
}
|
||||
ConfigurationSection section = config.getConfigurationSection("messages");
|
||||
if (section != null) {
|
||||
prefix = section.getString("prefix", "<gradient:#ff206c:#fdee55>[CustomCrops]</gradient> ");
|
||||
reload = section.getString("reload", "<white>Reloaded! Took <green>{time}ms.</green></white>");
|
||||
|
||||
spring = section.getString("spring", "Spring");
|
||||
summer = section.getString("summer", "Summer");
|
||||
autumn = section.getString("autumn", "Autumn");
|
||||
winter = section.getString("winter", "Winter");
|
||||
noSeason = section.getString("no-season", "Season Disabled");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSeasonTranslation(Season season) {
|
||||
if (season == null) return noSeason;
|
||||
return switch (season) {
|
||||
case SPRING -> spring;
|
||||
case SUMMER -> summer;
|
||||
case AUTUMN -> autumn;
|
||||
case WINTER -> winter;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getReload() {
|
||||
return reload;
|
||||
}
|
||||
}
|
||||
@@ -1,64 +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.customcrops.manager;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class PacketManager {
|
||||
|
||||
private static PacketManager instance;
|
||||
private final ProtocolManager protocolManager;
|
||||
private final CustomCropsPlugin plugin;
|
||||
|
||||
public PacketManager(CustomCropsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.protocolManager = ProtocolLibrary.getProtocolManager();
|
||||
instance = this;
|
||||
}
|
||||
|
||||
public static PacketManager getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void send(Player player, PacketContainer packet) {
|
||||
this.protocolManager.sendServerPacket(player, packet);
|
||||
}
|
||||
|
||||
public void send(Player player, PacketContainer... packets) {
|
||||
if (!player.isOnline()) return;
|
||||
if (plugin.getVersionManager().isVersionNewerThan1_19_R3()) {
|
||||
List<PacketContainer> bundle = new ArrayList<>(Arrays.asList(packets));
|
||||
PacketContainer bundlePacket = new PacketContainer(PacketType.Play.Server.BUNDLE);
|
||||
bundlePacket.getPacketBundles().write(0, bundle);
|
||||
send(player, bundlePacket);
|
||||
} else {
|
||||
for (PacketContainer packet : packets) {
|
||||
send(player, packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,120 +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.customcrops.manager;
|
||||
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.manager.PlaceholderManager;
|
||||
import net.momirealms.customcrops.compatibility.papi.CCPapi;
|
||||
import net.momirealms.customcrops.compatibility.papi.ParseUtils;
|
||||
import net.momirealms.customcrops.util.ConfigUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PlaceholderManagerImpl extends PlaceholderManager {
|
||||
|
||||
private final HashMap<String, String> customPlaceholderMap;
|
||||
private final CustomCropsPlugin plugin;
|
||||
private final boolean hasPapi;
|
||||
private CCPapi ccPapi;
|
||||
|
||||
public PlaceholderManagerImpl(CustomCropsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.customPlaceholderMap = new HashMap<>();
|
||||
this.hasPapi = Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI");
|
||||
if (hasPapi) {
|
||||
ccPapi = new CCPapi(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
if (ccPapi != null) {
|
||||
ccPapi.register();
|
||||
}
|
||||
this.loadCustomPlaceholders();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
if (ccPapi != null) {
|
||||
ccPapi.unregister();
|
||||
}
|
||||
this.customPlaceholderMap.clear();
|
||||
}
|
||||
|
||||
public void loadCustomPlaceholders() {
|
||||
YamlConfiguration config = ConfigUtils.getConfig("config.yml");
|
||||
ConfigurationSection section = config.getConfigurationSection("other-settings.placeholder-register");
|
||||
if (section != null) {
|
||||
for (Map.Entry<String, Object> entry : section.getValues(false).entrySet()) {
|
||||
this.customPlaceholderMap.put(entry.getKey(), (String) entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parse(@Nullable Player player, String text, Map<String, String> placeholders) {
|
||||
var list = detectPlaceholders(text);
|
||||
for (String papi : list) {
|
||||
String replacer = null;
|
||||
if (placeholders != null) {
|
||||
replacer = placeholders.get(papi);
|
||||
}
|
||||
if (replacer == null) {
|
||||
String custom = customPlaceholderMap.get(papi);
|
||||
if (custom != null) {
|
||||
replacer = setPlaceholders(player, parse(player, custom, placeholders));
|
||||
}
|
||||
}
|
||||
if (replacer != null) {
|
||||
text = text.replace(papi, replacer);
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> parse(@Nullable Player player, List<String> list, Map<String, String> replacements) {
|
||||
return list.stream()
|
||||
.map(s -> parse(player, s, replacements))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> detectPlaceholders(String text) {
|
||||
List<String> placeholders = new ArrayList<>();
|
||||
Matcher matcher = pattern.matcher(text);
|
||||
while (matcher.find()) placeholders.add(matcher.group());
|
||||
return placeholders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setPlaceholders(Player player, String text) {
|
||||
return hasPapi ? ParseUtils.setPlaceholders(player, text) : text;
|
||||
}
|
||||
}
|
||||
@@ -1,186 +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.customcrops.manager;
|
||||
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.manager.VersionManager;
|
||||
import net.momirealms.customcrops.api.util.LogUtils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class VersionManagerImpl extends VersionManager {
|
||||
|
||||
private final CustomCropsPlugin plugin;
|
||||
private final String pluginVersion;
|
||||
private boolean foliaScheduler;
|
||||
private final boolean isSpigot;
|
||||
private boolean isMojmap;
|
||||
|
||||
private final float mcVersion;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public VersionManagerImpl(CustomCropsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.isSpigot = plugin.getServer().getName().equals("CraftBukkit");
|
||||
this.pluginVersion = plugin.getDescription().getVersion();
|
||||
|
||||
String[] split = plugin.getServerVersion().split("\\.");
|
||||
this.mcVersion = Float.parseFloat(split[1] + "." + (split.length >= 3 ? split[2] : "0"));
|
||||
|
||||
try {
|
||||
Class.forName("io.papermc.paper.threadedregions.RegionizedServer");
|
||||
this.foliaScheduler = true;
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
this.foliaScheduler = false;
|
||||
}
|
||||
|
||||
// Check if the server is Mojmap
|
||||
try {
|
||||
Class.forName("net.minecraft.network.protocol.game.ClientboundBossEventPacket");
|
||||
this.isMojmap = true;
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRegionScheduler() {
|
||||
return foliaScheduler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPluginVersion() {
|
||||
return pluginVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSpigot() {
|
||||
return isSpigot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVersionNewerThan1_19_R3() {
|
||||
return mcVersion >= 19.4;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVersionNewerThan1_20_R2() {
|
||||
return mcVersion >= 20.2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVersionNewerThan1_19() {
|
||||
return mcVersion >= 19;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVersionNewerThan1_19_R2() {
|
||||
return mcVersion >= 19.3;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVersionNewerThan1_20() {
|
||||
return mcVersion >= 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVersionNewerThan1_18() {
|
||||
return mcVersion >= 18;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMojmap() {
|
||||
return isMojmap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> checkUpdate() {
|
||||
CompletableFuture<Boolean> updateFuture = new CompletableFuture<>();
|
||||
plugin.getScheduler().runTaskAsync(() -> {
|
||||
try {
|
||||
URL url = new URL("https://api.polymart.org/v1/getResourceInfoSimple/?resource_id=2625&key=version");
|
||||
URLConnection conn = url.openConnection();
|
||||
conn.setConnectTimeout(10000);
|
||||
conn.setReadTimeout(60000);
|
||||
InputStream inputStream = conn.getInputStream();
|
||||
String newest = new BufferedReader(new InputStreamReader(inputStream)).readLine();
|
||||
String current = plugin.getVersionManager().getPluginVersion();
|
||||
inputStream.close();
|
||||
if (!compareVer(newest, current)) {
|
||||
updateFuture.complete(false);
|
||||
return;
|
||||
}
|
||||
updateFuture.complete(true);
|
||||
} catch (Exception exception) {
|
||||
LogUtils.warn("Error occurred when checking update.", exception);
|
||||
updateFuture.complete(false);
|
||||
}
|
||||
});
|
||||
return updateFuture;
|
||||
}
|
||||
|
||||
private boolean compareVer(String newV, String currentV) {
|
||||
if (newV == null || currentV == null || newV.isEmpty() || currentV.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
String[] newVS = newV.split("\\.");
|
||||
String[] currentVS = currentV.split("\\.");
|
||||
int maxL = Math.min(newVS.length, currentVS.length);
|
||||
for (int i = 0; i < maxL; i++) {
|
||||
try {
|
||||
String[] newPart = newVS[i].split("-");
|
||||
String[] currentPart = currentVS[i].split("-");
|
||||
int newNum = Integer.parseInt(newPart[0]);
|
||||
int currentNum = Integer.parseInt(currentPart[0]);
|
||||
if (newNum > currentNum) {
|
||||
return true;
|
||||
} else if (newNum < currentNum) {
|
||||
return false;
|
||||
} else if (newPart.length > 1 && currentPart.length > 1) {
|
||||
String[] newHotfix = newPart[1].split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
|
||||
String[] currentHotfix = currentPart[1].split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
|
||||
if (newHotfix.length == 2 && currentHotfix.length == 1) return true;
|
||||
else if (newHotfix.length > 1 && currentHotfix.length > 1) {
|
||||
int newHotfixNum = Integer.parseInt(newHotfix[1]);
|
||||
int currentHotfixNum = Integer.parseInt(currentHotfix[1]);
|
||||
if (newHotfixNum > currentHotfixNum) {
|
||||
return true;
|
||||
} else if (newHotfixNum < currentHotfixNum) {
|
||||
return false;
|
||||
} else {
|
||||
return newHotfix[0].compareTo(currentHotfix[0]) > 0;
|
||||
}
|
||||
}
|
||||
} else if (newPart.length > 1) {
|
||||
return true;
|
||||
} else if (currentPart.length > 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return newVS.length > currentVS.length;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,30 +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.customcrops.mechanic.action;
|
||||
|
||||
import net.momirealms.customcrops.api.mechanic.action.Action;
|
||||
import net.momirealms.customcrops.api.mechanic.requirement.State;
|
||||
|
||||
public class EmptyAction implements Action {
|
||||
|
||||
public static EmptyAction instance = new EmptyAction();
|
||||
|
||||
@Override
|
||||
public void trigger(State state) {
|
||||
}
|
||||
}
|
||||
@@ -1,760 +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.customcrops.mechanic.condition;
|
||||
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.common.Pair;
|
||||
import net.momirealms.customcrops.api.manager.ConditionManager;
|
||||
import net.momirealms.customcrops.api.manager.ConfigManager;
|
||||
import net.momirealms.customcrops.api.mechanic.condition.Condition;
|
||||
import net.momirealms.customcrops.api.mechanic.condition.ConditionExpansion;
|
||||
import net.momirealms.customcrops.api.mechanic.condition.ConditionFactory;
|
||||
import net.momirealms.customcrops.api.mechanic.item.Fertilizer;
|
||||
import net.momirealms.customcrops.api.mechanic.world.SimpleLocation;
|
||||
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld;
|
||||
import net.momirealms.customcrops.api.mechanic.world.level.WorldPot;
|
||||
import net.momirealms.customcrops.api.mechanic.world.season.Season;
|
||||
import net.momirealms.customcrops.api.util.LogUtils;
|
||||
import net.momirealms.customcrops.compatibility.papi.ParseUtils;
|
||||
import net.momirealms.customcrops.mechanic.misc.CrowAttackAnimation;
|
||||
import net.momirealms.customcrops.mechanic.world.block.MemoryCrop;
|
||||
import net.momirealms.customcrops.util.ClassUtils;
|
||||
import net.momirealms.customcrops.util.ConfigUtils;
|
||||
import net.momirealms.sparrow.heart.SparrowHeart;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.type.Farmland;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
|
||||
public class ConditionManagerImpl implements ConditionManager {
|
||||
|
||||
private final String EXPANSION_FOLDER = "expansions/condition";
|
||||
private final HashMap<String, ConditionFactory> conditionBuilderMap;
|
||||
private final CustomCropsPlugin plugin;
|
||||
|
||||
public ConditionManagerImpl(CustomCropsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.conditionBuilderMap = new HashMap<>();
|
||||
this.registerInbuiltConditions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
this.loadExpansions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unload() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
this.conditionBuilderMap.clear();
|
||||
}
|
||||
|
||||
private void registerInbuiltConditions() {
|
||||
this.registerSeasonCondition();
|
||||
this.registerWaterCondition();
|
||||
this.registerTemperatureCondition();
|
||||
this.registerAndCondition();
|
||||
this.registerOrCondition();
|
||||
this.registerRandomCondition();
|
||||
this.registerEqualsCondition();
|
||||
this.registerNumberEqualCondition();
|
||||
this.registerRegexCondition();
|
||||
this.registerGreaterThanCondition();
|
||||
this.registerLessThanCondition();
|
||||
this.registerContainCondition();
|
||||
this.registerStartWithCondition();
|
||||
this.registerEndWithCondition();
|
||||
this.registerInListCondition();
|
||||
this.registerBiomeRequirement();
|
||||
this.registerFertilizerCondition();
|
||||
this.registerCrowAttackCondition();
|
||||
this.registerPotCondition();
|
||||
this.registerLightCondition();
|
||||
this.registerPointCondition();
|
||||
this.registerWorldRequirement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerCondition(String type, ConditionFactory conditionFactory) {
|
||||
if (this.conditionBuilderMap.containsKey(type)) return false;
|
||||
this.conditionBuilderMap.put(type, conditionFactory);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregisterCondition(String type) {
|
||||
return this.conditionBuilderMap.remove(type) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Condition[] getConditions(ConfigurationSection section) {
|
||||
ArrayList<Condition> conditions = new ArrayList<>();
|
||||
if (section != null) {
|
||||
for (Map.Entry<String, Object> entry : section.getValues(false).entrySet()) {
|
||||
if (entry.getValue() instanceof ConfigurationSection innerSection) {
|
||||
String key = entry.getKey();
|
||||
if (hasCondition(key)) {
|
||||
conditions.add(getCondition(key, innerSection));
|
||||
} else {
|
||||
conditions.add(getCondition(section.getConfigurationSection(key)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return conditions.toArray(new Condition[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Condition getCondition(ConfigurationSection section) {
|
||||
if (section == null) {
|
||||
LogUtils.warn("Condition section should not be null");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
return getCondition(section.getString("type"), section.get("value"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Condition getCondition(String key, Object args) {
|
||||
if (key == null) {
|
||||
LogUtils.warn("Condition type should not be null");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
ConditionFactory factory = getConditionFactory(key);
|
||||
if (factory == null) {
|
||||
LogUtils.warn("Condition type: " + key + " doesn't exist.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
return factory.build(args);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ConditionFactory getConditionFactory(String type) {
|
||||
return conditionBuilderMap.get(type);
|
||||
}
|
||||
|
||||
private void registerCrowAttackCondition() {
|
||||
registerCondition("crow_attack", (args -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String flyModel = section.getString("fly-model");
|
||||
String standModel = section.getString("stand-model");
|
||||
double chance = section.getDouble("chance");
|
||||
return (block, offline) -> {
|
||||
if (Math.random() > chance) return false;
|
||||
SimpleLocation location = block.getLocation();
|
||||
if (ConfigManager.enableScarecrow()) {
|
||||
Optional<CustomCropsWorld> world = plugin.getWorldManager().getCustomCropsWorld(location.getWorldName());
|
||||
if (world.isEmpty()) return false;
|
||||
CustomCropsWorld customCropsWorld = world.get();
|
||||
if (!ConfigManager.scarecrowProtectChunk()) {
|
||||
int range = ConfigManager.scarecrowRange();
|
||||
for (int i = -range; i <= range; i++) {
|
||||
for (int j = -range; j <= range; j++) {
|
||||
for (int k : new int[]{0,-1,1}) {
|
||||
if (customCropsWorld.getScarecrowAt(location.copy().add(i, k, j)).isPresent()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (customCropsWorld.doesChunkHaveScarecrow(location)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!offline)
|
||||
new CrowAttackAnimation(location, flyModel, standModel).start();
|
||||
return true;
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at crow-attack condition.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void registerWorldRequirement() {
|
||||
registerCondition("world", (args) -> {
|
||||
HashSet<String> worlds = new HashSet<>(ConfigUtils.stringListArgs(args));
|
||||
return (block, offline) -> worlds.contains(block.getLocation().getWorldName());
|
||||
});
|
||||
registerCondition("!world", (args) -> {
|
||||
HashSet<String> worlds = new HashSet<>(ConfigUtils.stringListArgs(args));
|
||||
return (block, offline) -> !worlds.contains(block.getLocation().getWorldName());
|
||||
});
|
||||
}
|
||||
|
||||
private void registerBiomeRequirement() {
|
||||
registerCondition("biome", (args) -> {
|
||||
HashSet<String> biomes = new HashSet<>(ConfigUtils.stringListArgs(args));
|
||||
return (block, offline) -> {
|
||||
String currentBiome = SparrowHeart.getInstance().getBiomeResourceLocation(block.getLocation().getBukkitLocation());
|
||||
return biomes.contains(currentBiome);
|
||||
};
|
||||
});
|
||||
registerCondition("!biome", (args) -> {
|
||||
HashSet<String> biomes = new HashSet<>(ConfigUtils.stringListArgs(args));
|
||||
return (block, offline) -> {
|
||||
String currentBiome = SparrowHeart.getInstance().getBiomeResourceLocation(block.getLocation().getBukkitLocation());
|
||||
return !biomes.contains(currentBiome);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private void registerRandomCondition() {
|
||||
registerCondition("random", (args -> {
|
||||
double value = ConfigUtils.getDoubleValue(args);
|
||||
return (block, offline) -> Math.random() < value;
|
||||
}));
|
||||
}
|
||||
|
||||
private void registerPotCondition() {
|
||||
registerCondition("pot", (args -> {
|
||||
HashSet<String> pots = new HashSet<>(ConfigUtils.stringListArgs(args));
|
||||
return (block, offline) -> {
|
||||
Optional<WorldPot> worldPot = plugin.getWorldManager().getPotAt(block.getLocation().copy().add(0,-1,0));
|
||||
return worldPot.filter(pot -> pots.contains(pot.getKey())).isPresent();
|
||||
};
|
||||
}));
|
||||
registerCondition("!pot", (args -> {
|
||||
HashSet<String> pots = new HashSet<>(ConfigUtils.stringListArgs(args));
|
||||
return (block, offline) -> {
|
||||
Optional<WorldPot> worldPot = plugin.getWorldManager().getPotAt(block.getLocation().copy().add(0,-1,0));
|
||||
return worldPot.filter(pot -> !pots.contains(pot.getKey())).isPresent();
|
||||
};
|
||||
}));
|
||||
}
|
||||
|
||||
private void registerFertilizerCondition() {
|
||||
registerCondition("fertilizer", (args -> {
|
||||
HashSet<String> fertilizer = new HashSet<>(ConfigUtils.stringListArgs(args));
|
||||
return (block, offline) -> {
|
||||
Optional<WorldPot> worldPot = plugin.getWorldManager().getPotAt(block.getLocation().copy().add(0,-1,0));
|
||||
return worldPot.filter(pot -> {
|
||||
Fertilizer fertilizerInstance = pot.getFertilizer();
|
||||
if (fertilizerInstance == null) return false;
|
||||
return fertilizer.contains(fertilizerInstance.getKey());
|
||||
}).isPresent();
|
||||
};
|
||||
}));
|
||||
registerCondition("fertilizer_type", (args -> {
|
||||
HashSet<String> fertilizer = new HashSet<>(ConfigUtils.stringListArgs(args).stream().map(str -> str.toUpperCase(Locale.ENGLISH)).toList());
|
||||
return (block, offline) -> {
|
||||
Optional<WorldPot> worldPot = plugin.getWorldManager().getPotAt(block.getLocation().copy().add(0,-1,0));
|
||||
return worldPot.filter(pot -> {
|
||||
Fertilizer fertilizerInstance = pot.getFertilizer();
|
||||
if (fertilizerInstance == null) return false;
|
||||
return fertilizer.contains(fertilizerInstance.getFertilizerType().name());
|
||||
}).isPresent();
|
||||
};
|
||||
}));
|
||||
}
|
||||
|
||||
private void registerAndCondition() {
|
||||
registerCondition("&&", (args -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
Condition[] conditions = getConditions(section);
|
||||
return (block, offline) -> ConditionManager.isConditionMet(block, offline, conditions);
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at && condition.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void registerOrCondition() {
|
||||
registerCondition("||", (args -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
Condition[] conditions = getConditions(section);
|
||||
return (block, offline) -> {
|
||||
for (Condition condition : conditions) {
|
||||
if (condition.isConditionMet(block, offline)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at || condition.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void registerTemperatureCondition() {
|
||||
registerCondition("temperature", (args) -> {
|
||||
List<Pair<Integer, Integer>> tempPairs = ConfigUtils.stringListArgs(args).stream().map(it -> ConfigUtils.splitStringIntegerArgs(it, "~")).toList();
|
||||
return (block, offline) -> {
|
||||
SimpleLocation location = block.getLocation();
|
||||
World world = location.getBukkitWorld();
|
||||
if (world == null) return false;
|
||||
double temp = world.getTemperature(location.getX(), location.getY(), location.getZ());
|
||||
for (Pair<Integer, Integer> pair : tempPairs) {
|
||||
if (temp >= pair.left() && temp <= pair.right()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
private void registerGreaterThanCondition() {
|
||||
registerCondition(">=", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String v1 = section.getString("value1", "");
|
||||
String v2 = section.getString("value2", "");
|
||||
return (block, offline) -> {
|
||||
String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1;
|
||||
String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2;
|
||||
return Double.parseDouble(p1) >= Double.parseDouble(p2);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at >= requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
registerCondition(">", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String v1 = section.getString("value1", "");
|
||||
String v2 = section.getString("value2", "");
|
||||
return (block, offline) -> {
|
||||
String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1;
|
||||
String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2;
|
||||
return Double.parseDouble(p1) > Double.parseDouble(p2);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at > requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void registerRegexCondition() {
|
||||
registerCondition("regex", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String v1 = section.getString("papi", "");
|
||||
String v2 = section.getString("regex", "");
|
||||
return (block, offline) -> ParseUtils.setPlaceholders(null, v1).matches(v2);
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at regex requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void registerNumberEqualCondition() {
|
||||
registerCondition("==", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String v1 = section.getString("value1", "");
|
||||
String v2 = section.getString("value2", "");
|
||||
return (block, offline) -> {
|
||||
String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1;
|
||||
String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2;
|
||||
return Double.parseDouble(p1) == Double.parseDouble(p2);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at !startsWith requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
registerCondition("!=", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String v1 = section.getString("value1", "");
|
||||
String v2 = section.getString("value2", "");
|
||||
return (block, offline) -> {
|
||||
String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1;
|
||||
String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2;
|
||||
return Double.parseDouble(p1) != Double.parseDouble(p2);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at !startsWith requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
private void registerLessThanCondition() {
|
||||
registerCondition("<", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String v1 = section.getString("value1", "");
|
||||
String v2 = section.getString("value2", "");
|
||||
return (block, offline) -> {
|
||||
String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1;
|
||||
String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2;
|
||||
return Double.parseDouble(p1) < Double.parseDouble(p2);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at < requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
registerCondition("<=", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String v1 = section.getString("value1", "");
|
||||
String v2 = section.getString("value2", "");
|
||||
return (block, offline) -> {
|
||||
String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1;
|
||||
String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2;
|
||||
return Double.parseDouble(p1) <= Double.parseDouble(p2);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at <= requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void registerStartWithCondition() {
|
||||
registerCondition("startsWith", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String v1 = section.getString("value1", "");
|
||||
String v2 = section.getString("value2", "");
|
||||
return (block, offline) -> {
|
||||
String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1;
|
||||
String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2;
|
||||
return p1.startsWith(p2);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at startsWith requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
registerCondition("!startsWith", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String v1 = section.getString("value1", "");
|
||||
String v2 = section.getString("value2", "");
|
||||
return (block, offline) -> {
|
||||
String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1;
|
||||
String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2;
|
||||
return !p1.startsWith(p2);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at !startsWith requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void registerEndWithCondition() {
|
||||
registerCondition("endsWith", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String v1 = section.getString("value1", "");
|
||||
String v2 = section.getString("value2", "");
|
||||
return (block, offline) -> {
|
||||
String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1;
|
||||
String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2;
|
||||
return p1.endsWith(p2);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at endsWith requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
registerCondition("!endsWith", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String v1 = section.getString("value1", "");
|
||||
String v2 = section.getString("value2", "");
|
||||
return (block, offline) -> {
|
||||
String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1;
|
||||
String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2;
|
||||
return !p1.endsWith(p2);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at !endsWith requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void registerContainCondition() {
|
||||
registerCondition("contains", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String v1 = section.getString("value1", "");
|
||||
String v2 = section.getString("value2", "");
|
||||
return (block, offline) -> {
|
||||
String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1;
|
||||
String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2;
|
||||
return p1.contains(p2);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at contains requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
registerCondition("!contains", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String v1 = section.getString("value1", "");
|
||||
String v2 = section.getString("value2", "");
|
||||
return (block, offline) -> {
|
||||
String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1;
|
||||
String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2;
|
||||
return !p1.contains(p2);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at !contains requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void registerInListCondition() {
|
||||
registerCondition("in-list", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String papi = section.getString("papi", "");
|
||||
HashSet<String> values = new HashSet<>(ConfigUtils.stringListArgs(section.get("values")));
|
||||
return (block, offline) -> {
|
||||
String p1 = papi.startsWith("%") ? ParseUtils.setPlaceholders(null, papi) : papi;
|
||||
return values.contains(p1);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at in-list requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
registerCondition("!in-list", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String papi = section.getString("papi", "");
|
||||
HashSet<String> values = new HashSet<>(ConfigUtils.stringListArgs(section.get("values")));
|
||||
return (block, offline) -> {
|
||||
String p1 = papi.startsWith("%") ? ParseUtils.setPlaceholders(null, papi) : papi;
|
||||
return !values.contains(p1);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at in-list requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void registerEqualsCondition() {
|
||||
registerCondition("equals", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String v1 = section.getString("value1", "");
|
||||
String v2 = section.getString("value2", "");
|
||||
return (block, offline) -> {
|
||||
String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1;
|
||||
String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2;
|
||||
return p1.equals(p2);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at equals requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
registerCondition("!equals", (args) -> {
|
||||
if (args instanceof ConfigurationSection section) {
|
||||
String v1 = section.getString("value1", "");
|
||||
String v2 = section.getString("value2", "");
|
||||
return (block, offline) -> {
|
||||
String p1 = v1.startsWith("%") ? ParseUtils.setPlaceholders(null, v1) : v1;
|
||||
String p2 = v2.startsWith("%") ? ParseUtils.setPlaceholders(null, v2) : v2;
|
||||
return !p1.equals(p2);
|
||||
};
|
||||
} else {
|
||||
LogUtils.warn("Wrong value format found at !equals requirement.");
|
||||
return EmptyCondition.instance;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void registerSeasonCondition() {
|
||||
registerCondition("suitable_season", (args) -> {
|
||||
HashSet<String> seasons = new HashSet<>(ConfigUtils.stringListArgs(args).stream().map(it -> it.toUpperCase(Locale.ENGLISH)).toList());
|
||||
return (block, offline) -> {
|
||||
Season season = plugin.getIntegrationManager().getSeasonInterface().getSeason(block.getLocation().getBukkitWorld());
|
||||
if (season == null) {
|
||||
return true;
|
||||
}
|
||||
if (seasons.contains(season.name())) {
|
||||
return true;
|
||||
}
|
||||
if (ConfigManager.enableGreenhouse()) {
|
||||
SimpleLocation location = block.getLocation();
|
||||
Optional<CustomCropsWorld> world = plugin.getWorldManager().getCustomCropsWorld(location.getWorldName());
|
||||
if (world.isEmpty()) return false;
|
||||
CustomCropsWorld customCropsWorld = world.get();
|
||||
for (int i = 1, range = ConfigManager.greenhouseRange(); i <= range; i++) {
|
||||
if (customCropsWorld.getGlassAt(location.copy().add(0,i,0)).isPresent()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
});
|
||||
registerCondition("unsuitable_season", (args) -> {
|
||||
HashSet<String> seasons = new HashSet<>(ConfigUtils.stringListArgs(args).stream().map(it -> it.toUpperCase(Locale.ENGLISH)).toList());
|
||||
return (block, offline) -> {
|
||||
Season season = plugin.getIntegrationManager().getSeasonInterface().getSeason(block.getLocation().getBukkitWorld());
|
||||
if (season == null) {
|
||||
return false;
|
||||
}
|
||||
if (seasons.contains(season.name())) {
|
||||
if (ConfigManager.enableGreenhouse()) {
|
||||
SimpleLocation location = block.getLocation();
|
||||
Optional<CustomCropsWorld> world = plugin.getWorldManager().getCustomCropsWorld(location.getWorldName());
|
||||
if (world.isEmpty()) return false;
|
||||
CustomCropsWorld customCropsWorld = world.get();
|
||||
for (int i = 1, range = ConfigManager.greenhouseRange(); i <= range; i++) {
|
||||
if (customCropsWorld.getGlassAt(location.copy().add(0,i,0)).isPresent()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private void registerLightCondition() {
|
||||
registerCondition("skylight_more_than", (args) -> {
|
||||
int value = (int) args;
|
||||
return (block, offline) -> {
|
||||
int light = block.getLocation().getBukkitLocation().getBlock().getLightFromSky();
|
||||
return value > light;
|
||||
};
|
||||
});
|
||||
registerCondition("skylight_less_than", (args) -> {
|
||||
int value = (int) args;
|
||||
return (block, offline) -> {
|
||||
int light = block.getLocation().getBukkitLocation().getBlock().getLightFromSky();
|
||||
return value < light;
|
||||
};
|
||||
});
|
||||
registerCondition("light_more_than", (args) -> {
|
||||
int value = (int) args;
|
||||
return (block, offline) -> {
|
||||
int light = block.getLocation().getBukkitLocation().getBlock().getLightLevel();
|
||||
return value > light;
|
||||
};
|
||||
});
|
||||
registerCondition("light_less_than", (args) -> {
|
||||
int value = (int) args;
|
||||
return (block, offline) -> {
|
||||
int light = block.getLocation().getBukkitLocation().getBlock().getLightLevel();
|
||||
return value < light;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private void registerPointCondition() {
|
||||
registerCondition("point_more_than", (args) -> {
|
||||
int value = (int) args;
|
||||
return (block, offline) -> {
|
||||
if (block instanceof MemoryCrop crop) {
|
||||
return crop.getPoint() > value;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
});
|
||||
registerCondition("point_less_than", (args) -> {
|
||||
int value = (int) args;
|
||||
return (block, offline) -> {
|
||||
if (block instanceof MemoryCrop crop) {
|
||||
return crop.getPoint() < value;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private void registerWaterCondition() {
|
||||
registerCondition("water_more_than", (args) -> {
|
||||
int value = (int) args;
|
||||
return (block, offline) -> {
|
||||
Optional<WorldPot> worldPot = plugin.getWorldManager().getPotAt(block.getLocation().copy().add(0,-1,0));
|
||||
return worldPot.filter(pot -> pot.getWater() > value).isPresent();
|
||||
};
|
||||
});
|
||||
registerCondition("water_less_than", (args) -> {
|
||||
int value = (int) args;
|
||||
return (block, offline) -> {
|
||||
Optional<WorldPot> worldPot = plugin.getWorldManager().getPotAt(block.getLocation().copy().add(0,-1,0));
|
||||
return worldPot.filter(pot -> pot.getWater() < value).isPresent();
|
||||
};
|
||||
});
|
||||
registerCondition("moisture_more_than", (args) -> {
|
||||
int value = (int) args;
|
||||
return (block, offline) -> {
|
||||
Block underBlock = block.getLocation().copy().add(0,-1,0).getBukkitLocation().getBlock();
|
||||
if (underBlock.getBlockData() instanceof Farmland farmland) {
|
||||
return farmland.getMoisture() > value;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
});
|
||||
registerCondition("moisture_less_than", (args) -> {
|
||||
int value = (int) args;
|
||||
return (block, offline) -> {
|
||||
Block underBlock = block.getLocation().copy().add(0,-1,0).getBukkitLocation().getBlock();
|
||||
if (underBlock.getBlockData() instanceof Farmland farmland) {
|
||||
return farmland.getMoisture() < value;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("ResultOfMethodCallIgnored")
|
||||
private void loadExpansions() {
|
||||
File expansionFolder = new File(plugin.getDataFolder(), EXPANSION_FOLDER);
|
||||
if (!expansionFolder.exists())
|
||||
expansionFolder.mkdirs();
|
||||
|
||||
List<Class<? extends ConditionExpansion>> classes = new ArrayList<>();
|
||||
File[] expansionJars = expansionFolder.listFiles();
|
||||
if (expansionJars == null) return;
|
||||
for (File expansionJar : expansionJars) {
|
||||
if (expansionJar.getName().endsWith(".jar")) {
|
||||
try {
|
||||
Class<? extends ConditionExpansion> expansionClass = ClassUtils.findClass(expansionJar, ConditionExpansion.class);
|
||||
classes.add(expansionClass);
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
LogUtils.warn("Failed to load expansion: " + expansionJar.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
for (Class<? extends ConditionExpansion> expansionClass : classes) {
|
||||
ConditionExpansion expansion = expansionClass.getDeclaredConstructor().newInstance();
|
||||
unregisterCondition(expansion.getConditionType());
|
||||
registerCondition(expansion.getConditionType(), expansion.getConditionFactory());
|
||||
LogUtils.info("Loaded condition expansion: " + expansion.getConditionType() + "[" + expansion.getVersion() + "]" + " by " + expansion.getAuthor());
|
||||
}
|
||||
} catch (InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException e) {
|
||||
LogUtils.warn("Error occurred when creating expansion instance.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +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.customcrops.mechanic.condition;
|
||||
|
||||
import net.momirealms.customcrops.api.mechanic.condition.Condition;
|
||||
import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock;
|
||||
|
||||
public class EmptyCondition implements Condition {
|
||||
|
||||
public static EmptyCondition instance = new EmptyCondition();
|
||||
|
||||
@Override
|
||||
public boolean isConditionMet(CustomCropsBlock block, boolean offline) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +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.customcrops.mechanic.item;
|
||||
|
||||
import net.momirealms.customcrops.api.common.item.EventItem;
|
||||
import net.momirealms.customcrops.api.manager.ActionManager;
|
||||
import net.momirealms.customcrops.api.mechanic.action.Action;
|
||||
import net.momirealms.customcrops.api.mechanic.action.ActionTrigger;
|
||||
import net.momirealms.customcrops.api.mechanic.requirement.State;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public abstract class AbstractEventItem implements EventItem {
|
||||
|
||||
private final HashMap<ActionTrigger, Action[]> actionMap;
|
||||
|
||||
public AbstractEventItem(HashMap<ActionTrigger, Action[]> actionMap) {
|
||||
this.actionMap = actionMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trigger(ActionTrigger actionTrigger, State state) {
|
||||
Action[] actions = actionMap.get(actionTrigger);
|
||||
if (actions != null) {
|
||||
ActionManager.triggerActions(state, actions);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,49 +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.customcrops.mechanic.item.custom.crucible;
|
||||
//
|
||||
//import net.momirealms.customcrops.mechanic.item.ItemManagerImpl;
|
||||
//import net.momirealms.customcrops.api.mechanic.item.custom.AbstractCustomListener;
|
||||
//import org.bukkit.event.EventHandler;
|
||||
//
|
||||
//public class CrucibleListener extends AbstractCustomListener {
|
||||
//
|
||||
// public CrucibleListener(ItemManagerImpl itemManager) {
|
||||
// super(itemManager);
|
||||
// }
|
||||
//
|
||||
// @EventHandler (ignoreCancelled = true)
|
||||
// public void onBreakCustomBlock() {
|
||||
// }
|
||||
//
|
||||
// @EventHandler (ignoreCancelled = true)
|
||||
// public void onPlaceCustomBlock() {
|
||||
// }
|
||||
//
|
||||
// @EventHandler (ignoreCancelled = true)
|
||||
// public void onPlaceFurniture() {
|
||||
// }
|
||||
//
|
||||
// @EventHandler (ignoreCancelled = true)
|
||||
// public void onBreakFurniture() {
|
||||
// }
|
||||
//
|
||||
// @EventHandler (ignoreCancelled = true)
|
||||
// public void onInteractFurniture() {
|
||||
// }
|
||||
//}
|
||||
@@ -1,124 +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.customcrops.mechanic.item.custom.crucible;
|
||||
//
|
||||
//import io.lumine.mythic.bukkit.BukkitAdapter;
|
||||
//import io.lumine.mythic.bukkit.adapters.BukkitEntity;
|
||||
//import io.lumine.mythiccrucible.MythicCrucible;
|
||||
//import io.lumine.mythiccrucible.items.CrucibleItem;
|
||||
//import io.lumine.mythiccrucible.items.ItemManager;
|
||||
//import io.lumine.mythiccrucible.items.blocks.CustomBlockItemContext;
|
||||
//import io.lumine.mythiccrucible.items.blocks.CustomBlockManager;
|
||||
//import io.lumine.mythiccrucible.items.furniture.Furniture;
|
||||
//import io.lumine.mythiccrucible.items.furniture.FurnitureManager;
|
||||
//import net.momirealms.customcrops.api.util.LogUtils;
|
||||
//import net.momirealms.customcrops.api.mechanic.item.custom.CustomProvider;
|
||||
//import org.bukkit.Location;
|
||||
//import org.bukkit.Material;
|
||||
//import org.bukkit.block.Block;
|
||||
//import org.bukkit.block.BlockFace;
|
||||
//import org.bukkit.entity.Entity;
|
||||
//import org.bukkit.inventory.ItemStack;
|
||||
//
|
||||
//import java.util.Optional;
|
||||
//
|
||||
//public class CrucibleProvider implements CustomProvider {
|
||||
//
|
||||
// private final ItemManager itemManager;
|
||||
// private final CustomBlockManager blockManager;
|
||||
// private final FurnitureManager furnitureManager;
|
||||
//
|
||||
// public CrucibleProvider() {
|
||||
// this.itemManager = MythicCrucible.inst().getItemManager();
|
||||
// this.blockManager = itemManager.getCustomBlockManager();
|
||||
// this.furnitureManager = itemManager.getFurnitureManager();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean removeBlock(Location location) {
|
||||
// Block block = location.getBlock();
|
||||
// if (block.getType() == Material.AIR) {
|
||||
// return false;
|
||||
// }
|
||||
// Optional<CustomBlockItemContext> optional = blockManager.getBlockFromBlock(block);
|
||||
// if (optional.isPresent()) {
|
||||
// optional.get().remove(block, null, false);
|
||||
// } else {
|
||||
// block.setType(Material.AIR);
|
||||
// }
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void placeCustomBlock(Location location, String id) {
|
||||
// Optional<CrucibleItem> optionalCI = itemManager.getItem(id);
|
||||
// if (optionalCI.isPresent()) {
|
||||
// location.getBlock().setBlockData(optionalCI.get().getBlockData().getBlockData());
|
||||
// } else {
|
||||
// LogUtils.warn("Custom block(" + id +") doesn't exist in Crucible configs. Please double check if that block exists.");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Entity placeFurniture(Location location, String id) {
|
||||
// Optional<CrucibleItem> optionalCI = itemManager.getItem(id);
|
||||
// if (optionalCI.isPresent()) {
|
||||
// return optionalCI.get().getFurnitureData().placeFrame(location.getBlock(), BlockFace.UP, 0f, null);
|
||||
// } else {
|
||||
// LogUtils.warn("Furniture(" + id +") doesn't exist in Crucible configs. Please double check if that furniture exists.");
|
||||
// return null;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void removeFurniture(Entity entity) {
|
||||
// Optional<Furniture> optional = furnitureManager.getFurniture(entity.getUniqueId());
|
||||
// optional.ifPresent(furniture -> furniture.getFurnitureData().remove(furniture, null, false, false));
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String getBlockID(Block block) {
|
||||
// Optional<CustomBlockItemContext> optionalCB = blockManager.getBlockFromBlock(block);
|
||||
// return optionalCB.map(customBlockItemContext -> customBlockItemContext.getCrucibleItem().getInternalName()).orElse(block.getType().name());
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String getItemID(ItemStack itemStack) {
|
||||
// return itemManager.getItem(itemStack).map(CrucibleItem::getInternalName).orElse(null);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public ItemStack getItemStack(String id) {
|
||||
// Optional<CrucibleItem> optionalCI = itemManager.getItem(id);
|
||||
// return optionalCI.map(crucibleItem -> BukkitAdapter.adapt(crucibleItem.getMythicItem().generateItemStack(1))).orElse(null);
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public String getEntityID(Entity entity) {
|
||||
// Optional<CrucibleItem> optionalCI = furnitureManager.getItemFromEntity(entity);
|
||||
// if (optionalCI.isPresent()) {
|
||||
// return optionalCI.get().getInternalName();
|
||||
// }
|
||||
// return entity.getType().name();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public boolean isFurniture(Entity entity) {
|
||||
// return furnitureManager.isFurniture(new BukkitEntity(entity));
|
||||
// }
|
||||
//}
|
||||
@@ -1,94 +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.customcrops.mechanic.item.custom.itemsadder;
|
||||
|
||||
import dev.lone.itemsadder.api.CustomFurniture;
|
||||
import dev.lone.itemsadder.api.Events.*;
|
||||
import net.momirealms.customcrops.api.mechanic.item.custom.AbstractCustomListener;
|
||||
import net.momirealms.customcrops.mechanic.item.ItemManagerImpl;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.EventHandler;
|
||||
|
||||
public class ItemsAdderListener extends AbstractCustomListener {
|
||||
|
||||
public ItemsAdderListener(ItemManagerImpl itemManager) {
|
||||
super(itemManager);
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onBreakCustomBlock(CustomBlockBreakEvent event) {
|
||||
this.itemManager.handlePlayerBreakBlock(
|
||||
event.getPlayer(),
|
||||
event.getBlock(),
|
||||
event.getNamespacedID(),
|
||||
event
|
||||
);
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onPlaceCustomBlock(CustomBlockPlaceEvent event) {
|
||||
super.onPlaceBlock(
|
||||
event.getPlayer(),
|
||||
event.getBlock(),
|
||||
event.getNamespacedID(),
|
||||
event
|
||||
);
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onPlaceFurniture(FurniturePlaceSuccessEvent event) {
|
||||
Entity entity = event.getBukkitEntity();
|
||||
if (entity == null) return;
|
||||
// player would be null if furniture is placed with API
|
||||
if (event.getPlayer() == null) return;
|
||||
super.onPlaceFurniture(
|
||||
event.getPlayer(),
|
||||
entity.getLocation(),
|
||||
event.getNamespacedID(),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onBreakFurniture(FurnitureBreakEvent event) {
|
||||
CustomFurniture customFurniture = event.getFurniture();
|
||||
if (customFurniture == null) return;
|
||||
Entity entity = customFurniture.getEntity();
|
||||
if (entity == null) return;
|
||||
super.onBreakFurniture(
|
||||
event.getPlayer(),
|
||||
entity.getLocation(),
|
||||
event.getNamespacedID(),
|
||||
event
|
||||
);
|
||||
}
|
||||
|
||||
@EventHandler (ignoreCancelled = true)
|
||||
public void onInteractFurniture(FurnitureInteractEvent event) {
|
||||
CustomFurniture customFurniture = event.getFurniture();
|
||||
if (customFurniture == null) return;
|
||||
Entity entity = customFurniture.getEntity();
|
||||
if (entity == null) return;
|
||||
super.onInteractFurniture(event.getPlayer(),
|
||||
entity.getLocation(),
|
||||
event.getNamespacedID(),
|
||||
entity,
|
||||
event
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,115 +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.customcrops.mechanic.item.custom.itemsadder;
|
||||
|
||||
import dev.lone.itemsadder.api.CustomBlock;
|
||||
import dev.lone.itemsadder.api.CustomFurniture;
|
||||
import dev.lone.itemsadder.api.CustomStack;
|
||||
import net.momirealms.customcrops.api.mechanic.item.custom.CustomProvider;
|
||||
import net.momirealms.customcrops.api.util.LogUtils;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class ItemsAdderProvider implements CustomProvider {
|
||||
|
||||
@Override
|
||||
public boolean removeBlock(Location location) {
|
||||
Block block = location.getBlock();
|
||||
if (block.getType() == Material.AIR)
|
||||
return false;
|
||||
if (!CustomBlock.remove(location)) {
|
||||
block.setType(Material.AIR);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void placeCustomBlock(Location location, String id) {
|
||||
CustomBlock block = CustomBlock.place(id, location);
|
||||
if (block == null) {
|
||||
LogUtils.warn("Detected that custom block(" + id + ") doesn't exist in ItemsAdder configs. Please double check if that block exists.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity placeFurniture(Location location, String id) {
|
||||
try {
|
||||
CustomFurniture furniture = CustomFurniture.spawnPreciseNonSolid(id, location);
|
||||
if (furniture == null) return null;
|
||||
return furniture.getEntity();
|
||||
} catch (RuntimeException e) {
|
||||
LogUtils.warn("Failed to place ItemsAdder furniture. If this is not a problem caused by furniture not existing, consider increasing max-furniture-vehicles-per-chunk in ItemsAdder config.yml.");
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeFurniture(Entity entity) {
|
||||
CustomFurniture.remove(entity, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBlockID(Block block) {
|
||||
CustomBlock customBlock = CustomBlock.byAlreadyPlaced(block);
|
||||
if (customBlock == null) {
|
||||
return block.getType().name();
|
||||
}
|
||||
return customBlock.getNamespacedID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemID(ItemStack itemInHand) {
|
||||
CustomStack customStack = CustomStack.byItemStack(itemInHand);
|
||||
if (customStack == null) {
|
||||
return null;
|
||||
}
|
||||
return customStack.getNamespacedID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getItemStack(String id) {
|
||||
if (id == null) return new ItemStack(Material.AIR);
|
||||
CustomStack customStack = CustomStack.getInstance(id);
|
||||
if (customStack == null) {
|
||||
return null;
|
||||
}
|
||||
return customStack.getItemStack().clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntityID(Entity entity) {
|
||||
CustomFurniture customFurniture = CustomFurniture.byAlreadySpawned(entity);
|
||||
if (customFurniture == null) {
|
||||
return entity.getType().name();
|
||||
}
|
||||
return customFurniture.getNamespacedID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFurniture(Entity entity) {
|
||||
try {
|
||||
return CustomFurniture.byAlreadySpawned(entity) != null;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
package net.momirealms.customcrops.mechanic.item.factory;
|
||||
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class AbstractItem<R, I> implements Item<I> {
|
||||
|
||||
private final CustomCropsPlugin plugin;
|
||||
private final ItemFactory<?, R, I> factory;
|
||||
private final R item;
|
||||
|
||||
AbstractItem(CustomCropsPlugin plugin, ItemFactory<?, R, I> factory, R item) {
|
||||
this.plugin = plugin;
|
||||
this.factory = factory;
|
||||
this.item = item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item<I> customModelData(Integer data) {
|
||||
factory.customModelData(item, data);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> customModelData() {
|
||||
return factory.customModelData(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item<I> damage(Integer data) {
|
||||
factory.damage(item, data);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> damage() {
|
||||
return factory.damage(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item<I> maxDamage(Integer data) {
|
||||
factory.maxDamage(item, data);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> maxDamage() {
|
||||
return factory.maxDamage(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item<I> lore(List<String> lore) {
|
||||
factory.lore(item, lore);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<List<String>> lore() {
|
||||
return factory.lore(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Object> getTag(Object... path) {
|
||||
return factory.getTag(item, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Item<I> setTag(Object value, Object... path) {
|
||||
factory.setTag(item, value, path);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTag(Object... path) {
|
||||
return factory.hasTag(item, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeTag(Object... path) {
|
||||
return factory.removeTag(item, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public I getItem() {
|
||||
return factory.getItem(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public I load() {
|
||||
return factory.load(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public I loadCopy() {
|
||||
return factory.loadCopy(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
factory.update(item);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package net.momirealms.customcrops.mechanic.item.factory;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
|
||||
public class ComponentKeys {
|
||||
|
||||
public static final String CUSTOM_MODEL_DATA = Key.key("minecraft", "custom_model_data").asString();
|
||||
public static final String MAX_DAMAGE = Key.key("minecraft", "max_damage").asString();
|
||||
public static final String CUSTOM_NAME = Key.key("minecraft", "custom_name").asString();
|
||||
public static final String LORE = Key.key("minecraft", "lore").asString();
|
||||
public static final String DAMAGE = Key.key("minecraft", "damage").asString();
|
||||
public static final String ENCHANTMENT_GLINT_OVERRIDE = Key.key("minecraft", "enchantment_glint_override").asString();
|
||||
public static final String HIDE_TOOLTIP = Key.key("minecraft", "hide_tooltip").asString();
|
||||
public static final String MAX_STACK_SIZE = Key.key("minecraft", "max_stack_size").asString();
|
||||
public static final String PROFILE = Key.key("minecraft", "profile").asString();
|
||||
public static final String UNBREAKABLE = Key.key("minecraft", "unbreakable").asString();
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package net.momirealms.customcrops.mechanic.item.factory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface Item<I> {
|
||||
|
||||
Item<I> customModelData(Integer data);
|
||||
|
||||
Optional<Integer> customModelData();
|
||||
|
||||
Item<I> damage(Integer data);
|
||||
|
||||
Optional<Integer> damage();
|
||||
|
||||
Item<I> maxDamage(Integer data);
|
||||
|
||||
Optional<Integer> maxDamage();
|
||||
|
||||
Item<I> lore(List<String> lore);
|
||||
|
||||
Optional<List<String>> lore();
|
||||
|
||||
Optional<Object> getTag(Object... path);
|
||||
|
||||
Item<I> setTag(Object value, Object... path);
|
||||
|
||||
boolean hasTag(Object... path);
|
||||
|
||||
boolean removeTag(Object... path);
|
||||
|
||||
I getItem();
|
||||
|
||||
I load();
|
||||
|
||||
I loadCopy();
|
||||
|
||||
void update();
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package net.momirealms.customcrops.mechanic.item.factory;
|
||||
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
public abstract class ItemFactory<P extends CustomCropsPlugin, R, I> {
|
||||
|
||||
protected final P plugin;
|
||||
|
||||
protected ItemFactory(P plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public Item<I> wrap(R item) {
|
||||
Objects.requireNonNull(item, "item");
|
||||
return new AbstractItem<>(this.plugin, this, item);
|
||||
}
|
||||
|
||||
protected abstract Optional<Object> getTag(R item, Object... path);
|
||||
|
||||
protected abstract void setTag(R item, Object value, Object... path);
|
||||
|
||||
protected abstract boolean hasTag(R item, Object... path);
|
||||
|
||||
protected abstract boolean removeTag(R item, Object... path);
|
||||
|
||||
protected abstract void update(R item);
|
||||
|
||||
protected abstract I load(R item);
|
||||
|
||||
protected abstract I getItem(R item);
|
||||
|
||||
protected abstract I loadCopy(R item);
|
||||
|
||||
protected abstract Optional<Integer> customModelData(R item);
|
||||
|
||||
protected abstract void customModelData(R item, Integer data);
|
||||
|
||||
protected abstract Optional<List<String>> lore(R item);
|
||||
|
||||
protected abstract void lore(R item, List<String> lore);
|
||||
|
||||
protected abstract Optional<Integer> maxDamage(R item);
|
||||
|
||||
protected abstract void maxDamage(R item, Integer data);
|
||||
|
||||
protected abstract Optional<Integer> damage(R item);
|
||||
|
||||
protected abstract void damage(R item, Integer data);
|
||||
}
|
||||
@@ -1,76 +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.customcrops.mechanic.item.function;
|
||||
|
||||
import net.momirealms.customcrops.mechanic.item.function.wrapper.ConditionWrapper;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
public class CFunction implements Comparable<CFunction> {
|
||||
|
||||
private static int functionID = 0;
|
||||
private final Function<ConditionWrapper, FunctionResult> function;
|
||||
private final FunctionPriority priority;
|
||||
private final int id;
|
||||
|
||||
public CFunction(Function<ConditionWrapper, FunctionResult> function, FunctionPriority priority) {
|
||||
this.function = function;
|
||||
this.priority = priority;
|
||||
this.id = functionID++;
|
||||
}
|
||||
|
||||
public FunctionResult apply(ConditionWrapper wrapper) {
|
||||
return function.apply(wrapper);
|
||||
}
|
||||
|
||||
public Function<ConditionWrapper, FunctionResult> getFunction() {
|
||||
return function;
|
||||
}
|
||||
|
||||
public FunctionPriority getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull CFunction o) {
|
||||
if (this.priority.ordinal() > o.priority.ordinal()) {
|
||||
return 1;
|
||||
} else if (this.priority.ordinal() < o.priority.ordinal()) {
|
||||
return -1;
|
||||
}
|
||||
return Integer.compare(this.id, o.id);
|
||||
}
|
||||
|
||||
public static void resetID() {
|
||||
functionID = 0;
|
||||
}
|
||||
|
||||
public enum FunctionPriority {
|
||||
|
||||
HIGHEST,
|
||||
HIGH,
|
||||
NORMAL,
|
||||
LOW,
|
||||
LOWEST;
|
||||
|
||||
public boolean isHigherThan(FunctionPriority priority) {
|
||||
return this.ordinal() < priority.ordinal();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +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.customcrops.mechanic.item.function;
|
||||
|
||||
public enum FunctionResult {
|
||||
|
||||
PASS,
|
||||
RETURN,
|
||||
CANCEL_EVENT_AND_RETURN
|
||||
}
|
||||
@@ -1,26 +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.customcrops.mechanic.item.function;
|
||||
|
||||
public enum FunctionTrigger {
|
||||
PLACE,
|
||||
BREAK,
|
||||
BE_INTERACTED,
|
||||
INTERACT_AT,
|
||||
INTERACT_AIR
|
||||
}
|
||||
@@ -1,36 +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.customcrops.mechanic.item.function.wrapper;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class BreakBlockWrapper extends BreakWrapper {
|
||||
|
||||
private final Block brokenBlock;
|
||||
|
||||
public BreakBlockWrapper(Player player, Block brokenBlock) {
|
||||
super(player, brokenBlock.getLocation());
|
||||
this.brokenBlock = brokenBlock;
|
||||
}
|
||||
|
||||
public Block getBrokenBlock() {
|
||||
return brokenBlock;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +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.customcrops.mechanic.item.function.wrapper;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class BreakFurnitureWrapper extends BreakWrapper {
|
||||
|
||||
private final Location location;
|
||||
private final String id;
|
||||
|
||||
public BreakFurnitureWrapper(Player player, Location location, String id) {
|
||||
super(player, location);
|
||||
this.location = location;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +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.customcrops.mechanic.item.function.wrapper;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class BreakWrapper extends ConditionWrapper {
|
||||
|
||||
private final Location location;
|
||||
|
||||
public BreakWrapper(Player player, Location location) {
|
||||
super(player);
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
}
|
||||
@@ -1,40 +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.customcrops.mechanic.item.function.wrapper;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public abstract class ConditionWrapper {
|
||||
|
||||
private final Player player;
|
||||
private final ItemStack itemInHand;
|
||||
|
||||
public ConditionWrapper(Player player) {
|
||||
this.player = player;
|
||||
this.itemInHand = player.getInventory().getItemInMainHand();
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public ItemStack getItemInHand() {
|
||||
return itemInHand;
|
||||
}
|
||||
}
|
||||
@@ -1,42 +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.customcrops.mechanic.item.function.wrapper;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class InteractBlockWrapper extends InteractWrapper {
|
||||
|
||||
private final Block clickedBlock;
|
||||
private final BlockFace clickedFace;
|
||||
|
||||
public InteractBlockWrapper(Player player, Block clickedBlock, BlockFace clickedFace) {
|
||||
super(player, clickedBlock.getLocation());
|
||||
this.clickedBlock = clickedBlock;
|
||||
this.clickedFace = clickedFace;
|
||||
}
|
||||
|
||||
public Block getClickedBlock() {
|
||||
return clickedBlock;
|
||||
}
|
||||
|
||||
public BlockFace getClickedFace() {
|
||||
return clickedFace;
|
||||
}
|
||||
}
|
||||
@@ -1,46 +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.customcrops.mechanic.item.function.wrapper;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class InteractFurnitureWrapper extends InteractWrapper {
|
||||
|
||||
private final String id;
|
||||
private final Entity entity;
|
||||
|
||||
public InteractFurnitureWrapper(Player player, Location location, String id, @Nullable Entity baseEntity) {
|
||||
super(player, location);
|
||||
this.entity = baseEntity;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Entity getEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +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.customcrops.mechanic.item.function.wrapper;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class InteractWrapper extends ConditionWrapper {
|
||||
|
||||
private final Location location;
|
||||
|
||||
public InteractWrapper(Player player, Location location) {
|
||||
super(player);
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
}
|
||||
@@ -1,36 +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.customcrops.mechanic.item.function.wrapper;
|
||||
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class PlaceBlockWrapper extends PlaceWrapper {
|
||||
|
||||
private final Block placedBlock;
|
||||
|
||||
public PlaceBlockWrapper(Player player, Block placedBlock, String blockID) {
|
||||
super(player, placedBlock.getLocation(), blockID);
|
||||
this.placedBlock = placedBlock;
|
||||
}
|
||||
|
||||
public Block getPlacedBlock() {
|
||||
return placedBlock;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +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.customcrops.mechanic.item.function.wrapper;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class PlaceFurnitureWrapper extends PlaceWrapper {
|
||||
|
||||
public PlaceFurnitureWrapper(Player player, Location location, String id) {
|
||||
super(player, location, id);
|
||||
}
|
||||
}
|
||||
@@ -1,42 +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.customcrops.mechanic.item.function.wrapper;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class PlaceWrapper extends ConditionWrapper {
|
||||
|
||||
private final Location location;
|
||||
private final String id;
|
||||
|
||||
public PlaceWrapper(Player player, Location location, String id) {
|
||||
super(player);
|
||||
this.location = location;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,102 +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.customcrops.mechanic.item.impl;
|
||||
|
||||
import net.momirealms.customcrops.api.mechanic.action.Action;
|
||||
import net.momirealms.customcrops.api.mechanic.action.ActionTrigger;
|
||||
import net.momirealms.customcrops.api.mechanic.item.Fertilizer;
|
||||
import net.momirealms.customcrops.api.mechanic.item.FertilizerType;
|
||||
import net.momirealms.customcrops.api.mechanic.requirement.Requirement;
|
||||
import net.momirealms.customcrops.mechanic.item.AbstractEventItem;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class AbstractFertilizer extends AbstractEventItem implements Fertilizer {
|
||||
|
||||
private final String key;
|
||||
private final String itemID;
|
||||
private final int times;
|
||||
private final FertilizerType fertilizerType;
|
||||
private final HashSet<String> potWhitelist;
|
||||
private final boolean beforePlant;
|
||||
private final String icon;
|
||||
private final Requirement[] requirements;
|
||||
|
||||
public AbstractFertilizer(
|
||||
String key,
|
||||
String itemID,
|
||||
int times,
|
||||
FertilizerType fertilizerType,
|
||||
HashSet<String> potWhitelist,
|
||||
boolean beforePlant,
|
||||
String icon,
|
||||
Requirement[] requirements,
|
||||
HashMap<ActionTrigger, Action[]> actionMap
|
||||
) {
|
||||
super(actionMap);
|
||||
this.key = key;
|
||||
this.itemID = itemID;
|
||||
this.times = times;
|
||||
this.fertilizerType = fertilizerType;
|
||||
this.potWhitelist = potWhitelist;
|
||||
this.beforePlant = beforePlant;
|
||||
this.icon = icon;
|
||||
this.requirements = requirements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemID() {
|
||||
return itemID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimes() {
|
||||
return times;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FertilizerType getFertilizerType() {
|
||||
return fertilizerType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<String> getPotWhitelist() {
|
||||
return potWhitelist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBeforePlant() {
|
||||
return beforePlant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Requirement[] getRequirements() {
|
||||
return requirements;
|
||||
}
|
||||
}
|
||||
@@ -1,241 +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.customcrops.mechanic.item.impl;
|
||||
|
||||
import net.momirealms.customcrops.api.CustomCropsPlugin;
|
||||
import net.momirealms.customcrops.api.mechanic.action.Action;
|
||||
import net.momirealms.customcrops.api.mechanic.action.ActionTrigger;
|
||||
import net.momirealms.customcrops.api.mechanic.condition.Conditions;
|
||||
import net.momirealms.customcrops.api.mechanic.condition.DeathConditions;
|
||||
import net.momirealms.customcrops.api.mechanic.item.BoneMeal;
|
||||
import net.momirealms.customcrops.api.mechanic.item.Crop;
|
||||
import net.momirealms.customcrops.api.mechanic.item.ItemCarrier;
|
||||
import net.momirealms.customcrops.api.mechanic.requirement.Requirement;
|
||||
import net.momirealms.customcrops.mechanic.item.AbstractEventItem;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class CropConfig extends AbstractEventItem implements Crop {
|
||||
|
||||
private final String key;
|
||||
private final String seedID;
|
||||
private final int maxPoints;
|
||||
private final boolean rotation;
|
||||
private final ItemCarrier carrier;
|
||||
private final Requirement[] plantRequirements;
|
||||
private final Requirement[] breakRequirements;
|
||||
private final Requirement[] interactRequirements;
|
||||
private final BoneMeal[] boneMeals;
|
||||
private final Conditions growConditions;
|
||||
private final HashSet<String> whitelistPots;
|
||||
private final DeathConditions[] deathConditions;
|
||||
private final HashMap<Integer, CropStageConfig> point2StageConfigMap;
|
||||
private final HashMap<String, CropStageConfig> item2StageConfigMap;
|
||||
|
||||
public CropConfig(
|
||||
String key,
|
||||
String seedID,
|
||||
ItemCarrier carrier,
|
||||
HashSet<String> whitelistPots,
|
||||
boolean rotation,
|
||||
int maxPoints,
|
||||
BoneMeal[] boneMeals,
|
||||
Conditions growConditions,
|
||||
DeathConditions[] deathConditions,
|
||||
HashMap<ActionTrigger, Action[]> actionMap,
|
||||
HashMap<Integer, CropStageConfig> point2StageConfigMap,
|
||||
Requirement[] plantRequirements,
|
||||
Requirement[] breakRequirements,
|
||||
Requirement[] interactRequirements
|
||||
) {
|
||||
super(actionMap);
|
||||
this.key = key;
|
||||
this.seedID = seedID;
|
||||
this.boneMeals = boneMeals;
|
||||
this.rotation = rotation;
|
||||
this.maxPoints = maxPoints;
|
||||
this.growConditions = growConditions;
|
||||
this.deathConditions = deathConditions;
|
||||
this.plantRequirements = plantRequirements;
|
||||
this.breakRequirements = breakRequirements;
|
||||
this.interactRequirements = interactRequirements;
|
||||
this.point2StageConfigMap = point2StageConfigMap;
|
||||
this.whitelistPots = whitelistPots;
|
||||
this.carrier = carrier;
|
||||
this.item2StageConfigMap = new HashMap<>();
|
||||
for (CropStageConfig cropStageConfig : point2StageConfigMap.values()) {
|
||||
if (cropStageConfig.getStageID() != null) {
|
||||
this.item2StageConfigMap.put(cropStageConfig.getStageID(), cropStageConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSeedItemID() {
|
||||
return seedID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxPoints() {
|
||||
return maxPoints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Requirement[] getPlantRequirements() {
|
||||
return plantRequirements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Requirement[] getBreakRequirements() {
|
||||
return breakRequirements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Requirement[] getInteractRequirements() {
|
||||
return interactRequirements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Conditions getGrowConditions() {
|
||||
return growConditions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeathConditions[] getDeathConditions() {
|
||||
return deathConditions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoneMeal[] getBoneMeals() {
|
||||
return boneMeals;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRotation() {
|
||||
return rotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stage getStageByPoint(int point) {
|
||||
return point2StageConfigMap.get(point);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getStageItemByPoint(int point) {
|
||||
if (point >= 0) {
|
||||
Stage stage = point2StageConfigMap.get(point);
|
||||
if (stage != null) {
|
||||
String id = stage.getStageID();
|
||||
if (id == null) return getStageItemByPoint(point-1);
|
||||
return id;
|
||||
} else {
|
||||
return getStageItemByPoint(point-1);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stage getStageByItemID(String itemID) {
|
||||
return item2StageConfigMap.get(itemID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends Stage> getStages() {
|
||||
return new ArrayList<>(point2StageConfigMap.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashSet<String> getPotWhitelist() {
|
||||
return whitelistPots;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemCarrier getItemCarrier() {
|
||||
return carrier;
|
||||
}
|
||||
|
||||
public static class CropStageConfig extends AbstractEventItem implements Crop.Stage {
|
||||
|
||||
@Nullable
|
||||
private final String stageID;
|
||||
|
||||
private final int point;
|
||||
private final double hologramOffset;
|
||||
private final Requirement[] interactRequirements;
|
||||
private final Requirement[] breakRequirements;
|
||||
|
||||
public CropStageConfig(
|
||||
@Nullable String stageID,
|
||||
int point,
|
||||
double hologramOffset,
|
||||
HashMap<ActionTrigger, Action[]> actionMap,
|
||||
Requirement[] interactRequirements,
|
||||
Requirement[] breakRequirements
|
||||
) {
|
||||
super(actionMap);
|
||||
this.stageID = stageID;
|
||||
this.point = point;
|
||||
this.hologramOffset = hologramOffset;
|
||||
this.interactRequirements = interactRequirements;
|
||||
this.breakRequirements = breakRequirements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Crop getCrop() {
|
||||
return CustomCropsPlugin.get().getItemManager().getCropByStageID(stageID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getHologramOffset() {
|
||||
return hologramOffset;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getStageID() {
|
||||
return stageID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPoint() {
|
||||
return point;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Requirement[] getInteractRequirements() {
|
||||
return interactRequirements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Requirement[] getBreakRequirements() {
|
||||
return breakRequirements;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user