9
0
mirror of https://github.com/Xiao-MoMi/Custom-Crops.git synced 2025-12-26 18:39:17 +00:00

migration system

This commit is contained in:
XiaoMoMi
2024-03-10 04:24:15 +08:00
parent 19a0080aae
commit 0f18904de0
41 changed files with 1403 additions and 95 deletions

View File

@@ -34,6 +34,7 @@ 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.misc.migrator.Migration;
import net.momirealms.customcrops.mechanic.requirement.RequirementManagerImpl;
import net.momirealms.customcrops.mechanic.world.WorldManagerImpl;
import net.momirealms.customcrops.scheduler.SchedulerImpl;
@@ -102,6 +103,7 @@ public class CustomCropsPluginImpl extends CustomCropsPlugin {
this.antiGriefLib.init();
this.integrationManager.init();
this.disableNBTAPILogs();
Migration.tryUpdating();
this.reload();
this.worldManager.init();
if (ConfigManager.metrics()) new Metrics(this, 16593);

View File

@@ -17,6 +17,12 @@
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.util.LogUtils;
@@ -26,12 +32,14 @@ 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.Objects;
public class ConfigManagerImpl extends ConfigManager {
private static final String configVersion = "35";
public static final String configVersion = "35";
private CustomCropsPlugin plugin;
private String lang;
private int maximumPoolSize;
@@ -54,6 +62,7 @@ public class ConfigManagerImpl extends ConfigManager {
private int scarecrowRange;
private boolean syncSeasons;
private WeakReference<World> referenceWorld;
private boolean convertWorldOnLoad;
public ConfigManagerImpl(CustomCropsPlugin plugin) {
this.plugin = plugin;
@@ -61,6 +70,29 @@ public class ConfigManagerImpl extends ConfigManager {
@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");
@@ -80,6 +112,7 @@ public class ConfigManagerImpl extends ConfigManager {
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) {
@@ -129,6 +162,11 @@ public class ConfigManagerImpl extends ConfigManager {
return keepAliveTime;
}
@Override
protected boolean isConvertWorldOnLoad() {
return convertWorldOnLoad;
}
@Override
protected double[] getDefaultQualityRatio() {
return defaultQualityRatio;

View File

@@ -118,6 +118,7 @@ public class ActionManagerImpl implements ActionManager {
this.registerVariationAction();
this.registerForceTickAction();
this.registerHologramAction();
this.registerLegacyDropItemsAction();
}
@Override
@@ -536,7 +537,7 @@ public class ActionManagerImpl implements ActionManager {
}
private void registerDropItemsAction() {
registerAction("drop-items", (args, chance) -> {
registerAction("drop-item", (args, chance) -> {
if (args instanceof ConfigurationSection section) {
boolean ignoreFertilizer = section.getBoolean("ignore-fertilizer", true);
String item = section.getString("item");
@@ -574,64 +575,95 @@ public class ActionManagerImpl implements ActionManager {
});
}
private void registerPlantAction() {
registerAction("plant", (args, chance) -> {
private void registerLegacyDropItemsAction() {
registerAction("drop-items", (args, chance) -> {
if (args instanceof ConfigurationSection section) {
int point = section.getInt("point", 0);
String key = section.getString("crop");
return state -> {
if (Math.random() > chance) return;
if (key == null) return;
Crop crop = plugin.getItemManager().getCropByID(key);
if (crop == null) {
LogUtils.warn("Crop: " + key + " doesn't exist.");
return;
}
Location location = state.getLocation();
Pot pot = plugin.getItemManager().getPotByBlock(location.getBlock().getRelative(BlockFace.DOWN));
if (pot == null) {
plugin.debug("Crop should be planted on a pot at " + location);
return;
}
// check whitelist
if (!crop.getPotWhitelist().contains(pot.getKey())) {
crop.trigger(ActionTrigger.WRONG_POT, state);
return;
}
// check plant requirements
if (!RequirementManager.isRequirementMet(state, crop.getPlantRequirements())) {
return;
}
// check limitation
if (plugin.getWorldManager().isReachLimit(SimpleLocation.of(location), ItemType.CROP)) {
crop.trigger(ActionTrigger.REACH_LIMIT, state);
return;
}
// fire event
CropPlantEvent plantEvent = new CropPlantEvent(state.getPlayer(), state.getItemInHand(), location, crop, 0);
if (EventUtils.fireAndCheckCancel(plantEvent)) {
return;
}
// place the crop
switch (crop.getItemCarrier()) {
case ITEM_FRAME, ITEM_DISPLAY, TRIPWIRE -> plugin.getItemManager().placeItem(location, crop.getItemCarrier(), crop.getStageItemByPoint(point));
default -> {
LogUtils.warn("Unsupported type for crop: " + crop.getItemCarrier().name());
return;
List<Action> actions = new ArrayList<>();
ConfigurationSection otherItemSection = section.getConfigurationSection("other-items");
if (otherItemSection != null) {
for (Map.Entry<String, Object> entry : otherItemSection.getValues(false).entrySet()) {
if (entry.getValue() instanceof ConfigurationSection inner) {
actions.add(getActionFactory("drop-item").build(inner, inner.getDouble("chance", 1)));
}
}
plugin.getWorldManager().addCropAt(new MemoryCrop(SimpleLocation.of(location), crop.getKey(), point), SimpleLocation.of(location));
}
ConfigurationSection qualitySection = section.getConfigurationSection("quality-crops");
if (qualitySection != null) {
actions.add(getActionFactory("quality-crops").build(qualitySection, 1));
}
return state -> {
if (Math.random() > chance) return;
for (Action action : actions) {
action.trigger(state);
}
};
} else {
LogUtils.warn("Illegal value format found at action: plant");
LogUtils.warn("Illegal value format found at action: drop-items");
return EmptyAction.instance;
}
});
}
private void registerPlantAction() {
for (String name : List.of("plant", "replant")) {
registerAction(name, (args, chance) -> {
if (args instanceof ConfigurationSection section) {
int point = section.getInt("point", 0);
String key = section.getString("crop");
return state -> {
if (Math.random() > chance) return;
if (key == null) return;
Crop crop = plugin.getItemManager().getCropByID(key);
if (crop == null) {
LogUtils.warn("Crop: " + key + " doesn't exist.");
return;
}
Location location = state.getLocation();
Pot pot = plugin.getItemManager().getPotByBlock(location.getBlock().getRelative(BlockFace.DOWN));
if (pot == null) {
plugin.debug("Crop should be planted on a pot at " + location);
return;
}
// check whitelist
if (!crop.getPotWhitelist().contains(pot.getKey())) {
crop.trigger(ActionTrigger.WRONG_POT, state);
return;
}
// check plant requirements
if (!RequirementManager.isRequirementMet(state, crop.getPlantRequirements())) {
return;
}
// check limitation
if (plugin.getWorldManager().isReachLimit(SimpleLocation.of(location), ItemType.CROP)) {
crop.trigger(ActionTrigger.REACH_LIMIT, state);
return;
}
// fire event
CropPlantEvent plantEvent = new CropPlantEvent(state.getPlayer(), state.getItemInHand(), location, crop, 0);
if (EventUtils.fireAndCheckCancel(plantEvent)) {
return;
}
// place the crop
switch (crop.getItemCarrier()) {
case ITEM_FRAME, ITEM_DISPLAY, TRIPWIRE -> plugin.getItemManager().placeItem(location, crop.getItemCarrier(), crop.getStageItemByPoint(point));
default -> {
LogUtils.warn("Unsupported type for crop: " + crop.getItemCarrier().name());
return;
}
}
plugin.getWorldManager().addCropAt(new MemoryCrop(SimpleLocation.of(location), crop.getKey(), point), SimpleLocation.of(location));
};
} else {
LogUtils.warn("Illegal value format found at action: " + name);
return EmptyAction.instance;
}
});
}
}
private void registerBreakAction() {
registerAction("break", (args, chance) -> {
boolean arg = (boolean) args;
boolean arg = (boolean) (args == null ? true : args);
return state -> {
if (Math.random() > chance) return;
Optional<CustomCropsBlock> removed = plugin.getWorldManager().getBlockAt(SimpleLocation.of(state.getLocation()));
@@ -746,19 +778,13 @@ public class ActionManagerImpl implements ActionManager {
private void registerItemAmountAction() {
registerAction("item-amount", (args, chance) -> {
if (args instanceof ConfigurationSection section) {
boolean mainOrOff = section.getString("hand", "main").equalsIgnoreCase("main");
int amount = section.getInt("amount", 1);
return state -> {
if (Math.random() > chance) return;
Player player = state.getPlayer();
ItemStack itemStack = mainOrOff ? player.getInventory().getItemInMainHand() : player.getInventory().getItemInOffHand();
itemStack.setAmount(Math.max(0, itemStack.getAmount() + amount));
};
} else {
LogUtils.warn("Illegal value format found at action: item-amount");
return EmptyAction.instance;
}
int amount = (int) args;
return state -> {
if (Math.random() > chance) return;
Player player = state.getPlayer();
ItemStack itemStack = player.getInventory().getItemInMainHand();
itemStack.setAmount(Math.max(0, itemStack.getAmount() + amount));
};
});
}

View File

@@ -43,7 +43,7 @@ public interface CustomProvider {
}
}
void placeFurniture(Location location, String id);
Entity placeFurniture(Location location, String id);
void removeFurniture(Entity entity);

View File

@@ -56,15 +56,17 @@ import net.momirealms.customcrops.mechanic.world.block.*;
import net.momirealms.customcrops.utils.ConfigUtils;
import net.momirealms.customcrops.utils.EventUtils;
import net.momirealms.customcrops.utils.ItemUtils;
import net.momirealms.customcrops.utils.RotationUtils;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.block.data.type.Farmland;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemDisplay;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
@@ -334,6 +336,25 @@ public class ItemManagerImpl implements ItemManager {
}
}
@Override
public void placeItem(Location location, ItemCarrier carrier, String id, boolean rotate) {
switch (carrier) {
case ITEM_DISPLAY, ITEM_FRAME -> {
Entity entity = customProvider.placeFurniture(location, id);
if (rotate) {
if (entity instanceof ItemFrame frame) {
frame.setRotation(RotationUtils.getRandomRotation());
} else if (entity instanceof ItemDisplay display) {
display.setRotation(RotationUtils.getRandomFloatRotation(), display.getLocation().getPitch());
}
}
}
case TRIPWIRE, NOTE_BLOCK, CHORUS, MUSHROOM -> {
customProvider.placeBlock(location, id);
}
}
}
@Override
public void removeAnythingAt(Location location) {
customProvider.removeAnythingAt(location);

View File

@@ -46,8 +46,12 @@ public class ItemsAdderProvider implements CustomProvider {
}
@Override
public void placeFurniture(Location location, String id) {
CustomFurniture.spawnPreciseNonSolid(id, location);
public Entity placeFurniture(Location location, String id) {
Location center = location.toCenterLocation();
center.setY(center.getBlockY());
CustomFurniture furniture = CustomFurniture.spawnPreciseNonSolid(id, location);
if (furniture == null) return null;
return furniture.getEntity();
}
@Override

View File

@@ -52,8 +52,10 @@ public class OraxenProvider implements CustomProvider {
}
@Override
public void placeFurniture(Location location, String id) {
OraxenFurniture.place(id, location, Rotation.NONE, BlockFace.UP);
public Entity placeFurniture(Location location, String id) {
Location center = location.toCenterLocation();
center.setY(center.getBlockY());
return OraxenFurniture.place(id, location, Rotation.NONE, BlockFace.UP);
}
@Override

View File

@@ -134,7 +134,7 @@ public class CropConfig extends AbstractEventItem implements Crop {
}
@Override
public boolean isRotation() {
public boolean hasRotation() {
return rotation;
}

View File

@@ -0,0 +1,456 @@
package net.momirealms.customcrops.mechanic.misc.migrator;
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.mechanic.world.level.WorldSetting;
import net.momirealms.customcrops.api.util.LogUtils;
import net.momirealms.customcrops.mechanic.world.CWorld;
import net.momirealms.customcrops.mechanic.world.adaptor.BukkitWorldAdaptor;
import net.momirealms.customcrops.utils.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.util.Map;
import java.util.Objects;
public class Migration {
public static void tryUpdating() {
File configFile = new File(CustomCropsPlugin.getInstance().getDataFolder(), "config.yml");
// If not config file found, do nothing
if (!configFile.exists()) return;
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
String version = config.getString("config-version");
if (version == null) return;
int versionNumber = Integer.parseInt(version);
if (!(versionNumber >= 25 && versionNumber <= 34)) {
return;
}
// do migration
if (config.contains("mechanics.season.sync-season")) {
config.set("mechanics.sync-season.enable", config.getBoolean("mechanics.season.sync-season.enable"));
config.set("mechanics.sync-season.reference", config.getBoolean("mechanics.season.sync-season.reference"));
}
if (config.contains("mechanics.season.greenhouse")) {
config.set("mechanics.greenhouse.enable", config.getBoolean("mechanics.season.greenhouse.enable"));
config.set("mechanics.greenhouse.id", config.getString("mechanics.season.greenhouse.block"));
config.set("mechanics.greenhouse.range", config.getInt("mechanics.season.greenhouse.range"));
}
if (config.contains("mechanics.scarecrow")) {
config.set("mechanics.scarecrow.id", config.getString("mechanics.scarecrow"));
}
try {
config.save(configFile);
} catch (IOException e) {
e.printStackTrace();
}
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"))
.build()
);
} catch (IOException e) {
LogUtils.warn(e.getMessage());
}
updateWateringCans();
updatePots();
updateFertilizers();
updateSprinklers();
updateCrops();
if (CustomCropsPlugin.get().getWorldManager().getWorldAdaptor() instanceof BukkitWorldAdaptor adaptor) {
for (World world : Bukkit.getWorlds()) {
CWorld temp = new CWorld(CustomCropsPlugin.getInstance().getWorldManager(), world);
temp.setWorldSetting(WorldSetting.of(false,300,true, 1,true,2,true,2,false,false,false,28,-1,-1,-1, 0));
adaptor.convertWorld(temp, world);
}
}
}
private static void updateWateringCans() {
var files = ConfigUtils.getFilesRecursively(new File(CustomCropsPlugin.getInstance().getDataFolder(), "contents" + File.separator + "watering-cans"));
for (File file : files) {
YamlConfiguration yaml = YamlConfiguration.loadConfiguration(file);
for (Map.Entry<String, Object> sections : yaml.getValues(false).entrySet()) {
if (sections.getValue() instanceof ConfigurationSection section) {
ConfigurationSection fillSection = section.getConfigurationSection("fill-method");
if (fillSection != null) {
for (String key : fillSection.getKeys(false)) {
fillSection.set(key + ".particle", null);
fillSection.set(key + ".sound", null);
}
}
if (section.contains("sound")) {
section.set("events.consume_water.sound_action.type", "sound");
section.set("events.consume_water.sound_action.value.key", section.getString("sound"));
section.set("events.consume_water.sound_action.value.source", "player");
section.set("events.consume_water.sound_action.value.volume", 1);
section.set("events.consume_water.sound_action.value.pitch", 1);
section.set("sound", null);
}
if (section.contains("particle")) {
section.set("events.add_water.particle_action.type", "particle");
section.set("events.add_water.particle_action.value.particle", section.getString("particle"));
section.set("events.add_water.particle_action.value.x", 0.5);
section.set("events.add_water.particle_action.value.z", 0.5);
section.set("events.add_water.particle_action.value.y", 1.3);
section.set("events.add_water.particle_action.value.count", 5);
section.set("particle", null);
}
if (section.contains("actionbar")) {
if (section.getBoolean("actionbar.enable")) {
section.set("events.consume_water.actionbar_action.type", "actionbar");
section.set("events.consume_water.actionbar_action.value", section.getString("actionbar.content"));
section.set("events.add_water.actionbar_action.type", "actionbar");
section.set("events.add_water.actionbar_action.value", section.getString("actionbar.content"));
}
section.set("actionbar", null);
}
section.set("events.add_water.sound_action.type", "sound");
section.set("events.add_water.sound_action.value.key", "minecraft:item.bucket.empty");
section.set("events.add_water.sound_action.value.source", "player");
section.set("events.add_water.sound_action.value.volume", 1);
section.set("events.add_water.sound_action.value.pitch", 1);
}
}
try {
yaml.save(file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void updatePots() {
var files = ConfigUtils.getFilesRecursively(new File(CustomCropsPlugin.getInstance().getDataFolder(), "contents" + File.separator + "pots"));
for (File file : files) {
YamlConfiguration yaml = YamlConfiguration.loadConfiguration(file);
for (Map.Entry<String, Object> sections : yaml.getValues(false).entrySet()) {
if (sections.getValue() instanceof ConfigurationSection section) {
section.set("absorb-rainwater", true);
section.set("absorb-nearby-water", false);
ConfigurationSection fillSection = section.getConfigurationSection("fill-method");
if (fillSection != null) {
for (String key : fillSection.getKeys(false)) {
fillSection.set(key + ".particle", null);
fillSection.set(key + ".sound", null);
}
}
if (section.contains("hologram.water.water-bar")) {
section.set("water-bar.left", section.getString("hologram.water.water-bar.left"));
section.set("water-bar.right", section.getString("hologram.water.water-bar.right"));
section.set("water-bar.empty", section.getString("hologram.water.water-bar.empty"));
section.set("water-bar.full", section.getString("hologram.water.water-bar.full"));
}
section.set("events.add_water.particle_action.type", "particle");
section.set("events.add_water.particle_action.value.particle", "WATER_SPLASH");
section.set("events.add_water.particle_action.value.x", 0.5);
section.set("events.add_water.particle_action.value.z", 0.5);
section.set("events.add_water.particle_action.value.y", 1.3);
section.set("events.add_water.particle_action.value.count", 5);
section.set("events.add_water.particle_action.value.offset-x", 0.3);
section.set("events.add_water.particle_action.value.offset-z", 0.3);
ConfigurationSection holoSection = section.getConfigurationSection("hologram");
if (holoSection != null) {
int duration = holoSection.getInt("duration") * 20;
String requireItem = holoSection.getString("require-item", "*");
section.set("events.interact.conditional_action.type", "conditional");
section.set("events.interact.conditional_action.value.conditions.requirement_1.type", "item-in-hand");
section.set("events.interact.conditional_action.value.conditions.requirement_1.value.amount", 1);
section.set("events.interact.conditional_action.value.conditions.requirement_1.value.item", requireItem);
if (holoSection.getBoolean("water.enable")) {
String waterText = holoSection.getString("water.content");
section.set("events.interact.conditional_action.value.actions.water_hologram.type", "hologram");
section.set("events.interact.conditional_action.value.actions.water_hologram.value.duration", duration);
section.set("events.interact.conditional_action.value.actions.water_hologram.value.text", waterText);
section.set("events.interact.conditional_action.value.actions.water_hologram.value.apply-correction", true);
section.set("events.interact.conditional_action.value.actions.water_hologram.value.x", 0.5);
section.set("events.interact.conditional_action.value.actions.water_hologram.value.y", 0.6);
section.set("events.interact.conditional_action.value.actions.water_hologram.value.z", 0.5);
}
if (holoSection.getBoolean("fertilizer.enable")) {
String fertilizerText = holoSection.getString("fertilizer.content");
section.set("events.interact.conditional_action.value.actions.conditional_fertilizer_action.type", "conditional");
section.set("events.interact.conditional_action.value.actions.conditional_fertilizer_action.value.conditions.requirement_1.type", "fertilizer");
section.set("events.interact.conditional_action.value.actions.conditional_fertilizer_action.value.conditions.requirement_1.value.has", true);
section.set("events.interact.conditional_action.value.actions.conditional_fertilizer_action.value.actions.fertilizer_hologram.type", "hologram");
section.set("events.interact.conditional_action.value.actions.conditional_fertilizer_action.value.actions.fertilizer_hologram.value.text", fertilizerText);
section.set("events.interact.conditional_action.value.actions.conditional_fertilizer_action.value.actions.fertilizer_hologram.value.duration", duration);
section.set("events.interact.conditional_action.value.actions.conditional_fertilizer_action.value.actions.fertilizer_hologram.value.apply-correction", true);
section.set("events.interact.conditional_action.value.actions.conditional_fertilizer_action.value.actions.fertilizer_hologram.value.x", 0.5);
section.set("events.interact.conditional_action.value.actions.conditional_fertilizer_action.value.actions.fertilizer_hologram.value.y", 0.83);
section.set("events.interact.conditional_action.value.actions.conditional_fertilizer_action.value.actions.fertilizer_hologram.value.z", 0.5);
}
section.set("hologram", null);
}
}
}
try {
yaml.save(file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void updateFertilizers() {
var files = ConfigUtils.getFilesRecursively(new File(CustomCropsPlugin.getInstance().getDataFolder(), "contents" + File.separator + "fertilizers"));
for (File file : files) {
YamlConfiguration yaml = YamlConfiguration.loadConfiguration(file);
for (Map.Entry<String, Object> sections : yaml.getValues(false).entrySet()) {
if (sections.getValue() instanceof ConfigurationSection section) {
if (section.contains("particle")) {
section.set("events.use.particle_action.type", "particle");
section.set("events.use.particle_action.value.particle", section.getString("particle"));
section.set("events.use.particle_action.value.x", 0.5);
section.set("events.use.particle_action.value.y", 1.3);
section.set("events.use.particle_action.value.z", 0.5);
section.set("events.use.particle_action.value.count", 5);
section.set("events.use.particle_action.value.offset-x", 0.3);
section.set("events.use.particle_action.value.offset-z", 0.3);
section.set("particle", null);
}
if (section.contains("sound")) {
section.set("events.use.sound_action.type", "sound");
section.set("events.use.sound_action.value.source", "player");
section.set("events.use.sound_action.value.key", section.getString("sound"));
section.set("events.use.sound_action.value.volume", 1);
section.set("events.use.sound_action.value.pitch", 1);
section.set("sound", null);
}
if (section.contains("pot-whitelist")) {
section.set("events.wrong_pot.sound_action.type", "sound");
section.set("events.wrong_pot.sound_action.value.source", "player");
section.set("events.wrong_pot.sound_action.value.key", "minecraft:item.bundle.insert");
section.set("events.wrong_pot.sound_action.value.volume", 1);
section.set("events.wrong_pot.sound_action.value.pitch", 1);
section.set("events.wrong_pot.actionbar_action.type", "actionbar");
section.set("events.wrong_pot.actionbar_action.value", "<red><bold>[X] This fertilizer can only be used in pots.");
}
if (section.getBoolean("before-plant")) {
section.set("events.before_plant.sound_action.type", "sound");
section.set("events.before_plant.sound_action.value.source", "player");
section.set("events.before_plant.sound_action.value.key", "minecraft:item.bundle.insert");
section.set("events.before_plant.sound_action.value.volume", 1);
section.set("events.before_plant.sound_action.value.pitch", 1);
section.set("events.before_plant.actionbar_action.type", "actionbar");
section.set("events.before_plant.actionbar_action.value", "<red><bold>[X] You can only use this fertilizer before planting the crop.");
}
}
}
try {
yaml.save(file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void updateSprinklers() {
var files = ConfigUtils.getFilesRecursively(new File(CustomCropsPlugin.getInstance().getDataFolder(), "contents" + File.separator + "sprinklers"));
for (File file : files) {
YamlConfiguration yaml = YamlConfiguration.loadConfiguration(file);
for (Map.Entry<String, Object> sections : yaml.getValues(false).entrySet()) {
if (sections.getValue() instanceof ConfigurationSection section) {
section.set("infinite", false);
ConfigurationSection fillSection = section.getConfigurationSection("fill-method");
if (fillSection != null) {
for (String key : fillSection.getKeys(false)) {
fillSection.set(key + ".particle", null);
fillSection.set(key + ".sound", null);
}
}
if (section.contains("place-sound")) {
section.set("events.place.sound_action.type", "sound");
section.set("events.place.sound_action.value.key", section.getString("place-sound"));
section.set("events.place.sound_action.value.source", "player");
section.set("events.place.sound_action.value.volume", 1);
section.set("events.place.sound_action.value.pitch", 1);
section.set("place-sound", null);
}
section.set("events.interact.force_work_action.type", "conditional");
section.set("events.interact.force_work_action.value.conditions.requirement_1.type", "sneak");
section.set("events.interact.force_work_action.value.conditions.requirement_1.value", true);
section.set("events.interact.force_work_action.value.actions.action_1.type", "force-tick");
if (section.contains("hologram")) {
if (section.getBoolean("hologram.enable")) {
int duration = section.getInt("hologram.duration") * 20;
String text = section.getString("hologram.content");
if (section.contains("hologram.water-bar")) {
section.set("water-bar.left", section.getString("hologram.water-bar.left"));
section.set("water-bar.right", section.getString("hologram.water-bar.right"));
section.set("water-bar.empty", section.getString("hologram.water-bar.empty"));
section.set("water-bar.full", section.getString("hologram.water-bar.full"));
}
section.set("events.interact.hologram_action.type", "hologram");
section.set("events.interact.hologram_action.value.duration", duration);
section.set("events.interact.hologram_action.value.text", text);
section.set("events.interact.hologram_action.value.x", 0.5);
section.set("events.interact.hologram_action.value.y", -0.3);
section.set("events.interact.hologram_action.value.z", 0.5);
section.set("events.interact.hologram_action.value.visible-to-all", false);
}
section.set("hologram", null);
}
if (section.contains("animation")) {
if (section.getBoolean("animation.enable")) {
String item = section.getString("animation.item");
int duration = section.getInt("animation.duration") * 20;
section.set("events.work.fake_item_action.type", "fake-item");
section.set("events.work.fake_item_action.value.item", item);
section.set("events.work.fake_item_action.value.duration", duration);
section.set("events.work.fake_item_action.value.x", 0.5);
section.set("events.work.fake_item_action.value.y", 0.4);
section.set("events.work.fake_item_action.value.z", 0.5);
section.set("events.work.fake_item_action.value.visible-to-all", true);
}
section.set("animation", null);
}
section.set("events.add_water.particle_action.type", "particle");
section.set("events.add_water.particle_action.value.particle", "WATER_SPLASH");
section.set("events.add_water.particle_action.value.x", 0.5);
section.set("events.add_water.particle_action.value.z", 0.5);
section.set("events.add_water.particle_action.value.y", 0.7);
section.set("events.add_water.particle_action.value.count", 5);
section.set("events.add_water.sound_action.type", "sound");
section.set("events.add_water.sound_action.value.key", "minecraft:item.bucket.empty");
section.set("events.add_water.sound_action.value.source", "player");
section.set("events.add_water.sound_action.value.pitch", 1);
section.set("events.add_water.sound_action.value.volume", 1);
}
}
try {
yaml.save(file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void updateCrops() {
var files = ConfigUtils.getFilesRecursively(new File(CustomCropsPlugin.getInstance().getDataFolder(), "contents" + File.separator + "crops"));
for (File file : files) {
YamlConfiguration yaml = YamlConfiguration.loadConfiguration(file);
for (Map.Entry<String, Object> sections : yaml.getValues(false).entrySet()) {
if (sections.getValue() instanceof ConfigurationSection section) {
if (section.contains("plant-actions")) {
section.set("events.plant", section.getConfigurationSection("plant-actions"));
section.set("plant-actions", null);
}
ConfigurationSection boneMeal = section.getConfigurationSection("custom-bone-meal");
if (boneMeal != null) {
for (Map.Entry<String, Object> entry : boneMeal.getValues(false).entrySet()) {
if (entry.getValue() instanceof ConfigurationSection inner) {
inner.set("actions.swing_action.type", "swing-hand");
inner.set("actions.swing_action.value", true);
if (inner.contains("particle")) {
inner.set("actions.particle_action.type", "particle");
inner.set("actions.particle_action.value.particle", inner.getString("particle"));
inner.set("actions.particle_action.value.count",5);
inner.set("actions.particle_action.value.x", 0.5);
inner.set("actions.particle_action.value.y", 0.5);
inner.set("actions.particle_action.value.z", 0.5);
inner.set("actions.particle_action.value.offset-x", 0.3);
inner.set("actions.particle_action.value.offset-y", 0.3);
inner.set("actions.particle_action.value.offset-z", 0.3);
inner.set("particle", null);
}
if (inner.contains("sound")) {
inner.set("actions.sound_action.type", "sound");
inner.set("actions.sound_action.value.key", inner.getString("sound"));
inner.set("actions.sound_action.value.source", "player");
inner.set("actions.sound_action.value.volume", 1);
inner.set("actions.sound_action.value.pitch", 1);
inner.set("sound", null);
}
}
}
}
ConfigurationSection pointSection = section.getConfigurationSection("points");
if (pointSection == null) continue;
for (Map.Entry<String, Object> entry1 : pointSection.getValues(false).entrySet()) {
if (entry1.getValue() instanceof ConfigurationSection pointS1) {
ConfigurationSection eventSection = pointS1.getConfigurationSection("events");
if (eventSection != null) {
if (eventSection.contains("interact-by-hand")) {
eventSection.set("interact.empty_hand_action.type", "conditional");
eventSection.set("interact.empty_hand_action.value.conditions", eventSection.getConfigurationSection("interact-by-hand.requirements"));
eventSection.set("interact.empty_hand_action.value.conditions.requirement_empty_hand.type", "item-in-hand");
eventSection.set("interact.empty_hand_action.value.conditions.requirement_empty_hand.value.item", "AIR");
eventSection.set("interact.empty_hand_action.value.actions", eventSection.getConfigurationSection("interact-by-hand"));
eventSection.set("interact.empty_hand_action.value.actions.requirements", null);
eventSection.set("interact-by-hand", null);
}
if (eventSection.contains("interact-with-item")) {
ConfigurationSection interactWithItem = eventSection.getConfigurationSection("interact-with-item");
if (interactWithItem != null) {
int amount = 0;
for (Map.Entry<String, Object> entry : interactWithItem.getValues(false).entrySet()) {
if (entry.getValue() instanceof ConfigurationSection inner) {
amount++;
String requiredItem = inner.getString("item");
boolean consume = inner.getBoolean("reduce-amount");
String returned = inner.getString("return");
ConfigurationSection actions = inner.getConfigurationSection("actions");
eventSection.set("interact.action_" + amount + ".type", "conditional");
eventSection.set("interact.action_" + amount + ".type", "conditional");
eventSection.set("interact.action_" + amount + ".value.conditions", inner.getConfigurationSection("requirements"));
eventSection.set("interact.action_" + amount + ".value.conditions.requirement_item.type", "item-in-hand");
eventSection.set("interact.action_" + amount + ".value.conditions.requirement_item.value.item", requiredItem);
eventSection.set("interact.action_" + amount + ".value.actions", actions);
if (consume) {
eventSection.set("interact.action_" + amount + ".value.actions.consume_item.type", "item-amount");
eventSection.set("interact.action_" + amount + ".value.actions.consume_item.value", -1);
}
if (returned != null) {
eventSection.set("interact.action_" + amount + ".value.actions.return_item.type", "give-item");
eventSection.set("interact.action_" + amount + ".value.actions.return_item.value.id", returned);
eventSection.set("interact.action_" + amount + ".value.actions.return_item.value.amount", 1);
}
}
}
}
eventSection.set("interact-with-item", null);
}
}
}
}
}
}
try {
yaml.save(file);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

View File

@@ -163,6 +163,10 @@ public class RequirementManagerImpl implements RequirementManager {
}
}
}
if (section.contains("message")) {
List<String> messages = ConfigUtils.stringListArgs(section.get("message"));
actionList.add(plugin.getActionManager().getActionFactory("message").build(messages, 1));
}
if (actionList.size() == 0)
actionList = null;
}

View File

@@ -355,7 +355,7 @@ public class CChunk implements CustomCropsChunk {
String after = crop.getStageItemByPoint(x);
if (pre.equals(after)) return;
CustomCropsPlugin.get().getItemManager().removeAnythingAt(bkLoc);
CustomCropsPlugin.get().getItemManager().placeItem(bkLoc, crop.getItemCarrier(), after);
CustomCropsPlugin.get().getItemManager().placeItem(bkLoc, crop.getItemCarrier(), after, crop.hasRotation());
}
@Override

View File

@@ -81,7 +81,7 @@ public class CWorld implements CustomCropsWorld {
for (Map.Entry<ChunkCoordinate, CChunk> lazyEntry : lazyChunks.entrySet()) {
CChunk chunk = lazyEntry.getValue();
int sec = chunk.getUnloadedSeconds() + 1;
if (sec >= 10) {
if (sec >= 30) {
chunksToSave.add(Pair.of(lazyEntry.getKey(), chunk));
} else {
chunk.setUnloadedSeconds(sec);

View File

@@ -20,12 +20,12 @@ package net.momirealms.customcrops.mechanic.world;
import net.momirealms.customcrops.api.CustomCropsPlugin;
import net.momirealms.customcrops.api.manager.WorldManager;
import net.momirealms.customcrops.api.mechanic.item.*;
import net.momirealms.customcrops.api.mechanic.world.AbstractWorldAdaptor;
import net.momirealms.customcrops.api.mechanic.world.ChunkCoordinate;
import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock;
import net.momirealms.customcrops.api.mechanic.world.SimpleLocation;
import net.momirealms.customcrops.api.mechanic.world.level.*;
import net.momirealms.customcrops.api.util.LogUtils;
import net.momirealms.customcrops.mechanic.world.adaptor.AbstractWorldAdaptor;
import net.momirealms.customcrops.mechanic.world.adaptor.BukkitWorldAdaptor;
import net.momirealms.customcrops.mechanic.world.adaptor.SlimeWorldAdaptor;
import net.momirealms.customcrops.utils.ConfigUtils;
@@ -502,4 +502,9 @@ public class WorldManagerImpl implements WorldManager, Listener {
public void saveChunkToFile(CustomCropsChunk chunk) {
this.worldAdaptor.saveDynamicData(chunk.getCustomCropsWorld(), chunk);
}
@Override
public AbstractWorldAdaptor getWorldAdaptor() {
return worldAdaptor;
}
}

View File

@@ -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.world.adaptor;
import net.momirealms.customcrops.api.manager.WorldManager;
import net.momirealms.customcrops.api.mechanic.world.ChunkCoordinate;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsChunk;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld;
import org.bukkit.event.Listener;
public abstract class AbstractWorldAdaptor implements Listener {
public static final int version = 1;
protected WorldManager worldManager;
public AbstractWorldAdaptor(WorldManager worldManager) {
this.worldManager = worldManager;
}
public abstract void unload(CustomCropsWorld customCropsWorld);
public abstract void init(CustomCropsWorld customCropsWorld);
public abstract void loadDynamicData(CustomCropsWorld customCropsWorld, ChunkCoordinate chunkCoordinate);
public abstract void unloadDynamicData(CustomCropsWorld customCropsWorld, ChunkCoordinate chunkCoordinate);
public abstract void saveDynamicData(CustomCropsWorld ccWorld, CustomCropsChunk chunk);
}

View File

@@ -26,23 +26,30 @@ import com.flowpowered.nbt.stream.NBTOutputStream;
import com.github.luben.zstd.Zstd;
import com.google.gson.Gson;
import net.momirealms.customcrops.api.CustomCropsPlugin;
import net.momirealms.customcrops.api.manager.ConfigManager;
import net.momirealms.customcrops.api.manager.WorldManager;
import net.momirealms.customcrops.api.mechanic.world.ChunkCoordinate;
import net.momirealms.customcrops.api.mechanic.world.ChunkPos;
import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock;
import net.momirealms.customcrops.api.mechanic.world.*;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsChunk;
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 net.momirealms.customcrops.api.object.crop.GrowingCrop;
import net.momirealms.customcrops.api.object.fertilizer.Fertilizer;
import net.momirealms.customcrops.api.object.pot.Pot;
import net.momirealms.customcrops.api.object.sprinkler.Sprinkler;
import net.momirealms.customcrops.api.object.world.CCChunk;
import net.momirealms.customcrops.api.util.LogUtils;
import net.momirealms.customcrops.mechanic.world.*;
import net.momirealms.customcrops.mechanic.world.block.*;
import net.momirealms.customcrops.scheduler.task.TickTask;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.event.EventHandler;
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
import org.bukkit.persistence.PersistentDataType;
import org.jetbrains.annotations.Nullable;
import java.io.*;
import java.nio.ByteOrder;
@@ -58,6 +65,7 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
public BukkitWorldAdaptor(WorldManager worldManager) {
super(worldManager);
this.gson = new Gson();
this.worldFolder = "";
}
@Override
@@ -89,12 +97,19 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
return;
}
// create directory
new File(world.getWorldFolder(), "customcrops").mkdir();
// try converting legacy worlds
if (ConfigManager.convertWorldOnLoad()) {
convertWorld(cWorld, world);
return;
}
// init world basic info
String json = world.getPersistentDataContainer().get(key, PersistentDataType.STRING);
WorldInfoData data = (json == null || json.equals("null")) ? WorldInfoData.empty() : gson.fromJson(json, WorldInfoData.class);
cWorld.setInfoData(data);
new File(world.getWorldFolder(), "customcrops").mkdir();
}
@Override
@@ -435,4 +450,75 @@ public class BukkitWorldAdaptor extends AbstractWorldAdaptor {
outStream.writeTag(tag);
return outByteStream.toByteArray();
}
public void convertWorld(@Nullable CWorld cWorld, World world) {
// handle legacy files
File leagcyFile = new File(world.getWorldFolder(), "customcrops" + File.separator + "data.yml");
if (leagcyFile.exists()) {
// read date and season
YamlConfiguration data = YamlConfiguration.loadConfiguration(leagcyFile);
try {
Season season = Season.valueOf(data.getString("season"));
if (cWorld != null)
cWorld.setInfoData(new WorldInfoData(season, data.getInt("date", 1)));
world.getPersistentDataContainer().set(key, PersistentDataType.STRING,
gson.toJson(new WorldInfoData(season, data.getInt("date", 1))));
} catch (IllegalArgumentException e) {
if (cWorld != null)
cWorld.setInfoData(WorldInfoData.empty());
}
// delete the file
leagcyFile.delete();
new File(world.getWorldFolder(), "customcrops" + File.separator + "corrupted.yml").delete();
// read chunks
File folder = new File(world.getWorldFolder(), "customcrops" + File.separator + "chunks");
if (!folder.exists()) return;
LogUtils.warn("Converting chunks for world " + world.getName() + " from 3.3 to 3.4... This might take some time.");
File[] data_files = folder.listFiles();
if (data_files == null) return;
for (File file : data_files) {
ChunkCoordinate chunkCoordinate = ChunkCoordinate.getByString(file.getName().substring(0, file.getName().length() - 7));
try (FileInputStream fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis)) {
CCChunk chunk = (CCChunk) ois.readObject();
CChunk cChunk = new CChunk(cWorld, chunkCoordinate);
for (net.momirealms.customcrops.api.object.world.SimpleLocation legacyLocation : chunk.getGreenhouseSet()) {
SimpleLocation simpleLocation = new SimpleLocation(legacyLocation.getWorldName(), legacyLocation.getX(), legacyLocation.getY(), legacyLocation.getZ());
cChunk.addGlassAt(new MemoryGlass(simpleLocation), simpleLocation);
}
for (net.momirealms.customcrops.api.object.world.SimpleLocation legacyLocation : chunk.getScarecrowSet()) {
SimpleLocation simpleLocation = new SimpleLocation(legacyLocation.getWorldName(), legacyLocation.getX(), legacyLocation.getY(), legacyLocation.getZ());
cChunk.addScarecrowAt(new MemoryScarecrow(simpleLocation), simpleLocation);
}
for (Map.Entry<net.momirealms.customcrops.api.object.world.SimpleLocation, GrowingCrop> entry : chunk.getGrowingCropMap().entrySet()) {
net.momirealms.customcrops.api.object.world.SimpleLocation legacyLocation = entry.getKey();
SimpleLocation simpleLocation = new SimpleLocation(legacyLocation.getWorldName(), legacyLocation.getX(), legacyLocation.getY(), legacyLocation.getZ());
cChunk.addCropAt(new MemoryCrop(simpleLocation, entry.getValue().getKey(), entry.getValue().getPoints()), simpleLocation);
}
for (Map.Entry<net.momirealms.customcrops.api.object.world.SimpleLocation, Sprinkler> entry : chunk.getSprinklerMap().entrySet()) {
net.momirealms.customcrops.api.object.world.SimpleLocation legacyLocation = entry.getKey();
SimpleLocation simpleLocation = new SimpleLocation(legacyLocation.getWorldName(), legacyLocation.getX(), legacyLocation.getY(), legacyLocation.getZ());
cChunk.addSprinklerAt(new MemorySprinkler(simpleLocation, entry.getValue().getKey(), entry.getValue().getWater()), simpleLocation);
}
for (Map.Entry<net.momirealms.customcrops.api.object.world.SimpleLocation, Pot> entry : chunk.getPotMap().entrySet()) {
net.momirealms.customcrops.api.object.world.SimpleLocation legacyLocation = entry.getKey();
SimpleLocation simpleLocation = new SimpleLocation(legacyLocation.getWorldName(), legacyLocation.getX(), legacyLocation.getY(), legacyLocation.getZ());
Fertilizer fertilizer = entry.getValue().getFertilizer();
cChunk.addPotAt(new MemoryPot(simpleLocation, entry.getValue().getKey(), entry.getValue().getWater(), fertilizer == null ? "" : fertilizer.getKey(), fertilizer == null ? 0 : fertilizer.getTimes()), simpleLocation);
}
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(getChunkDataFilePath(world, cChunk.getChunkCoordinate())))) {
bos.write(serialize(cChunk));
} catch (IOException e) {
LogUtils.severe("Failed to save CustomCrops data.");
e.printStackTrace();
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
LogUtils.info("Error at " + file.getAbsolutePath());
}
}
LogUtils.info("Successfully converted chunks for world: " + world);
}
}
}

View File

@@ -20,6 +20,7 @@ package net.momirealms.customcrops.mechanic.world.adaptor;
import com.infernalsuite.aswm.api.SlimePlugin;
import com.infernalsuite.aswm.api.events.LoadSlimeWorldEvent;
import net.momirealms.customcrops.api.manager.WorldManager;
import net.momirealms.customcrops.api.mechanic.world.AbstractWorldAdaptor;
import net.momirealms.customcrops.api.mechanic.world.ChunkCoordinate;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsChunk;
import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld;

View File

@@ -111,6 +111,7 @@ public class MemoryCrop extends AbstractCustomCropsBlock implements WorldCrop {
SimpleLocation location = getLocation();
Location bukkitLocation = location.getBukkitLocation();
if (bukkitLocation == null) return;
int previous = getPoint();
@@ -168,7 +169,7 @@ public class MemoryCrop extends AbstractCustomCropsBlock implements WorldCrop {
}
if (pre.equals(after)) return;
CustomCropsPlugin.get().getItemManager().removeAnythingAt(bukkitLocation);
CustomCropsPlugin.get().getItemManager().placeItem(bukkitLocation, crop.getItemCarrier(), after);
CustomCropsPlugin.get().getItemManager().placeItem(bukkitLocation, crop.getItemCarrier(), after, crop.hasRotation());
}, bukkitLocation);
}
}

View File

@@ -52,6 +52,14 @@ public class MemoryPot extends AbstractCustomCropsBlock implements WorldPot {
setData("fertilizer-times", new IntTag("fertilizer-times", 0));
}
public MemoryPot(SimpleLocation location, String key, int water, String fertilizer, int fertilizerTimes) {
super(location, new CompoundMap());
setData("key", new StringTag("key", key));
setData("water", new IntTag("water", water));
setData("fertilizer", new StringTag("fertilizer", fertilizer));
setData("fertilizer-times", new IntTag("fertilizer-times", fertilizerTimes));
}
@Override
public String getKey() {
return getData("key").getAsStringTag()

View File

@@ -0,0 +1,36 @@
/*
* 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.utils;
import org.bukkit.Rotation;
import java.util.Random;
public class RotationUtils {
private static final Rotation[] rotationsI = {Rotation.NONE, Rotation.FLIPPED, Rotation.CLOCKWISE, Rotation.COUNTER_CLOCKWISE};
private static final float[] rotationsF = {0f, 90f, 180f, -90f};
public static Rotation getRandomRotation() {
return rotationsI[new Random().nextInt(4)];
}
public static float getRandomFloatRotation() {
return rotationsF[new Random().nextInt(4)];
}
}

View File

@@ -102,13 +102,13 @@ mechanics:
# Scarecrow prevents crops from being attacked by crows
scarecrow:
enable: true
id: {0}scarecrow
id: '{0}scarecrow'
range: 7
# Greenhouse glass prevents crops from withering from season changing
greenhouse:
enable: true
id: {0}greenhouse_glass
id: '{0}greenhouse_glass'
range: 5
# Sync seasons
@@ -145,4 +145,7 @@ other-settings:
# Whether to protect the original lore of the item
# This uses the scoreboard component to identify the plugin's lore,
# which may conflict with some plugins that still use SpigotAPI#ItemMeta.
protect-original-lore: false
protect-original-lore: false
# Should the plugin try to convert worlds from 3.3 to 3.4 when WorldLoadEvent is triggered
convert-on-world-load: false

View File

@@ -60,7 +60,7 @@ tomato:
break:
# 30% chance of dropping crop seeds
action_1:
type: drop-items
type: drop-item
value:
ignore-fertilizer: true
item: {0}tomato_seeds
@@ -73,7 +73,7 @@ tomato:
events:
break:
action_1:
type: drop-items
type: drop-item
value:
ignore-fertilizer: true
item: {0}tomato_seeds
@@ -86,7 +86,7 @@ tomato:
events:
break:
action_1:
type: drop-items
type: drop-item
value:
ignore-fertilizer: true
item: {0}tomato_seeds
@@ -128,7 +128,7 @@ tomato:
chance: 0.01
break:
action_1:
type: drop-items
type: drop-item
value:
ignore-fertilizer: true
item: {0}tomato_seeds
@@ -173,7 +173,7 @@ tomato:
events:
break:
action_1:
type: drop-items
type: drop-item
value:
ignore-fertilizer: true
item: {0}tomato_seeds
@@ -181,7 +181,7 @@ tomato:
max: 2
chance: 1
action_2:
type: drop-items
type: drop-item
value:
ignore-fertilizer: false
item: {0}golden_tomato
@@ -259,6 +259,9 @@ tomato:
custom-bone-meal:
bone_meal_1:
item: BONE_MEAL
chance:
2: 0.2
1: 0.6
actions:
swing_action:
type: swing-hand
@@ -280,7 +283,4 @@ tomato:
source: player
key: minecraft:item.bone_meal.use
volume: 1
pitch: 1
chance:
2: 0.2
1: 0.6
pitch: 1

View File

@@ -93,7 +93,6 @@ default:
requirement_1:
type: item-in-hand
value:
hand: main
amount: 1
item: {0}soil_surveyor
actions:
@@ -116,6 +115,7 @@ default:
x: 0.5
y: 0.83
z: 0.5
visible-to-all: false
# Display the amount of water in pot
water_hologram:
type: hologram
@@ -126,3 +126,4 @@ default:
x: 0.5
y: 0.6
z: 0.5
visible-to-all: false