From 0f18904de06573692aaad851fcaf62ae6a14465d Mon Sep 17 00:00:00 2001
From: XiaoMoMi <972454774@qq.com>
Date: Sun, 10 Mar 2024 04:24:15 +0800
Subject: [PATCH] migration system
---
.../api/manager/ConfigManager.java | 6 +
.../customcrops/api/manager/ItemManager.java | 2 +
.../customcrops/api/manager/WorldManager.java | 3 +
.../customcrops/api/mechanic/item/Crop.java | 2 +-
.../mechanic/world}/AbstractWorldAdaptor.java | 3 +-
.../api/mechanic/world/ChunkCoordinate.java | 13 +
legacy-api/.gitignore | 42 ++
legacy-api/build.gradle.kts | 3 +
.../customcrops/api/object/ItemMode.java | 31 ++
.../customcrops/api/object/ItemType.java | 30 ++
.../api/object/OfflineReplaceTask.java | 33 ++
.../api/object/crop/GrowingCrop.java | 48 ++
.../api/object/fertilizer/Fertilizer.java | 44 ++
.../customcrops/api/object/pot/Pot.java | 52 ++
.../api/object/sprinkler/Sprinkler.java | 48 ++
.../customcrops/api/object/world/CCChunk.java | 77 +++
.../api/object/world/ChunkCoordinate.java | 72 +++
.../api/object/world/SimpleLocation.java | 108 +++++
plugin/build.gradle.kts | 3 +-
.../customcrops/CustomCropsPluginImpl.java | 2 +
.../manager/ConfigManagerImpl.java | 40 +-
.../mechanic/action/ActionManagerImpl.java | 146 +++---
.../mechanic/item/CustomProvider.java | 2 +-
.../mechanic/item/ItemManagerImpl.java | 23 +-
.../custom/itemsadder/ItemsAdderProvider.java | 8 +-
.../item/custom/oraxen/OraxenProvider.java | 6 +-
.../mechanic/item/impl/CropConfig.java | 2 +-
.../mechanic/misc/migrator/Migration.java | 456 ++++++++++++++++++
.../requirement/RequirementManagerImpl.java | 4 +
.../customcrops/mechanic/world/CChunk.java | 2 +-
.../customcrops/mechanic/world/CWorld.java | 2 +-
.../mechanic/world/WorldManagerImpl.java | 7 +-
.../world/adaptor/BukkitWorldAdaptor.java | 96 +++-
.../world/adaptor/SlimeWorldAdaptor.java | 1 +
.../mechanic/world/block/MemoryCrop.java | 3 +-
.../mechanic/world/block/MemoryPot.java | 8 +
.../customcrops/utils/RotationUtils.java | 36 ++
plugin/src/main/resources/config.yml | 9 +-
.../main/resources/contents/crops/default.yml | 20 +-
.../main/resources/contents/pots/default.yml | 3 +-
settings.gradle | 2 +
41 files changed, 1403 insertions(+), 95 deletions(-)
rename {plugin/src/main/java/net/momirealms/customcrops/mechanic/world/adaptor => api/src/main/java/net/momirealms/customcrops/api/mechanic/world}/AbstractWorldAdaptor.java (92%)
create mode 100644 legacy-api/.gitignore
create mode 100644 legacy-api/build.gradle.kts
create mode 100644 legacy-api/src/main/java/net/momirealms/customcrops/api/object/ItemMode.java
create mode 100644 legacy-api/src/main/java/net/momirealms/customcrops/api/object/ItemType.java
create mode 100644 legacy-api/src/main/java/net/momirealms/customcrops/api/object/OfflineReplaceTask.java
create mode 100644 legacy-api/src/main/java/net/momirealms/customcrops/api/object/crop/GrowingCrop.java
create mode 100644 legacy-api/src/main/java/net/momirealms/customcrops/api/object/fertilizer/Fertilizer.java
create mode 100644 legacy-api/src/main/java/net/momirealms/customcrops/api/object/pot/Pot.java
create mode 100644 legacy-api/src/main/java/net/momirealms/customcrops/api/object/sprinkler/Sprinkler.java
create mode 100644 legacy-api/src/main/java/net/momirealms/customcrops/api/object/world/CCChunk.java
create mode 100644 legacy-api/src/main/java/net/momirealms/customcrops/api/object/world/ChunkCoordinate.java
create mode 100644 legacy-api/src/main/java/net/momirealms/customcrops/api/object/world/SimpleLocation.java
create mode 100644 plugin/src/main/java/net/momirealms/customcrops/mechanic/misc/migrator/Migration.java
create mode 100644 plugin/src/main/java/net/momirealms/customcrops/utils/RotationUtils.java
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'
+