diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/entity/DelegateEntity.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/entity/DelegateEntity.java new file mode 100644 index 000000000..449e43102 --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/entity/DelegateEntity.java @@ -0,0 +1,52 @@ +package com.dfsek.terra.fabric.entity; + +import com.dfsek.terra.api.entity.Entity; +import com.dfsek.terra.api.entity.EntityType; +import com.dfsek.terra.api.util.vector.Vector3; +import com.dfsek.terra.api.world.ServerWorld; + +import net.minecraft.world.ServerWorldAccess; + + +public class DelegateEntity implements Entity { + private Vector3 position; + private ServerWorld world; + private final EntityType type; + + public DelegateEntity(Vector3 position, ServerWorld world, EntityType type) { + this.world = world; + this.position = position; + this.type = type; + } + + @Override + public Vector3 position() { + return position; + } + + @Override + public void position(Vector3 position) { + this.position = position; + } + + @Override + public ServerWorld world() { + return world; + } + + @Override + public void world(ServerWorld world) { + this.world = world; + } + + @Override + public Object getHandle() { + return this; + } + + public net.minecraft.entity.Entity createMinecraftEntity(ServerWorldAccess world) { + net.minecraft.entity.Entity entity = ((net.minecraft.entity.EntityType) type).create(world.toServerWorld()); + entity.setPos(position.getX(), position.getY(), position.getZ()); + return entity; + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/entity/DelegateEntityHolder.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/entity/DelegateEntityHolder.java new file mode 100644 index 000000000..46ea6c8f0 --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/entity/DelegateEntityHolder.java @@ -0,0 +1,10 @@ +package com.dfsek.terra.fabric.entity; + +import java.util.List; + + +public interface DelegateEntityHolder { + List getAndClearTerraEntities(); + + void addTerraEntity(DelegateEntity entity); +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java index ec5eeef2a..b3eaecf45 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java @@ -27,6 +27,8 @@ import com.dfsek.terra.api.world.chunk.generation.util.GeneratorWrapper; import com.dfsek.terra.api.world.info.WorldProperties; import com.dfsek.terra.fabric.config.PreLoadCompatibilityOptions; import com.dfsek.terra.fabric.data.Codecs; +import com.dfsek.terra.fabric.entity.DelegateEntityHolder; +import com.dfsek.terra.fabric.mixin.access.ChunkRegionAccessor; import com.dfsek.terra.fabric.mixin.access.StructureAccessorAccessor; import com.dfsek.terra.fabric.util.FabricAdapter; @@ -95,7 +97,8 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C ChunkPos pos = chunk.getPos(); ((BiomeProviderHolder) chunk) .terra$setHeldBiomeProvider(pack.getBiomeProvider() - .caching((ProtoWorld) ((StructureAccessorAccessor) structureAccessor).getWorld(), pos.x, pos.z)); + .caching((ProtoWorld) ((StructureAccessorAccessor) structureAccessor).getWorld(), pos.x, + pos.z)); } return super.populateBiomes(biomeRegistry, executor, noiseConfig, blender, structureAccessor, chunk); } @@ -116,6 +119,13 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C @Override public void populateEntities(ChunkRegion region) { + ((ChunkRegionAccessor) region) + .getChunks() + .forEach( + chunk -> ((DelegateEntityHolder) chunk) + .getAndClearTerraEntities() + .forEach(entity -> chunk.addEntity(entity.createMinecraftEntity(region))) + ); if(!this.settings.value().mobGenerationDisabled()) { ChunkPos chunkPos = region.getCenterPos(); RegistryEntry registryEntry = region.getBiome(chunkPos.getStartPos().withY(region.getTopY() - 1)); diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/ChunkRegionAccessor.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/ChunkRegionAccessor.java new file mode 100644 index 000000000..2c471cf0e --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/ChunkRegionAccessor.java @@ -0,0 +1,15 @@ +package com.dfsek.terra.fabric.mixin.access; + +import net.minecraft.world.ChunkRegion; +import net.minecraft.world.chunk.Chunk; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; + + +@Mixin(ChunkRegion.class) +public interface ChunkRegionAccessor { + @Accessor("chunks") + List getChunks(); +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/entity_holder/ProtoChunkMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/entity_holder/ProtoChunkMixin.java new file mode 100644 index 000000000..899475f16 --- /dev/null +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/entity_holder/ProtoChunkMixin.java @@ -0,0 +1,46 @@ +package com.dfsek.terra.fabric.mixin.entity_holder; + +import com.dfsek.terra.fabric.entity.DelegateEntity; +import com.dfsek.terra.fabric.entity.DelegateEntityHolder; + +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.HeightLimitView; +import net.minecraft.world.chunk.ChunkSection; +import net.minecraft.world.chunk.ProtoChunk; +import net.minecraft.world.chunk.UpgradeData; +import net.minecraft.world.gen.chunk.BlendingData; +import net.minecraft.world.tick.SimpleTickScheduler; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +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.CallbackInfo; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; + + +@Mixin(ProtoChunk.class) +@Implements(@Interface(iface = DelegateEntityHolder.class, prefix = "terra$")) +public class ProtoChunkMixin { + private AtomicReference> terra$entities; + + @Inject(method = "*", at = @At("RETURN")) + public void injectConstructor(CallbackInfo ci) { + this.terra$entities = new AtomicReference<>(new ArrayList<>()); + } + + public List terra$getAndClearTerraEntities() { + return terra$entities.getAndSet(new ArrayList<>()); + } + + public void terra$addTerraEntity(DelegateEntity entity) { + this.terra$entities.updateAndGet(list -> { + list.add(entity); + return list; + }); + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/world/ChunkRegionMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/world/ChunkRegionMixin.java index 293b7f345..bae1c94b8 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/world/ChunkRegionMixin.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/world/ChunkRegionMixin.java @@ -28,6 +28,8 @@ import com.dfsek.terra.api.world.ServerWorld; import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator; import com.dfsek.terra.api.world.chunk.generation.ProtoWorld; +import com.dfsek.terra.fabric.entity.DelegateEntity; +import com.dfsek.terra.fabric.entity.DelegateEntityHolder; import com.dfsek.terra.fabric.generation.BiomeProviderHolder; import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper; import com.dfsek.terra.fabric.generation.TerraBiomeSource; @@ -47,13 +49,15 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import java.util.ArrayList; import java.util.List; @Mixin(ChunkRegion.class) @Implements(@Interface(iface = ProtoWorld.class, prefix = "terraWorld$")) public abstract class ChunkRegionMixin { - private ConfigPack config; + private ConfigPack terra$config; + @Shadow @Final @@ -70,27 +74,28 @@ public abstract class ChunkRegionMixin { @Final private MultiTickScheduler fluidTickScheduler; - @SuppressWarnings("deprecation") - private final Lazy caching = Lazy.lazy(() -> ((TerraBiomeSource) ((ChunkRegion) (Object) this) - .toServerWorld() - .getChunkManager() - .getChunkGenerator() - .getBiomeSource()).getProvider().caching((ProtoWorld) this)); + @Shadow + public abstract net.minecraft.server.world.ServerWorld toServerWorld(); + @Shadow + public abstract Chunk getChunk(int chunkX, int chunkZ); + + private Lazy caching; + + @SuppressWarnings("deprecation") @Inject(at = @At("RETURN"), method = "(Lnet/minecraft/server/world/ServerWorld;Ljava/util/List;Lnet/minecraft/world/chunk/ChunkStatus;I)V") public void injectConstructor(net.minecraft.server.world.ServerWorld world, List list, ChunkStatus chunkStatus, int i, CallbackInfo ci) { - this.config = ((ServerWorld) world).getPack(); + this.terra$config = ((ServerWorld) world).getPack(); + this.caching = Lazy.lazy(() -> ((TerraBiomeSource) ((ChunkRegion) (Object) this) + .toServerWorld() + .getChunkManager() + .getChunkGenerator() + .getBiomeSource()).getProvider().caching((ProtoWorld) this)); } - public Entity terraWorld$spawnEntity(Vector3 location, EntityType entityType) { - net.minecraft.entity.Entity entity = ((net.minecraft.entity.EntityType) entityType).create(null); - entity.setPos(location.getX(), location.getY(), location.getZ()); - ((ChunkRegion) (Object) this).spawnEntity(entity); - return (Entity) entity; - } @Intrinsic(displace = true) public void terraWorld$setBlockState(int x, int y, int z, BlockState data, boolean physics) { @@ -139,10 +144,9 @@ public abstract class ChunkRegionMixin { } public Entity terraWorld$spawnEntity(double x, double y, double z, EntityType entityType) { - net.minecraft.entity.Entity entity = ((net.minecraft.entity.EntityType) entityType).create(null); - entity.setPos(x, y, z); - ((ChunkRegion) (Object) this).spawnEntity(entity); - return (Entity) entity; + DelegateEntity entity = new DelegateEntity(Vector3.of(x, y, z), (ServerWorld) this.toServerWorld(), entityType); + ((DelegateEntityHolder) getChunk((int) x / 16, (int) z / 16)).addTerraEntity(entity); + return entity; } public int terraWorld$centerChunkX() { @@ -158,6 +162,6 @@ public abstract class ChunkRegionMixin { } public ConfigPack terraWorld$getPack() { - return config; + return terra$config; } } diff --git a/platforms/fabric/src/main/resources/terra.mixins.json b/platforms/fabric/src/main/resources/terra.mixins.json index ad1d97bb9..82b9818df 100644 --- a/platforms/fabric/src/main/resources/terra.mixins.json +++ b/platforms/fabric/src/main/resources/terra.mixins.json @@ -1,53 +1,55 @@ { - "required": true, - "minVersion": "0.8", - "package": "com.dfsek.terra.fabric.mixin", - "compatibilityLevel": "JAVA_17", - "mixins": [ - "access.MobSpawnerLogicAccessor", - "access.StateAccessor", - "access.StructureAccessorAccessor", - "cache.ChunkRegionMixin", - "cache.ProtoChunkMixin", - "compat.GenerationSettingsFloraFeaturesMixin", - "fix.NetherFossilOptimization", - "implementations.BiomeMixin", - "implementations.HandleImplementationMixin", - "implementations.block.BlockMixin", - "implementations.block.entity.BlockEntityMixin", - "implementations.block.entity.LootableContainerBlockEntityMixin", - "implementations.block.entity.MobSpawnerBlockEntityMixin", - "implementations.block.entity.SignBlockEntityMixin", - "implementations.block.state.BlockStateMixin", - "implementations.block.state.PropertyMixin", - "implementations.chunk.ChunkRegionMixin", - "implementations.chunk.WorldChunkMixin", - "implementations.chunk.data.ProtoChunkMixin", - "implementations.entity.EntityMixin", - "implementations.entity.EntityTypeMixin", - "implementations.entity.PlayerEntityMixin", - "implementations.entity.ServerCommandSourceMixin", - "implementations.inventory.LockableContainerBlockEntityMixin", - "implementations.inventory.item.ItemMixin", - "implementations.inventory.item.ItemStackMixin", - "implementations.inventory.meta.EnchantmentMixin", - "implementations.inventory.meta.ItemStackDamageableMixin", - "implementations.inventory.meta.ItemStackMetaMixin", - "implementations.world.ChunkRegionMixin", - "implementations.world.ServerWorldMixin", - "lifecycle.DataPackContentsMixin", - "lifecycle.MinecraftServerMixin", - "lifecycle.NoiseConfigMixin", - "lifecycle.RegistryMixin" - ], - "client": [ - "lifecycle.client.MinecraftClientMixin" - ], - "server": [ - "lifecycle.server.ServerMainMixin" - ], - "injectors": { - "defaultRequire": 1 - }, - "refmap": "terra-refmap.json" + "required": true, + "minVersion": "0.8", + "package": "com.dfsek.terra.fabric.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "access.ChunkRegionAccessor", + "access.MobSpawnerLogicAccessor", + "access.StateAccessor", + "access.StructureAccessorAccessor", + "cache.ChunkRegionMixin", + "cache.ProtoChunkMixin", + "compat.GenerationSettingsFloraFeaturesMixin", + "entity_holder.ProtoChunkMixin", + "fix.NetherFossilOptimization", + "implementations.BiomeMixin", + "implementations.HandleImplementationMixin", + "implementations.block.BlockMixin", + "implementations.block.entity.BlockEntityMixin", + "implementations.block.entity.LootableContainerBlockEntityMixin", + "implementations.block.entity.MobSpawnerBlockEntityMixin", + "implementations.block.entity.SignBlockEntityMixin", + "implementations.block.state.BlockStateMixin", + "implementations.block.state.PropertyMixin", + "implementations.chunk.ChunkRegionMixin", + "implementations.chunk.WorldChunkMixin", + "implementations.chunk.data.ProtoChunkMixin", + "implementations.entity.EntityMixin", + "implementations.entity.EntityTypeMixin", + "implementations.entity.PlayerEntityMixin", + "implementations.entity.ServerCommandSourceMixin", + "implementations.inventory.LockableContainerBlockEntityMixin", + "implementations.inventory.item.ItemMixin", + "implementations.inventory.item.ItemStackMixin", + "implementations.inventory.meta.EnchantmentMixin", + "implementations.inventory.meta.ItemStackDamageableMixin", + "implementations.inventory.meta.ItemStackMetaMixin", + "implementations.world.ChunkRegionMixin", + "implementations.world.ServerWorldMixin", + "lifecycle.DataPackContentsMixin", + "lifecycle.MinecraftServerMixin", + "lifecycle.NoiseConfigMixin", + "lifecycle.RegistryMixin" + ], + "client": [ + "lifecycle.client.MinecraftClientMixin" + ], + "server": [ + "lifecycle.server.ServerMainMixin" + ], + "injectors": { + "defaultRequire": 1 + }, + "refmap": "terra-refmap.json" } \ No newline at end of file