diff --git a/api/src/main/java/net/momirealms/customcrops/api/manager/ConfigManager.java b/api/src/main/java/net/momirealms/customcrops/api/manager/ConfigManager.java index c730db4..9d21173 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/manager/ConfigManager.java +++ b/api/src/main/java/net/momirealms/customcrops/api/manager/ConfigManager.java @@ -116,6 +116,12 @@ public abstract class ConfigManager implements Reloadable { return instance.getScarecrowID(); } + public static boolean convertWorldOnLoad() { + return instance.isConvertWorldOnLoad(); + } + + protected abstract boolean isConvertWorldOnLoad(); + protected abstract double[] getDefaultQualityRatio(); protected abstract String getLang(); diff --git a/api/src/main/java/net/momirealms/customcrops/api/manager/ItemManager.java b/api/src/main/java/net/momirealms/customcrops/api/manager/ItemManager.java index 95564aa..39d9245 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/manager/ItemManager.java +++ b/api/src/main/java/net/momirealms/customcrops/api/manager/ItemManager.java @@ -42,6 +42,8 @@ public interface ItemManager extends Reloadable { void placeItem(Location location, ItemCarrier carrier, String id); + void placeItem(Location location, ItemCarrier carrier, String id, boolean rotate); + void removeAnythingAt(Location location); @Nullable diff --git a/api/src/main/java/net/momirealms/customcrops/api/manager/WorldManager.java b/api/src/main/java/net/momirealms/customcrops/api/manager/WorldManager.java index d354fea..4358f41 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/manager/WorldManager.java +++ b/api/src/main/java/net/momirealms/customcrops/api/manager/WorldManager.java @@ -19,6 +19,7 @@ package net.momirealms.customcrops.api.manager; import net.momirealms.customcrops.api.common.Reloadable; import net.momirealms.customcrops.api.mechanic.item.*; +import net.momirealms.customcrops.api.mechanic.world.AbstractWorldAdaptor; import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock; import net.momirealms.customcrops.api.mechanic.world.SimpleLocation; import net.momirealms.customcrops.api.mechanic.world.level.*; @@ -139,4 +140,6 @@ public interface WorldManager extends Reloadable { void removeScarecrowAt(@NotNull SimpleLocation location); CustomCropsBlock removeAnythingAt(SimpleLocation location); + + AbstractWorldAdaptor getWorldAdaptor(); } diff --git a/api/src/main/java/net/momirealms/customcrops/api/mechanic/item/Crop.java b/api/src/main/java/net/momirealms/customcrops/api/mechanic/item/Crop.java index 6b846fb..29defa0 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/mechanic/item/Crop.java +++ b/api/src/main/java/net/momirealms/customcrops/api/mechanic/item/Crop.java @@ -46,7 +46,7 @@ public interface Crop extends KeyItem { BoneMeal[] getBoneMeals(); - boolean isRotation(); + boolean hasRotation(); void trigger(ActionTrigger trigger, State state); diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/adaptor/AbstractWorldAdaptor.java b/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/AbstractWorldAdaptor.java similarity index 92% rename from plugin/src/main/java/net/momirealms/customcrops/mechanic/world/adaptor/AbstractWorldAdaptor.java rename to api/src/main/java/net/momirealms/customcrops/api/mechanic/world/AbstractWorldAdaptor.java index 294e404..7159a92 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/adaptor/AbstractWorldAdaptor.java +++ b/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/AbstractWorldAdaptor.java @@ -15,10 +15,9 @@ * along with this program. If not, see . */ -package net.momirealms.customcrops.mechanic.world.adaptor; +package net.momirealms.customcrops.api.mechanic.world; 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; diff --git a/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/ChunkCoordinate.java b/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/ChunkCoordinate.java index 81e93c6..6b402ca 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/ChunkCoordinate.java +++ b/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/ChunkCoordinate.java @@ -28,6 +28,19 @@ public record ChunkCoordinate(int x, int z) { return new ChunkCoordinate(x, z); } + public static ChunkCoordinate getByString(String coordinate) { + String[] split = coordinate.split(",", 2); + try { + int x = Integer.parseInt(split[0]); + int z = Integer.parseInt(split[1]); + return new ChunkCoordinate(x, z); + } + catch (NumberFormatException e) { + e.printStackTrace(); + return null; + } + } + @Override public int hashCode() { long combined = (long) x << 32 | z; diff --git a/legacy-api/.gitignore b/legacy-api/.gitignore new file mode 100644 index 0000000..b63da45 --- /dev/null +++ b/legacy-api/.gitignore @@ -0,0 +1,42 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/legacy-api/build.gradle.kts b/legacy-api/build.gradle.kts new file mode 100644 index 0000000..5094bf0 --- /dev/null +++ b/legacy-api/build.gradle.kts @@ -0,0 +1,3 @@ +dependencies { + compileOnly("io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT") +} \ No newline at end of file diff --git a/legacy-api/src/main/java/net/momirealms/customcrops/api/object/ItemMode.java b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/ItemMode.java new file mode 100644 index 0000000..bafdc53 --- /dev/null +++ b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/ItemMode.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +package net.momirealms.customcrops.api.object; + +import java.io.Serializable; + +@Deprecated +public enum ItemMode implements Serializable { + + ARMOR_STAND, + TRIPWIRE, + ITEM_FRAME, + ITEM_DISPLAY, + NOTE_BLOCK, + CHORUS +} diff --git a/legacy-api/src/main/java/net/momirealms/customcrops/api/object/ItemType.java b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/ItemType.java new file mode 100644 index 0000000..d973fed --- /dev/null +++ b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/ItemType.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +package net.momirealms.customcrops.api.object; + +@Deprecated +public enum ItemType { + + GLASS, + POT, + CROP, + SPRINKLER, + SCARECROW, + WATERING_CAN, + UNKNOWN +} diff --git a/legacy-api/src/main/java/net/momirealms/customcrops/api/object/OfflineReplaceTask.java b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/OfflineReplaceTask.java new file mode 100644 index 0000000..f80dcf9 --- /dev/null +++ b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/OfflineReplaceTask.java @@ -0,0 +1,33 @@ +package net.momirealms.customcrops.api.object; + +import java.io.Serial; +import java.io.Serializable; + +@Deprecated +public class OfflineReplaceTask implements Serializable { + + @Serial + private static final long serialVersionUID = -7700789811612423911L; + + private final String id; + private final ItemType itemType; + private final ItemMode itemMode; + + public OfflineReplaceTask(String id, ItemType itemType, ItemMode itemMode) { + this.id = id; + this.itemMode = itemMode; + this.itemType = itemType; + } + + public String getId() { + return id; + } + + public ItemMode getItemMode() { + return itemMode; + } + + public ItemType getItemType() { + return itemType; + } +} diff --git a/legacy-api/src/main/java/net/momirealms/customcrops/api/object/crop/GrowingCrop.java b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/crop/GrowingCrop.java new file mode 100644 index 0000000..07290c5 --- /dev/null +++ b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/crop/GrowingCrop.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +package net.momirealms.customcrops.api.object.crop; + +import java.io.Serial; +import java.io.Serializable; + +@Deprecated +public class GrowingCrop implements Serializable { + + @Serial + private static final long serialVersionUID = 2828962866548871991L; + + private int points; + private final String crop; + + public GrowingCrop(String crop, int points) { + this.points = points; + this.crop = crop; + } + + public int getPoints() { + return points; + } + + public void setPoints(int points) { + this.points = points; + } + + public String getKey() { + return crop; + } +} diff --git a/legacy-api/src/main/java/net/momirealms/customcrops/api/object/fertilizer/Fertilizer.java b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/fertilizer/Fertilizer.java new file mode 100644 index 0000000..5251783 --- /dev/null +++ b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/fertilizer/Fertilizer.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +package net.momirealms.customcrops.api.object.fertilizer; + +import java.io.Serial; +import java.io.Serializable; + +@Deprecated +public class Fertilizer implements Serializable { + + @Serial + private static final long serialVersionUID = -7593869247329159078L; + + private final String key; + private final int times; + + public Fertilizer(String key, int times) { + this.key = key; + this.times = times; + } + + public String getKey() { + return key; + } + + public int getTimes() { + return times; + } +} diff --git a/legacy-api/src/main/java/net/momirealms/customcrops/api/object/pot/Pot.java b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/pot/Pot.java new file mode 100644 index 0000000..ecfa1cf --- /dev/null +++ b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/pot/Pot.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +package net.momirealms.customcrops.api.object.pot; + +import net.momirealms.customcrops.api.object.fertilizer.Fertilizer; + +import java.io.Serial; +import java.io.Serializable; + +@Deprecated +public class Pot implements Serializable { + + @Serial + private static final long serialVersionUID = -6598493908660891824L; + + private Fertilizer fertilizer; + private int water; + private final String key; + + public Pot(String key, Fertilizer fertilizer, int water) { + this.key = key; + this.fertilizer = fertilizer; + this.water = water; + } + + public Fertilizer getFertilizer() { + return fertilizer; + } + + public int getWater() { + return water; + } + + public String getKey() { + return key; + } +} \ No newline at end of file diff --git a/legacy-api/src/main/java/net/momirealms/customcrops/api/object/sprinkler/Sprinkler.java b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/sprinkler/Sprinkler.java new file mode 100644 index 0000000..1d8023c --- /dev/null +++ b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/sprinkler/Sprinkler.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +package net.momirealms.customcrops.api.object.sprinkler; + +import java.io.Serial; +import java.io.Serializable; + +@Deprecated +public class Sprinkler implements Serializable { + + @Serial + private static final long serialVersionUID = -1994328062935821245L; + + private int water; + private final String key; + + public Sprinkler(String key, int water) { + this.water = water; + this.key = key; + } + + public int getWater() { + return water; + } + + public void setWater(int water) { + this.water = water; + } + + public String getKey() { + return key; + } +} diff --git a/legacy-api/src/main/java/net/momirealms/customcrops/api/object/world/CCChunk.java b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/world/CCChunk.java new file mode 100644 index 0000000..d18a8e2 --- /dev/null +++ b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/world/CCChunk.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +package net.momirealms.customcrops.api.object.world; + +import net.momirealms.customcrops.api.object.OfflineReplaceTask; +import net.momirealms.customcrops.api.object.crop.GrowingCrop; +import net.momirealms.customcrops.api.object.pot.Pot; +import net.momirealms.customcrops.api.object.sprinkler.Sprinkler; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +@Deprecated +public class CCChunk implements Serializable { + + @Serial + private static final long serialVersionUID = 5300805317167684402L; + + private final ConcurrentHashMap growingCropMap; + private final ConcurrentHashMap potMap; + private final ConcurrentHashMap sprinklerMap; + private ConcurrentHashMap replaceTaskMap; + private final Set greenhouseSet; + private final Set scarecrowSet; + + public CCChunk() { + this.growingCropMap = new ConcurrentHashMap<>(64); + this.potMap = new ConcurrentHashMap<>(64); + this.sprinklerMap = new ConcurrentHashMap<>(16); + this.greenhouseSet = Collections.synchronizedSet(new HashSet<>(64)); + this.scarecrowSet = Collections.synchronizedSet(new HashSet<>(4)); + this.replaceTaskMap = new ConcurrentHashMap<>(64); + } + + public ConcurrentHashMap getGrowingCropMap() { + return growingCropMap; + } + + public ConcurrentHashMap getPotMap() { + return potMap; + } + + public ConcurrentHashMap getSprinklerMap() { + return sprinklerMap; + } + + public ConcurrentHashMap getReplaceTaskMap() { + return replaceTaskMap; + } + + public Set getGreenhouseSet() { + return greenhouseSet; + } + + public Set getScarecrowSet() { + return scarecrowSet; + } +} \ No newline at end of file diff --git a/legacy-api/src/main/java/net/momirealms/customcrops/api/object/world/ChunkCoordinate.java b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/world/ChunkCoordinate.java new file mode 100644 index 0000000..e3d985c --- /dev/null +++ b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/world/ChunkCoordinate.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +package net.momirealms.customcrops.api.object.world; + +import java.io.Serial; +import java.io.Serializable; + +@Deprecated +public class ChunkCoordinate implements Serializable { + + @Serial + private static final long serialVersionUID = 8143293419668383618L; + + private final int x; + private final int z; + + public ChunkCoordinate(int x, int z) { + this.x = x; + this.z = z; + } + + public int getX() { + return x; + } + + public int getZ() { + return z; + } + + public String getFileName() { + return x + "," + z; + } + + @Override + public int hashCode() { + long combined = (long) x << 32 | z; + return Long.hashCode(combined); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final ChunkCoordinate other = (ChunkCoordinate) obj; + if (this.x != other.x) { + return false; + } + if (this.z != other.z) { + return false; + } + return true; + } +} diff --git a/legacy-api/src/main/java/net/momirealms/customcrops/api/object/world/SimpleLocation.java b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/world/SimpleLocation.java new file mode 100644 index 0000000..6a11d26 --- /dev/null +++ b/legacy-api/src/main/java/net/momirealms/customcrops/api/object/world/SimpleLocation.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +package net.momirealms.customcrops.api.object.world; + +import java.io.Serial; +import java.io.Serializable; +import java.util.Objects; + +@Deprecated +public class SimpleLocation implements Serializable { + + @Serial + private static final long serialVersionUID = -1288860694388882412L; + + private final int x; + private final int y; + private final int z; + private final String worldName; + + public SimpleLocation(String worldName, int x, int y, int z){ + this.worldName = worldName; + this.x = x; + this.y = y; + this.z = z; + } + + public int getX() { + return x; + } + + public int getZ() { + return z; + } + + public int getY() { + return y; + } + + public String getWorldName() { + return worldName; + } + + public ChunkCoordinate getChunkCoordinate() { + return new ChunkCoordinate(x >> 4, z >> 4); + } + + public SimpleLocation add(int x, int y, int z) { + return new SimpleLocation(worldName, this.x + x, this.y + y, this.z + z); + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final SimpleLocation other = (SimpleLocation) obj; + if (!Objects.equals(worldName, other.getWorldName())) { + return false; + } + if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(other.x)) { + return false; + } + if (Double.doubleToLongBits(this.y) != Double.doubleToLongBits(other.y)) { + return false; + } + if (Double.doubleToLongBits(this.z) != Double.doubleToLongBits(other.z)) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 3; + //hash = 19 * hash + (worldName != null ? worldName.hashCode() : 0); + hash = 19 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32)); + hash = 19 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32)); + hash = 19 * hash + (int) (Double.doubleToLongBits(this.z) ^ (Double.doubleToLongBits(this.z) >>> 32)); + return hash; + } + + @Override + public String toString() { + return "[" + worldName + "," + x + "," + y + "," + z + "]"; + } + + public SimpleLocation copy() { + return new SimpleLocation(worldName, x, y, z); + } +} \ No newline at end of file diff --git a/plugin/build.gradle.kts b/plugin/build.gradle.kts index d35513a..53a6f31 100644 --- a/plugin/build.gradle.kts +++ b/plugin/build.gradle.kts @@ -47,6 +47,7 @@ dependencies { compileOnly(files("libs/RealisticSeasons-api.jar")) implementation(project(":api")) + implementation(project(":legacy-api")) implementation("net.kyori:adventure-api:4.15.0") implementation("net.kyori:adventure-platform-bukkit:4.3.2") compileOnly("com.github.Xiao-MoMi:AntiGriefLib:0.7") @@ -55,7 +56,6 @@ dependencies { compileOnly("net.kyori:adventure-text-serializer-legacy:4.15.0") compileOnly("de.tr7zw:item-nbt-api:2.12.2") compileOnly("org.bstats:bstats-bukkit:3.0.2") - implementation("org.lz4:lz4-java:1.8.0") implementation("com.flowpowered:flow-nbt:2.0.2") implementation("com.github.luben:zstd-jni:1.5.5-11") } @@ -67,6 +67,7 @@ tasks { relocate ("net.kyori", "net.momirealms.customcrops.libraries") relocate ("org.objenesis", "net.momirealms.customcrops.libraries.objenesis") relocate ("org.bstats", "net.momirealms.customcrops.libraries.bstats") + relocate ("dev.dejvokep.boostedyaml", "net.momirealms.customcrops.libraries.boostedyaml") relocate ("net.momirealms.biomeapi", "net.momirealms.customcrops.libraries.biomeapi") relocate ("net.momirealms.antigrieflib", "net.momirealms.customcrops.libraries.antigrieflib") } diff --git a/plugin/src/main/java/net/momirealms/customcrops/CustomCropsPluginImpl.java b/plugin/src/main/java/net/momirealms/customcrops/CustomCropsPluginImpl.java index 7eb37be..9d301e7 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/CustomCropsPluginImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/CustomCropsPluginImpl.java @@ -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); diff --git a/plugin/src/main/java/net/momirealms/customcrops/manager/ConfigManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/manager/ConfigManagerImpl.java index 48aa7bf..5ccbba2 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/manager/ConfigManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/manager/ConfigManagerImpl.java @@ -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 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; diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/action/ActionManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/action/ActionManagerImpl.java index 3112e47..14b76f8 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/action/ActionManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/action/ActionManagerImpl.java @@ -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 actions = new ArrayList<>(); + ConfigurationSection otherItemSection = section.getConfigurationSection("other-items"); + if (otherItemSection != null) { + for (Map.Entry 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 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)); + }; }); } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/CustomProvider.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/CustomProvider.java index 362a662..0b41ca4 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/CustomProvider.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/CustomProvider.java @@ -43,7 +43,7 @@ public interface CustomProvider { } } - void placeFurniture(Location location, String id); + Entity placeFurniture(Location location, String id); void removeFurniture(Entity entity); diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/ItemManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/ItemManagerImpl.java index c1340d4..1a1d644 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/ItemManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/ItemManagerImpl.java @@ -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); diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/itemsadder/ItemsAdderProvider.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/itemsadder/ItemsAdderProvider.java index 28fb77c..eeaf47c 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/itemsadder/ItemsAdderProvider.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/itemsadder/ItemsAdderProvider.java @@ -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 diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/oraxen/OraxenProvider.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/oraxen/OraxenProvider.java index efb078a..54d79c1 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/oraxen/OraxenProvider.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/oraxen/OraxenProvider.java @@ -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 diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/impl/CropConfig.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/impl/CropConfig.java index e2f1b3a..5251d4f 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/impl/CropConfig.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/impl/CropConfig.java @@ -134,7 +134,7 @@ public class CropConfig extends AbstractEventItem implements Crop { } @Override - public boolean isRotation() { + public boolean hasRotation() { return rotation; } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/migrator/Migration.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/migrator/Migration.java new file mode 100644 index 0000000..907a527 --- /dev/null +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/migrator/Migration.java @@ -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 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 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 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", "[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", "[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 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 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 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 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 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(); + } + } + } +} diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/requirement/RequirementManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/requirement/RequirementManagerImpl.java index 69dbff5..f37c1cc 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/requirement/RequirementManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/requirement/RequirementManagerImpl.java @@ -163,6 +163,10 @@ public class RequirementManagerImpl implements RequirementManager { } } } + if (section.contains("message")) { + List messages = ConfigUtils.stringListArgs(section.get("message")); + actionList.add(plugin.getActionManager().getActionFactory("message").build(messages, 1)); + } if (actionList.size() == 0) actionList = null; } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CChunk.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CChunk.java index 1a4b29b..a9a2891 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CChunk.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CChunk.java @@ -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 diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CWorld.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CWorld.java index 5d59a66..015e402 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CWorld.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CWorld.java @@ -81,7 +81,7 @@ public class CWorld implements CustomCropsWorld { for (Map.Entry 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); diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/WorldManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/WorldManagerImpl.java index 4195859..43ef490 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/WorldManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/WorldManagerImpl.java @@ -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; + } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/adaptor/BukkitWorldAdaptor.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/adaptor/BukkitWorldAdaptor.java index a6bf231..0e8cecd 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/adaptor/BukkitWorldAdaptor.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/adaptor/BukkitWorldAdaptor.java @@ -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 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 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 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); + } + } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/adaptor/SlimeWorldAdaptor.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/adaptor/SlimeWorldAdaptor.java index 9d8d48a..910c97f 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/adaptor/SlimeWorldAdaptor.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/adaptor/SlimeWorldAdaptor.java @@ -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; diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryCrop.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryCrop.java index a12e221..23dab06 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryCrop.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryCrop.java @@ -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); } } \ No newline at end of file diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryPot.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryPot.java index 7d9a6c9..498fb78 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryPot.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/block/MemoryPot.java @@ -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() diff --git a/plugin/src/main/java/net/momirealms/customcrops/utils/RotationUtils.java b/plugin/src/main/java/net/momirealms/customcrops/utils/RotationUtils.java new file mode 100644 index 0000000..1a89fe8 --- /dev/null +++ b/plugin/src/main/java/net/momirealms/customcrops/utils/RotationUtils.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) <2022> + * + * 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 . + */ + +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)]; + } +} diff --git a/plugin/src/main/resources/config.yml b/plugin/src/main/resources/config.yml index 85f85ba..40a6034 100644 --- a/plugin/src/main/resources/config.yml +++ b/plugin/src/main/resources/config.yml @@ -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 \ No newline at end of file + 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 \ No newline at end of file diff --git a/plugin/src/main/resources/contents/crops/default.yml b/plugin/src/main/resources/contents/crops/default.yml index 2e1fcb2..bfe6c72 100644 --- a/plugin/src/main/resources/contents/crops/default.yml +++ b/plugin/src/main/resources/contents/crops/default.yml @@ -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 \ No newline at end of file + pitch: 1 \ No newline at end of file diff --git a/plugin/src/main/resources/contents/pots/default.yml b/plugin/src/main/resources/contents/pots/default.yml index f230d54..aef4cdf 100644 --- a/plugin/src/main/resources/contents/pots/default.yml +++ b/plugin/src/main/resources/contents/pots/default.yml @@ -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 \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index f35bb11..3b4dbf8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,5 @@ rootProject.name = 'CustomCrops' include(":plugin") include(":api") +include 'legacy-api' +