diff --git a/build.gradle.kts b/build.gradle.kts index e83fbe1..b8b1e81 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -14,12 +14,14 @@ val aw2at = Aw2AtTask.configureDefault( ) sourceSets.create("lithium") +sourceSets.create("architectury") neoForge { neoFormVersion = libs.versions.neoform.get() validateAccessTransformers = true accessTransformers.files.setFrom(aw2at.flatMap { t -> t.outputFile }) addModdingDependenciesTo(sourceSets.getByName("lithium")) + addModdingDependenciesTo(sourceSets.getByName("architectury")) } dependencies { @@ -36,6 +38,7 @@ dependencies { compileOnly(libs.clothConfig.neoforge) "lithiumCompileOnly"("maven.modrinth:lithium:${rootProject.property("neo_lithium_version")}") + "architecturyCompileOnly"("maven.modrinth:architectury-api:${rootProject.property("neo_architectury_version")}") compileOnly(sourceSets.getByName("lithium").output) } diff --git a/fabric/build.gradle.kts b/fabric/build.gradle.kts index 02d5962..a59d3b9 100644 --- a/fabric/build.gradle.kts +++ b/fabric/build.gradle.kts @@ -24,8 +24,10 @@ dependencies { runtimeOnly(rootProject.sourceSets.main.get().output) runtimeOnly(rootProject.sourceSets.getByName("lithium").output) + runtimeOnly(rootProject.sourceSets.getByName("architectury").output) shadow(project(":")) shadow(rootProject.sourceSets.getByName("lithium").output) + shadow(rootProject.sourceSets.getByName("architectury").output) compileOnly(project(":")) libs(libs.concurrentutil) { isTransitive = false } @@ -111,6 +113,7 @@ loom { sourceSet("main") sourceSet("main", project.rootProject) sourceSet("lithium", project.rootProject) + sourceSet("architectury", project.rootProject) } } } diff --git a/fabric/src/main/java/ca/spottedleaf/moonrise/fabric/FabricHooks.java b/fabric/src/main/java/ca/spottedleaf/moonrise/fabric/FabricHooks.java index a39e8f4..793b4fa 100644 --- a/fabric/src/main/java/ca/spottedleaf/moonrise/fabric/FabricHooks.java +++ b/fabric/src/main/java/ca/spottedleaf/moonrise/fabric/FabricHooks.java @@ -3,6 +3,7 @@ import ca.spottedleaf.moonrise.common.util.BaseChunkSystemHooks; import ca.spottedleaf.moonrise.common.PlatformHooks; import ca.spottedleaf.moonrise.common.util.ConfigHolder; +import ca.spottedleaf.moonrise.compat.architectury.ArchitecturyHooks; import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType; import com.mojang.datafixers.DSL; import com.mojang.datafixers.DataFixer; @@ -43,6 +44,7 @@ public final class FabricHooks extends BaseChunkSystemHooks implements PlatformHooks { private static final boolean HAS_FABRIC_LIFECYCLE_EVENTS = FabricLoader.getInstance().isModLoaded("fabric-lifecycle-events-v1"); + public static final boolean HAS_ARCHITECTURY = FabricLoader.getInstance().isModLoaded("architectury"); private static final Logger LOGGER = LogUtils.getLogger(); @@ -112,7 +114,9 @@ public void chunkUnloadFromWorld(final LevelChunk chunk) { @Override public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final SerializableChunkData data) { - + if (HAS_ARCHITECTURY) { + ArchitecturyHooks.onSaveEvent(chunk, world, data); + } } @Override @@ -174,6 +178,9 @@ public void entityMove(final Entity entity, final long oldSection, final long ne @Override public boolean screenEntity(final ServerLevel world, final Entity entity, final boolean fromDisk, final boolean event) { + if (HAS_ARCHITECTURY) { + return ArchitecturyHooks.onEntityAdd(entity, world); + } return true; } diff --git a/gradle.properties b/gradle.properties index 83d4483..efb9691 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,3 +24,4 @@ junit_version=5.11.3 # version ids from modrinth fabric_lithium_version=iMuOZwcu neo_lithium_version=LGakFQ7r +neo_architectury_version=baQ6rP1K diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts index 546299f..60eb45c 100644 --- a/neoforge/build.gradle.kts +++ b/neoforge/build.gradle.kts @@ -23,6 +23,7 @@ neoForge { sourceSet(sourceSets.main.get()) sourceSet(rootProject.sourceSets.main.get()) sourceSet(rootProject.sourceSets.getByName("lithium")) + sourceSet(rootProject.sourceSets.getByName("architectury")) } } runs { @@ -44,8 +45,10 @@ val gui = rootProject.property("enable_gui").toString() == "true" dependencies { runtimeOnly(rootProject.sourceSets.main.get().output) runtimeOnly(rootProject.sourceSets.getByName("lithium").output) + runtimeOnly(rootProject.sourceSets.getByName("architectury").output) shadow(project(":")) shadow(rootProject.sourceSets.getByName("lithium").output) + shadow(rootProject.sourceSets.getByName("architectury").output) compileOnly(project(":")) libs(libs.concurrentutil) { isTransitive = false } diff --git a/neoforge/src/main/java/ca/spottedleaf/moonrise/neoforge/mixin/chunk_system/NeoForgePersistentEntitySectionManagerMixin.java b/neoforge/src/main/java/ca/spottedleaf/moonrise/neoforge/mixin/chunk_system/NeoForgePersistentEntitySectionManagerMixin.java new file mode 100644 index 0000000..16f4dbe --- /dev/null +++ b/neoforge/src/main/java/ca/spottedleaf/moonrise/neoforge/mixin/chunk_system/NeoForgePersistentEntitySectionManagerMixin.java @@ -0,0 +1,27 @@ +package ca.spottedleaf.moonrise.neoforge.mixin.chunk_system; + +import net.minecraft.world.level.entity.EntityAccess; +import net.minecraft.world.level.entity.PersistentEntitySectionManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(PersistentEntitySectionManager.class) +abstract class NeoForgePersistentEntitySectionManagerMixin { + @Inject( + method = "addNewEntityWithoutEvent", + at = @At("HEAD") + ) + private void addNewEntityWithoutEvent(T entity, CallbackInfoReturnable cir) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "addEntityWithoutEvent", + at = @At("HEAD") + ) + private void addEntityWithoutEvent(T entity, boolean worldGenSpawned, CallbackInfoReturnable cir) { + throw new UnsupportedOperationException(); + } +} diff --git a/neoforge/src/main/resources/moonrise-neoforge.mixins.json b/neoforge/src/main/resources/moonrise-neoforge.mixins.json index 33d9090..940a3f9 100644 --- a/neoforge/src/main/resources/moonrise-neoforge.mixins.json +++ b/neoforge/src/main/resources/moonrise-neoforge.mixins.json @@ -3,6 +3,7 @@ "package": "ca.spottedleaf.moonrise.neoforge.mixin", "mixins": [ "chunk_system.NeoForgeMinecraftServerMixin", + "chunk_system.NeoForgePersistentEntitySectionManagerMixin", "chunk_system.NeoForgeServerLevelMixin", "chunk_system.NeoForgeTicketStorageMixin", "collisions.EntityMixin", diff --git a/src/architectury/java/ca/spottedleaf/moonrise/compat/architectury/ArchitecturyHooks.java b/src/architectury/java/ca/spottedleaf/moonrise/compat/architectury/ArchitecturyHooks.java new file mode 100644 index 0000000..af4b755 --- /dev/null +++ b/src/architectury/java/ca/spottedleaf/moonrise/compat/architectury/ArchitecturyHooks.java @@ -0,0 +1,32 @@ +package ca.spottedleaf.moonrise.compat.architectury; + +import dev.architectury.event.events.common.ChunkEvent; +import dev.architectury.event.events.common.EntityEvent; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.storage.SerializableChunkData; + +public final class ArchitecturyHooks { + /** + * Invokes Architectury's ChunkEvent.SAVE_DATA event. + * + * @param chunkAccess The chunk that is saved. + * @param level The level the chunk is in. + * @param data The data. + */ + public static void onSaveEvent(ChunkAccess chunkAccess, ServerLevel level, SerializableChunkData data) { + ChunkEvent.SAVE_DATA.invoker().save(chunkAccess, level, data); + } + + /** + * Invokes Architectury's EntityEvent.ADD event. + * + * @param entity The entity that is added. + * @param level The level the entity is in. + * @return Whether the entity should be added. + */ + public static boolean onEntityAdd(Entity entity, ServerLevel level) { + return !EntityEvent.ADD.invoker().add(entity, level).isFalse(); + } +} diff --git a/src/architectury/resources/workaround_shadow_2 b/src/architectury/resources/workaround_shadow_2 new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ChunkMapMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ChunkMapMixin.java index c6007cd..47e9977 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ChunkMapMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ChunkMapMixin.java @@ -55,6 +55,7 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import java.io.IOException; import java.io.Writer; import java.nio.file.Path; @@ -480,8 +481,8 @@ public boolean saveChunkIfNeeded(final ChunkHolder chunkHolder, final long time) * @author Spottedleaf * @see NewChunkHolder#save(boolean) */ - @Overwrite - public boolean save(final ChunkAccess chunk) { + @Inject(method = "save", at = @At("HEAD")) + public void save(ChunkAccess chunk, CallbackInfoReturnable cir) { throw new UnsupportedOperationException(); } diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/PersistentEntitySectionManagerMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/PersistentEntitySectionManagerMixin.java new file mode 100644 index 0000000..639d848 --- /dev/null +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/PersistentEntitySectionManagerMixin.java @@ -0,0 +1,325 @@ +package ca.spottedleaf.moonrise.mixin.chunk_system; + +import it.unimi.dsi.fastutil.longs.Long2ObjectMap; +import it.unimi.dsi.fastutil.longs.LongSet; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.FullChunkStatus; +import net.minecraft.world.level.ChunkPos; +import net.minecraft.world.level.entity.*; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.io.Writer; +import java.util.Queue; +import java.util.Set; +import java.util.UUID; +import java.util.function.Consumer; +import java.util.stream.Stream; + +@Mixin(PersistentEntitySectionManager.class) +abstract class PersistentEntitySectionManagerMixin { + @Mutable @Shadow @Final EntitySectionStorage sectionStorage; + @Mutable @Shadow @Final private LevelEntityGetter entityGetter; + @Mutable @Shadow @Final LevelCallback callbacks; + @Mutable @Shadow @Final private EntityPersistentStorage permanentStorage; + @Mutable @Shadow @Final Set knownUuids; + @Mutable @Shadow @Final private Long2ObjectMap chunkVisibility; + @Mutable @Shadow @Final private Long2ObjectMap chunkLoadStatuses; + @Mutable @Shadow @Final private LongSet chunksToUnload; + @Mutable @Shadow @Final private Queue> loadingInbox; + @Mutable @Shadow @Final private EntityLookup visibleEntityStorage; + + @Inject( + method = "", + at = @At("RETURN") + ) + private void destroyFields(final CallbackInfo ci) { + this.sectionStorage = null; + this.entityGetter = null; + this.callbacks = null; + this.permanentStorage = null; + this.knownUuids = null; + this.chunkVisibility = null; + this.chunkLoadStatuses = null; + this.chunksToUnload = null; + this.loadingInbox = null; + this.visibleEntityStorage = null; + } + @Inject( + method = "addNewEntity", + at = @At("HEAD") + ) + private void addNewEntity(T access, CallbackInfoReturnable cir) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "addEntity", + at = @At("HEAD") + ) + private void addEntity(T access, boolean worldGenSpawned, CallbackInfoReturnable cir) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "removeSectionIfEmpty", + at = @At("HEAD") + ) + private void removeSectionIfEmpty(long sectionKey, EntitySection section, CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "addEntityUuid", + at = @At("HEAD") + ) + private void addEntityUuid(T access, CallbackInfoReturnable cir) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "getEffectiveStatus", + at = @At("HEAD") + ) + private static void getEffectiveStatus(T entity, Visibility visibility, CallbackInfoReturnable cir) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "isTicking", + at = @At("HEAD") + ) + private void isTicking(ChunkPos chunkPos, CallbackInfoReturnable cir) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "addLegacyChunkEntities", + at = @At("HEAD") + ) + private void addLegacyChunkEntities(Stream entities, CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "addWorldGenChunkEntities", + at = @At("HEAD") + ) + private void addWorldGenChunkEntities(Stream entities, CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "startTicking", + at = @At("HEAD") + ) + private void startTicking(T entity, CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "stopTicking", + at = @At("HEAD") + ) + private void stopTicking(T entity, CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "startTracking", + at = @At("HEAD") + ) + private void startTracking(T entity, CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "stopTracking", + at = @At("HEAD") + ) + private void stopTracking(T entity, CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "updateChunkStatus(Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/world/level/entity/Visibility;)V", + at = @At("HEAD") + ) + private void updateChunkStatus(ChunkPos chunkPos, Visibility visibility, CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "updateChunkStatus(Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/server/level/FullChunkStatus;)V", + at = @At("HEAD") + ) + private void updateChunkStatus(ChunkPos chunkPos, FullChunkStatus status, CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "ensureChunkQueuedForLoad", + at = @At("HEAD") + ) + private void ensureChunkQueuedForLoad(long chunkPosValue, CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "storeChunkSections", + at = @At("HEAD") + ) + private void storeChunkSections(long chunkPosValue, Consumer entityAction, CallbackInfoReturnable cir) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "requestChunkLoad", + at = @At("HEAD") + ) + private void requestChunkLoad(long chunkPosValue, CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "processChunkUnload", + at = @At("HEAD") + ) + private void processChunkUnload(long chunkPosValue, CallbackInfoReturnable cir) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "unloadEntity", + at = @At("HEAD") + ) + private void unloadEntity(T entity, CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "processUnloads", + at = @At("HEAD") + ) + private void processUnloads(CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "processPendingLoads", + at = @At("HEAD") + ) + private void processPendingLoads(CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "tick", + at = @At("HEAD") + ) + private void tick(CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "getAllChunksToSave", + at = @At("HEAD") + ) + private void getAllChunksToSave(CallbackInfoReturnable cir) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "autoSave", + at = @At("HEAD") + ) + private void autoSave(CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "saveAll", + at = @At("HEAD") + ) + private void saveAll(CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "close", + at = @At("HEAD") + ) + private void close(CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "isLoaded", + at = @At("HEAD") + ) + private void isLoaded(UUID uuid, CallbackInfoReturnable cir) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "getEntityGetter", + at = @At("HEAD") + ) + public void getEntityGetter(CallbackInfoReturnable> cir) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "canPositionTick(Lnet/minecraft/core/BlockPos;)Z", + at = @At("HEAD") + ) + public void canPositionTick(BlockPos pos, CallbackInfoReturnable cir) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "canPositionTick(Lnet/minecraft/world/level/ChunkPos;)Z", + at = @At("HEAD") + ) + public void canPositionTick(ChunkPos chunkPos, CallbackInfoReturnable cir) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "areEntitiesLoaded(J)Z", + at = @At("HEAD") + ) + public void areEntitiesLoaded(long chunkPos, CallbackInfoReturnable cir) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "dumpSections", + at = @At("HEAD") + ) + public void dumpSections(Writer writer, CallbackInfo ci) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "gatherStats", + at = @At("HEAD") + ) + public void gatherStats(CallbackInfoReturnable cir) { + throw new UnsupportedOperationException(); + } + + @Inject( + method = "count", + at = @At("HEAD") + ) + public void count(CallbackInfoReturnable cir) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerLevelMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerLevelMixin.java index c27e872..44b8d67 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerLevelMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/chunk_system/ServerLevelMixin.java @@ -141,7 +141,7 @@ private void init(MinecraftServer minecraftServer, Executor executor, ResourceKey resourceKey, LevelStem levelStem, boolean bl, long l, List list, boolean bl2, RandomSequences randomSequences, CallbackInfo ci) { - this.entityManager = null; + //this.entityManager = null; // Keep entityManager non-null, architectury needs it this.moonrise$setEntityLookup(new ServerEntityLookup((ServerLevel)(Object)this, ((ServerLevel)(Object)this).new EntityCallbacks())); this.chunkTaskScheduler = new ChunkTaskScheduler((ServerLevel)(Object)this); diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java index 2516a5b..70b360a 100644 --- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java +++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java @@ -2,12 +2,14 @@ import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable; import ca.spottedleaf.concurrentutil.map.SWMRLong2ObjectHashTable; +import ca.spottedleaf.moonrise.common.PlatformHooks; import ca.spottedleaf.moonrise.common.list.EntityList; import ca.spottedleaf.moonrise.common.util.CoordinateUtils; import ca.spottedleaf.moonrise.common.util.WorldUtil; import ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity; import net.minecraft.core.BlockPos; import net.minecraft.server.level.FullChunkStatus; +import net.minecraft.server.level.ServerLevel; import net.minecraft.util.AbortableIterationConsumer; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; diff --git a/src/main/resources/moonrise.mixins.json b/src/main/resources/moonrise.mixins.json index 5065353..932ea4d 100644 --- a/src/main/resources/moonrise.mixins.json +++ b/src/main/resources/moonrise.mixins.json @@ -38,6 +38,7 @@ "chunk_system.LevelReaderMixin", "chunk_system.MinecraftServerMixin", "chunk_system.NoiseBasedChunkGeneratorMixin", + "chunk_system.PersistentEntitySectionManagerMixin", "chunk_system.PlayerListMixin", "chunk_system.PlayerSpawnFinderMixin", "chunk_system.PoiManagerMixin",