diff --git a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/SXItemSource.java b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/SXItemSource.java index ca7ddbc59..93d820fd0 100644 --- a/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/SXItemSource.java +++ b/bukkit/compatibility/src/main/java/net/momirealms/craftengine/bukkit/compatibility/item/SXItemSource.java @@ -13,7 +13,7 @@ public class SXItemSource implements ExternalItemSource { @Override public String plugin() { - return "sxitem"; + return "sx-item"; } @Nullable diff --git a/bukkit/loader/build.gradle.kts b/bukkit/loader/build.gradle.kts index c46bb9ff0..11ecaf4e1 100644 --- a/bukkit/loader/build.gradle.kts +++ b/bukkit/loader/build.gradle.kts @@ -50,7 +50,7 @@ bukkit { name = "CraftEngine" apiVersion = "1.20" authors = listOf("XiaoMoMi") - contributors = listOf("jhqwqmc", "iqtesterr", "WhiteProject1", "Catnies", "xiaozhangup", "TamashiiMon", "Halogly", "ArubikU", "Maxsh001", "Sasha2294", "MrPanda8") + contributors = listOf("https://github.com/Xiao-MoMi/craft-engine/graphs/contributors") softDepend = listOf("PlaceholderAPI", "WorldEdit", "FastAsyncWorldEdit", "Skript") foliaSupported = true } diff --git a/bukkit/paper-loader/build.gradle.kts b/bukkit/paper-loader/build.gradle.kts index 0e848216c..ca26d2289 100644 --- a/bukkit/paper-loader/build.gradle.kts +++ b/bukkit/paper-loader/build.gradle.kts @@ -53,7 +53,7 @@ paper { name = "CraftEngine" apiVersion = "1.20" authors = listOf("XiaoMoMi") - contributors = listOf("jhqwqmc", "iqtesterrr", "WhiteProject1", "Catnies", "xiaozhangup", "TamashiiMon", "Halogly", "ArubikU", "Maxsh001", "Sasha2294", "MrPanda8") + contributors = listOf("https://github.com/Xiao-MoMi/craft-engine/graphs/contributors") foliaSupported = true serverDependencies { register("PlaceholderAPI") { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index 124263ed2..79cd15c2d 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -917,7 +917,7 @@ public final class CoreReflections { ); public static final Method method$IdMapper$add = requireNonNull( - ReflectionUtils.getMethod(clazz$IdMapper, void.class, Object.class) + ReflectionUtils.getMethod(clazz$IdMapper, void.class, new String[] {"add", "b"}, Object.class) ); public static final Object instance$Block$BLOCK_STATE_REGISTRY; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java index 3ad6e4caa..a8022284b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/world/BukkitCEWorld.java @@ -7,14 +7,13 @@ import net.momirealms.craftengine.core.block.entity.render.BlockEntityRenderer; import net.momirealms.craftengine.core.block.entity.render.BlockEntityRendererConfig; import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.SectionPosUtils; -import net.momirealms.craftengine.core.world.BlockPos; -import net.momirealms.craftengine.core.world.CEWorld; -import net.momirealms.craftengine.core.world.ChunkPos; -import net.momirealms.craftengine.core.world.World; +import net.momirealms.craftengine.core.world.*; import net.momirealms.craftengine.core.world.chunk.storage.StorageAdaptor; import net.momirealms.craftengine.core.world.chunk.storage.WorldDataStorage; import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; public class BukkitCEWorld extends CEWorld { @@ -39,8 +38,9 @@ public class BukkitCEWorld extends CEWorld { ); super.lightSections.clear(); super.isUpdatingLights = false; - super.lightSections.addAll(super.pendingLightSections); - super.pendingLightSections.clear(); + List pendingLightSections = super.pendingLightSections; + super.pendingLightSections = new ArrayList<>(Math.max(pendingLightSections.size() / 2, 8)); + super.lightSections.addAll(pendingLightSections); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java index a424feb2a..4844f542e 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java +++ b/core/src/main/java/net/momirealms/craftengine/core/item/modifier/ExternalModifier.java @@ -8,12 +8,13 @@ import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.locale.LocalizedResourceConfigException; import net.momirealms.craftengine.core.util.Key; import net.momirealms.craftengine.core.util.ResourceConfigUtils; +import org.jetbrains.annotations.NotNull; -import java.util.Locale; -import java.util.Map; +import java.util.*; public class ExternalModifier implements ItemDataModifier { public static final Factory FACTORY = new Factory<>(); + private static final ThreadLocal> BUILD_STACK = ThreadLocal.withInitial(LinkedHashSet::new); private final String id; private final ExternalItemSource provider; @@ -38,14 +39,36 @@ public class ExternalModifier implements ItemDataModifier { @SuppressWarnings("unchecked") @Override public Item apply(Item item, ItemBuildContext context) { - I another = this.provider.build(id, context); - if (another == null) { - CraftEngine.instance().logger().warn("'" + id + "' could not be found in " + provider.plugin()); + Dependency dependency = new Dependency(provider.plugin(), id); + Set buildStack = BUILD_STACK.get(); + + if (buildStack.contains(dependency)) { + StringJoiner dependencyChain = new StringJoiner(" -> "); + buildStack.forEach(element -> dependencyChain.add(element.asString())); + dependencyChain.add(dependency.asString()); + CraftEngine.instance().logger().warn( + "Failed to build '" + this.id + "' from plugin '" + provider.plugin() + "' due to dependency loop: " + dependencyChain + ); return item; } - Item anotherWrapped = (Item) CraftEngine.instance().itemManager().wrap(another); - item.merge(anotherWrapped); - return item; + + buildStack.add(dependency); + try { + I another = this.provider.build(this.id, context); + if (another == null) { + CraftEngine.instance().logger().warn("'" + this.id + "' could not be found in " + provider.plugin()); + return item; + } + Item anotherWrapped = (Item) CraftEngine.instance().itemManager().wrap(another); + item.merge(anotherWrapped); + return item; + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to build item '" + this.id + "' from plugin '" + provider.plugin() + "'", e); + return item; + } finally { + buildStack.remove(dependency); + BUILD_STACK.remove(); + } } public static class Factory implements ItemDataModifierFactory { @@ -60,4 +83,11 @@ public class ExternalModifier implements ItemDataModifier { return new ExternalModifier<>(id, ResourceConfigUtils.requireNonNullOrThrow(provider, () -> new LocalizedResourceConfigException("warning.config.item.data.external.invalid_source", plugin))); } } + + private record Dependency(String source, String id) { + + public @NotNull String asString() { + return source + "[id=" + id + "]"; + } + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index 93e811218..2ce619894 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -24,7 +24,6 @@ import net.momirealms.craftengine.core.pack.model.generation.ModelGeneration; import net.momirealms.craftengine.core.pack.model.generation.ModelGenerator; import net.momirealms.craftengine.core.pack.model.rangedisptach.CustomModelDataRangeDispatchProperty; import net.momirealms.craftengine.core.pack.obfuscation.ObfA; -import net.momirealms.craftengine.core.pack.obfuscation.ResourcePackGenerationException; import net.momirealms.craftengine.core.pack.revision.Revision; import net.momirealms.craftengine.core.pack.revision.Revisions; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -125,7 +124,7 @@ public abstract class AbstractPackManager implements PackManager { loadInternalList("models", "block/", VANILLA_MODELS::add); loadInternalList("models", "item/", VANILLA_MODELS::add); - + loadInternalList("models", "item/legacy/", key -> VANILLA_MODELS.add(Key.of(key.namespace(), "item/" + key.value().substring(12)))); loadInternalList("textures", "", VANILLA_TEXTURES::add); VANILLA_MODELS.add(Key.of("minecraft", "builtin/entity")); VANILLA_MODELS.add(Key.of("minecraft", "item/player_head")); @@ -171,7 +170,7 @@ public abstract class AbstractPackManager implements PackManager { JsonArray fileList = listJson.getAsJsonArray("files"); for (JsonElement element : fileList) { if (element instanceof JsonPrimitive primitive) { - callback.accept(Key.of(prefix + FileUtils.pathWithoutExtension(primitive.getAsString()))); + callback.accept(Key.of("minecraft", prefix + FileUtils.pathWithoutExtension(primitive.getAsString()))); } } JsonArray directoryList = listJson.getAsJsonArray("directories"); @@ -248,16 +247,21 @@ public abstract class AbstractPackManager implements PackManager { // magicConstructor.newInstance(resourcePackPath(), resourcePackPath()); Method magicMethod = ReflectionUtils.getMethod(magicClazz, void.class); assert magicMethod != null; - this.zipGenerator = (p1, p2) -> { + final String magicStr1 = StringUtils.fromBytes(new byte[]{5, 50, 36, 56, 34, 37, 52, 50, 7, 54, 52, 60, 16, 50, 57, 50, 37, 54, 35, 62, 56, 57, 18, 47, 52, 50, 39, 35, 62, 56, 57}, 87); + final String magicStr2 = StringUtils.fromBytes(new byte[]{4, 35, 43, 46, 39, 38, 98, 54, 45, 98, 37, 39, 44, 39, 48, 35, 54, 39, 98, 48, 39, 49, 45, 55, 48, 33, 39, 98, 50, 35, 33, 41, 120, 98}, 66); + final String magicStr3 = StringUtils.fromBytes(new byte[]{107, 76, 68, 65, 72, 73, 13, 89, 66, 13, 74, 72, 67, 72, 95, 76, 89, 72, 13, 87, 68, 93, 13, 75, 68, 65, 72, 94, 39}, 45); + ReflectionUtils.getDeclaredField(getClass().getSuperclass(), StringUtils.fromBytes(new byte[]{69, 86, 79, 120, 90, 81, 90, 77, 94, 75, 80, 77}, 63)).set(this, (BiConsumer) (p1, p2) -> { try { Object magicObject = magicConstructor.newInstance(p1, p2); magicMethod.invoke(magicObject); - } catch (ResourcePackGenerationException e) { - this.plugin.logger().warn("Failed to generate resource pack: " + e.getMessage()); - } catch (Exception e) { - this.plugin.logger().warn("Failed to generate zip files\n" + new StringWriter(){{e.printStackTrace(new PrintWriter(this));}}.toString().replaceAll("\\.[Il]{2,}", "").replaceAll("/[Il]{2,}", "")); + } catch (Throwable e) { + if (e.getClass().getSimpleName().equals(magicStr1)) { + this.plugin.logger().warn(magicStr2 + e.getMessage()); + } else { + this.plugin.logger().warn(magicStr3 + new StringWriter(){{e.printStackTrace(new PrintWriter(this));}}.toString().replaceAll("\\.[Il]{2,}", "").replaceAll("/[Il]{2,}", "")); + } } - }; + }); } else { this.plugin.logger().warn("Magic class doesn't exist"); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/PackCacheData.java b/core/src/main/java/net/momirealms/craftengine/core/pack/PackCacheData.java index 1b4d1f23e..702bf2163 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/PackCacheData.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/PackCacheData.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.pack; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; import org.jetbrains.annotations.NotNull; @@ -7,7 +8,6 @@ import org.jetbrains.annotations.NotNull; import java.nio.file.Files; import java.nio.file.Path; import java.util.Set; -import java.util.stream.Collectors; public class PackCacheData { private final Set externalZips; @@ -17,13 +17,13 @@ public class PackCacheData { this.externalFolders = Config.foldersToMerge().stream() .map(it -> plugin.dataFolderPath().getParent().resolve(it)) .filter(Files::exists) - .collect(Collectors.toSet()); + .collect(ObjectOpenHashSet.toSet()); this.externalZips = Config.zipsToMerge().stream() .map(it -> plugin.dataFolderPath().getParent().resolve(it)) .filter(Files::exists) .filter(Files::isRegularFile) .filter(file -> file.getFileName().toString().endsWith(".zip")) - .collect(Collectors.toSet()); + .collect(ObjectOpenHashSet.toSet()); } @NotNull diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/ListMonitor.java b/core/src/main/java/net/momirealms/craftengine/core/util/ListMonitor.java index bddcd6a34..3e37d53b5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/ListMonitor.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/ListMonitor.java @@ -13,14 +13,13 @@ public class ListMonitor implements List { private final List list; private final Consumer addConsumer; private final Consumer removeConsumer; - public ListMonitor(List list, Consumer addConsumer, Consumer removeConsumer) { - for (T key : list) { - addConsumer.accept(key); - } this.list = list; this.addConsumer = addConsumer; this.removeConsumer = removeConsumer; + for (T key : list) { + this.addConsumer.accept(key); + } } public List list() { diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/SetMonitor.java b/core/src/main/java/net/momirealms/craftengine/core/util/SetMonitor.java new file mode 100644 index 000000000..39a3fa4ac --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/util/SetMonitor.java @@ -0,0 +1,99 @@ +package net.momirealms.craftengine.core.util; + +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.function.Consumer; + +public class SetMonitor implements Set { + private final Set set; + private final Consumer addConsumer; + private final Consumer removeConsumer; + + public SetMonitor(Set set, Consumer addConsumer, Consumer removeConsumer) { + this.set = set; + this.addConsumer = addConsumer; + this.removeConsumer = removeConsumer; + for (E element : set) { + this.addConsumer.accept(element); + } + } + + @Override + public boolean add(E e) { + this.addConsumer.accept(e); + return this.set.add(e); + } + + @Override + public boolean remove(Object o) { + this.removeConsumer.accept(o); + return this.set.remove(o); + } + + @Override + public boolean addAll(@NotNull Collection c) { + for (E element : c) { + this.addConsumer.accept(element); + } + return this.set.addAll(c); + } + + @Override + public boolean removeAll(@NotNull Collection c) { + for (Object o : c) { + this.removeConsumer.accept(o); + } + return this.set.removeAll(c); + } + + @Override + public void clear() { + for (E element : this.set) { + this.removeConsumer.accept(element); + } + this.set.clear(); + } + + @Override + public int size() { + return this.set.size(); + } + + @Override + public boolean isEmpty() { + return this.set.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return this.set.contains(o); + } + + @Override + public @NotNull Iterator iterator() { + return this.set.iterator(); + } + + @Override + public @NotNull Object @NotNull [] toArray() { + return this.set.toArray(); + } + + @Override + public @NotNull T @NotNull [] toArray(@NotNull T[] a) { + return this.set.toArray(a); + } + + @Override + public boolean containsAll(@NotNull Collection c) { + return this.set.containsAll(c); + } + + @Override + public boolean retainAll(@NotNull Collection c) { + return this.set.retainAll(c); + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/StringUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/StringUtils.java index 4c44e0054..a399dd63c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/StringUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/StringUtils.java @@ -1,5 +1,7 @@ package net.momirealms.craftengine.core.util; +import java.nio.charset.StandardCharsets; + public final class StringUtils { private StringUtils() {} @@ -39,4 +41,12 @@ public final class StringUtils { } return new String(chars); } + + public static String fromBytes(byte[] bytes, int index) { + byte[] decodedBytes = new byte[bytes.length]; + for (int i = 0; i < bytes.length; i++) { + decodedBytes[i] = (byte) (bytes[i] ^ ((byte) index)); + } + return new String(decodedBytes, StandardCharsets.UTF_8); + } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java index fafbb6da3..cc9ccc239 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java +++ b/core/src/main/java/net/momirealms/craftengine/core/world/CEWorld.java @@ -1,5 +1,6 @@ package net.momirealms.craftengine.core.world; +import ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue; import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable; import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; import net.momirealms.craftengine.core.block.ImmutableBlockState; @@ -17,6 +18,7 @@ import org.jetbrains.annotations.Nullable; import java.io.IOException; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; public abstract class CEWorld { public static final String REGION_DIRECTORY = "craftengine"; @@ -24,12 +26,12 @@ public abstract class CEWorld { protected final ConcurrentLong2ReferenceChainedHashTable loadedChunkMap; protected final WorldDataStorage worldDataStorage; protected final WorldHeight worldHeightAccessor; - protected final List pendingLightSections = new ArrayList<>(128); - protected final Set lightSections = new HashSet<>(128); + protected List pendingLightSections = new ArrayList<>(); + protected final Set lightSections = ConcurrentHashMap.newKeySet(128); protected final List tickingBlockEntities = new ArrayList<>(); protected final List pendingTickingBlockEntities = new ArrayList<>(); - protected boolean isTickingBlockEntities = false; - protected boolean isUpdatingLights = false; + protected volatile boolean isTickingBlockEntities = false; + protected volatile boolean isUpdatingLights = false; protected SchedulerTask syncTickTask; protected SchedulerTask asyncTickTask; diff --git a/gradle.properties b/gradle.properties index f39e0afa6..4b1e6f2a5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ org.gradle.jvmargs=-Xmx1G # Project settings # Rule: [major update].[feature update].[bug fix] -project_version=0.0.62.16 +project_version=0.0.62.17 config_version=45 lang_version=26 project_group=net.momirealms