From 98a9035ae82cef75c945b123bea3a10e97309571 Mon Sep 17 00:00:00 2001 From: dfsek Date: Sun, 19 Jun 2022 21:24:22 -0700 Subject: [PATCH 01/38] begin architectury implementation --- buildSrc/src/main/kotlin/DependencyConfig.kt | 1 + buildSrc/src/main/kotlin/Versions.kt | 7 + platforms/forge/build.gradle.kts | 88 +++++++ platforms/forge/gradle.properties | 1 + .../com/dfsek/terra/forge/ForgeAddon.java | 80 ++++++ .../dfsek/terra/forge/ForgeEntryPoint.java | 56 ++++ .../com/dfsek/terra/forge/PlatformImpl.java | 169 ++++++++++++ .../config/PostLoadCompatibilityOptions.java | 28 ++ .../config/PreLoadCompatibilityOptions.java | 60 +++++ .../forge/config/VanillaBiomeProperties.java | 76 ++++++ .../com/dfsek/terra/forge/data/Codecs.java | 65 +++++ .../FabricChunkGeneratorWrapper.java | 246 ++++++++++++++++++ .../forge/generation/TerraBiomeSource.java | 86 ++++++ .../terra/forge/handle/FabricItemHandle.java | 58 +++++ .../terra/forge/handle/FabricWorldHandle.java | 59 +++++ .../mixin/access/ChunkRegionAccessor.java | 15 ++ .../mixin/access/MobSpawnerLogicAccessor.java | 30 +++ .../forge/mixin/access/StateAccessor.java | 35 +++ .../access/StructureAccessorAccessor.java | 30 +++ ...oveGoalsUnsynchronizedRandomAccessFix.java | 27 ++ .../mixin/fix/NetherFossilOptimization.java | 29 +++ .../GenerationSettingsFloraFeaturesMixin.java | 32 +++ .../implementations/terra/BiomeMixin.java | 31 +++ .../terra/HandleImplementationMixin.java | 61 +++++ .../terra/block/BlockMixin.java | 44 ++++ .../terra/block/entity/BlockEntityMixin.java | 54 ++++ .../LootableContainerBlockEntityMixin.java | 35 +++ .../entity/MobSpawnerBlockEntityMixin.java | 131 ++++++++++ .../block/entity/SignBlockEntityMixin.java | 65 +++++ .../terra/block/state/BlockStateMixin.java | 83 ++++++ .../terra/block/state/PropertyMixin.java | 43 +++ .../terra/chunk/ChunkRegionMixin.java | 58 +++++ .../terra/chunk/WorldChunkMixin.java | 75 ++++++ .../terra/chunk/data/ProtoChunkMixin.java | 53 ++++ .../terra/entity/EntityMixin.java | 55 ++++ .../terra/entity/EntityTypeMixin.java | 29 +++ .../terra/entity/PlayerEntityMixin.java | 31 +++ .../entity/ServerCommandSourceMixin.java | 66 +++++ .../LockableContainerBlockEntityMixin.java | 47 ++++ .../terra/inventory/item/ItemMixin.java | 43 +++ .../terra/inventory/item/ItemStackMixin.java | 76 ++++++ .../inventory/meta/EnchantmentMixin.java | 53 ++++ .../meta/ItemStackDamageableMixin.java | 55 ++++ .../inventory/meta/ItemStackMetaMixin.java | 65 +++++ .../implementations/terra/package-info.java | 23 ++ .../terra/world/ChunkRegionMixin.java | 149 +++++++++++ .../terra/world/ServerWorldMixin.java | 102 ++++++++ .../lifecycle/DataPackContentsMixin.java | 28 ++ .../mixin/lifecycle/MinecraftServerMixin.java | 32 +++ .../mixin/lifecycle/NoiseConfigMixin.java | 31 +++ .../forge/mixin/lifecycle/RegistryMixin.java | 20 ++ .../client/MinecraftClientMixin.java | 41 +++ .../forge/mixin/lifecycle/package-info.java | 22 ++ .../lifecycle/server/ServerMainMixin.java | 40 +++ .../mixin_ifaces/FloraFeatureHolder.java | 10 + .../com/dfsek/terra/forge/util/BiomeUtil.java | 169 ++++++++++++ .../dfsek/terra/forge/util/FabricAdapter.java | 185 +++++++++++++ .../dfsek/terra/forge/util/FabricUtil.java | 61 +++++ .../dfsek/terra/forge/util/LifecycleUtil.java | 100 +++++++ .../terra/forge/util/ProtoPlatformBiome.java | 55 ++++ .../com/dfsek/terra/forge/util/SeedHack.java | 29 +++ .../com/dfsek/terra/forge/util/TagUtil.java | 103 ++++++++ .../src/main/resources/META-INF/mods.toml | 24 ++ .../src/main/resources/assets/terra/icon.png | Bin 0 -> 129860 bytes .../resources/assets/terra/lang/en_us.json | 4 + .../src/main/resources/terra.mixins.json | 53 ++++ settings.gradle.kts | 2 + 67 files changed, 3814 insertions(+) create mode 100644 platforms/forge/build.gradle.kts create mode 100644 platforms/forge/gradle.properties create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeAddon.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/config/PostLoadCompatibilityOptions.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/config/PreLoadCompatibilityOptions.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/config/VanillaBiomeProperties.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/data/Codecs.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/generation/FabricChunkGeneratorWrapper.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/generation/TerraBiomeSource.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/handle/FabricItemHandle.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/handle/FabricWorldHandle.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/ChunkRegionAccessor.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/MobSpawnerLogicAccessor.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/StateAccessor.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/StructureAccessorAccessor.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/NetherFossilOptimization.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/BiomeMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/HandleImplementationMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/BlockMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/BlockEntityMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/state/BlockStateMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/state/PropertyMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/ChunkRegionMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/WorldChunkMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityTypeMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/PlayerEntityMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/ServerCommandSourceMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/item/ItemMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/item/ItemStackMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/package-info.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ChunkRegionMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ServerWorldMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/DataPackContentsMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/MinecraftServerMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/RegistryMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/client/MinecraftClientMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/package-info.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/server/ServerMainMixin.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin_ifaces/FloraFeatureHolder.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/util/FabricAdapter.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/util/FabricUtil.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/util/SeedHack.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java create mode 100644 platforms/forge/src/main/resources/META-INF/mods.toml create mode 100644 platforms/forge/src/main/resources/assets/terra/icon.png create mode 100644 platforms/forge/src/main/resources/assets/terra/lang/en_us.json create mode 100644 platforms/forge/src/main/resources/terra.mixins.json diff --git a/buildSrc/src/main/kotlin/DependencyConfig.kt b/buildSrc/src/main/kotlin/DependencyConfig.kt index ecc0a8229..a507eb96c 100644 --- a/buildSrc/src/main/kotlin/DependencyConfig.kt +++ b/buildSrc/src/main/kotlin/DependencyConfig.kt @@ -34,6 +34,7 @@ fun Project.configureDependencies() { maven("https://repo.codemc.org/repository/maven-public") maven("https://repo.codemc.io/repository/nms/") maven("https://papermc.io/repo/repository/maven-public/") + maven ( "https://files.minecraftforge.net/maven/" ) } dependencies { diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index ca7ad4360..42a262e15 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -28,6 +28,13 @@ object Versions { const val minotaur = "1.1.0" } + object Forge { + const val minecraft = "1.19" + const val forge = "$minecraft-41.0.38" + const val yarn = "$minecraft+build.1" + const val architecuryLoom = "0.12.0-SNAPSHOT" + } + object Bukkit { const val paper = "1.18.2-R0.1-SNAPSHOT" const val paperLib = "1.0.5" diff --git a/platforms/forge/build.gradle.kts b/platforms/forge/build.gradle.kts new file mode 100644 index 000000000..73aee97a0 --- /dev/null +++ b/platforms/forge/build.gradle.kts @@ -0,0 +1,88 @@ +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar +import com.modrinth.minotaur.TaskModrinthUpload +import net.fabricmc.loom.task.RemapJarTask +import java.util.Date + +plugins { + id("dev.architectury.loom") version Versions.Forge.architecuryLoom + id("com.modrinth.minotaur") version Versions.Fabric.minotaur +} + +loom { + mixin { + defaultRefmapName.set("terra-refmap.json") + } + + forge { + mixinConfigs.set(listOf("terra.mixins.json")) + + } + +} + +dependencies { + shadedApi(project(":common:implementation:base")) + + forge("net.minecraftforge:forge:${Versions.Forge.forge}") + + minecraft("com.mojang:minecraft:${Versions.Forge.minecraft}") + mappings("net.fabricmc:yarn:${Versions.Forge.yarn}:v2") +} + + + + + +addonDir(project.file("./run/config/Terra/addons"), tasks.named("runClient").get()) +addonDir(project.file("./run/config/Terra/addons"), tasks.named("runServer").get()) + +tasks.withType().configureEach { + options.release.set(17) +} + +tasks.getByName("shadowJar") { + exclude("org/slf4j/**") +} + +val remapped = tasks.register("remapShadedJar") { + dependsOn("installAddons") + group = "loom" + val shadowJar = tasks.getByName("shadowJar") + dependsOn(shadowJar) + inputFile.set(shadowJar.archiveFile) + archiveFileName.set(shadowJar.archiveFileName.get().replace(Regex("-shaded\\.jar$"), "-shaded-mapped.jar")) + addNestedDependencies.set(true) +} + +tasks.named("assemble").configure { + dependsOn("remapShadedJar") +} + +tasks.withType { + finalizedBy(remapped) + manifest { + attributes( + mapOf( + "Specification-Title" to "terra", + "Specification-Vendor" to "Terra Contributors", + "Specification-Version" to "1", + "Implementation-Title" to project.name, + "Implementation-Version" to "@VERSION@", + "Implementation-Vendor" to "Terra Contributors", + "Implementation-Timestamp" to Date().toString() + ) + ) + } +} + +tasks.register("publishModrinth") { + dependsOn("remapShadedJar") + group = "loom" + token = System.getenv("MODRINTH_SECRET") + projectId = "FIlZB9L0" + versionNumber = "${project.version}-forge" + uploadFile = remapped.get().archiveFile.get().asFile + releaseType = "beta" + addGameVersion(Versions.Forge.minecraft) + addLoader("forge") +} \ No newline at end of file diff --git a/platforms/forge/gradle.properties b/platforms/forge/gradle.properties new file mode 100644 index 000000000..82425854e --- /dev/null +++ b/platforms/forge/gradle.properties @@ -0,0 +1 @@ +loom.platform=forge diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeAddon.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeAddon.java new file mode 100644 index 000000000..320c03fe2 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeAddon.java @@ -0,0 +1,80 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge; + +import ca.solostudios.strata.Versions; +import ca.solostudios.strata.version.Version; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.dfsek.terra.api.addon.BaseAddon; +import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent; +import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent; +import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; +import com.dfsek.terra.api.event.functional.FunctionalEventHandler; +import com.dfsek.terra.api.world.biome.Biome; +import com.dfsek.terra.forge.config.PostLoadCompatibilityOptions; +import com.dfsek.terra.forge.config.PreLoadCompatibilityOptions; +import com.dfsek.terra.forge.config.VanillaBiomeProperties; + + +public final class ForgeAddon implements BaseAddon { + private static final Version VERSION = Versions.getVersion(1, 0, 0); + private static final Logger logger = LoggerFactory.getLogger(ForgeAddon.class); + private final PlatformImpl terraForgePlugin; + + public ForgeAddon(PlatformImpl terraForgePlugin) { + this.terraForgePlugin = terraForgePlugin; + } + + @Override + public void initialize() { + terraForgePlugin.getEventManager() + .getHandler(FunctionalEventHandler.class) + .register(this, ConfigPackPreLoadEvent.class) + .then(event -> event.getPack().getContext().put(event.loadTemplate(new PreLoadCompatibilityOptions()))) + .global(); + + terraForgePlugin.getEventManager() + .getHandler(FunctionalEventHandler.class) + .register(this, ConfigPackPostLoadEvent.class) + .then(event -> event.getPack().getContext().put(event.loadTemplate(new PostLoadCompatibilityOptions()))) + .priority(100) + .global(); + + terraForgePlugin.getEventManager() + .getHandler(FunctionalEventHandler.class) + .register(this, ConfigurationLoadEvent.class) + .then(event -> { + if(event.is(Biome.class)) { + event.getLoadedObject(Biome.class).getContext().put(event.load(new VanillaBiomeProperties())); + } + }) + .global(); + } + + @Override + public Version getVersion() { + return VERSION; + } + + @Override + public String getID() { + return "terra-fabric"; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java new file mode 100644 index 000000000..22194ac6e --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java @@ -0,0 +1,56 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge; + +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.dfsek.terra.forge.data.Codecs; + +@Mod("terra") +public class ForgeEntryPoint { + private static final Logger logger = LoggerFactory.getLogger(ForgeEntryPoint.class); + + private static final PlatformImpl TERRA_PLUGIN = new PlatformImpl(); + + + public static PlatformImpl getPlatform() { + return TERRA_PLUGIN; + } + + public static void register() { // register the things + Registry.register(Registry.CHUNK_GENERATOR, new Identifier("terra:terra"), Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER); + Registry.register(Registry.BIOME_SOURCE, new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE); + } + + public ForgeEntryPoint() { + IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); + + modEventBus.addListener(this::commonSetup); + } + + private void commonSetup(final FMLCommonSetupEvent event) { + logger.info("Initializing Terra Forge mod..."); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java new file mode 100644 index 000000000..3e3791142 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java @@ -0,0 +1,169 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge; + +import ca.solostudios.strata.Versions; +import ca.solostudios.strata.parser.tokenizer.ParseException; +import ca.solostudios.strata.version.Version; +import com.dfsek.tectonic.api.TypeRegistry; +import com.dfsek.tectonic.api.depth.DepthTracker; +import com.dfsek.tectonic.api.exception.LoadException; +import net.minecraft.MinecraftVersion; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.BuiltinRegistries; +import net.minecraft.world.biome.Biome.Precipitation; +import net.minecraft.world.biome.BiomeEffects.GrassColorModifier; +import net.minecraftforge.fml.loading.FMLLoader; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import com.dfsek.terra.AbstractPlatform; +import com.dfsek.terra.addon.EphemeralAddon; +import com.dfsek.terra.api.addon.BaseAddon; +import com.dfsek.terra.api.handle.ItemHandle; +import com.dfsek.terra.api.handle.WorldHandle; +import com.dfsek.terra.api.util.generic.Lazy; +import com.dfsek.terra.api.world.biome.PlatformBiome; +import com.dfsek.terra.forge.generation.FabricChunkGeneratorWrapper; +import com.dfsek.terra.forge.handle.FabricItemHandle; +import com.dfsek.terra.forge.handle.FabricWorldHandle; +import com.dfsek.terra.forge.util.BiomeUtil; +import com.dfsek.terra.forge.util.ProtoPlatformBiome; + + +public class PlatformImpl extends AbstractPlatform { + private static final Logger LOGGER = LoggerFactory.getLogger(PlatformImpl.class); + private final ItemHandle itemHandle = new FabricItemHandle(); + private final WorldHandle worldHandle = new FabricWorldHandle(); + private final Lazy dataFolder = Lazy.lazy(() -> new File("./config/Terra")); + private MinecraftServer server; + + public PlatformImpl() { + load(); + } + + public void setServer(MinecraftServer server) { + this.server = server; + } + + public MinecraftServer getServer() { + return server; + } + + @Override + public boolean reload() { + getTerraConfig().load(this); + getRawConfigRegistry().clear(); + boolean succeed = getRawConfigRegistry().loadAll(this); + + + if(server != null) { + server.reloadResources(server.getDataPackManager().getNames()).exceptionally(throwable -> { + LOGGER.warn("Failed to execute reload", throwable); + return null; + }).join(); + BiomeUtil.registerBiomes(); + server.getWorlds().forEach(world -> { + if(world.getChunkManager().getChunkGenerator() instanceof FabricChunkGeneratorWrapper chunkGeneratorWrapper) { + getConfigRegistry().get(chunkGeneratorWrapper.getPack().getRegistryKey()).ifPresent(pack -> { + chunkGeneratorWrapper.setPack(pack); + LOGGER.info("Replaced pack in chunk generator for world {}", world); + }); + } + }); + } + return succeed; + } + + @Override + protected Iterable platformAddon() { + List addons = new ArrayList<>(); + + addons.add(new ForgeAddon(this)); + + String mcVersion = MinecraftVersion.CURRENT.getReleaseTarget(); + try { + addons.add(new EphemeralAddon(Versions.parseVersion(mcVersion), "minecraft")); + } catch(ParseException e) { + try { + addons.add(new EphemeralAddon(Versions.parseVersion(mcVersion + ".0"), "minecraft")); + } catch(ParseException ex) { + LOGGER.warn("Failed to parse Minecraft version", e); + } + } + + FMLLoader.getLoadingModList().getMods().forEach(mod -> { + String id = mod.getModId(); + if(id.equals("terra") || id.equals("minecraft") || id.equals("java")) return; + Version version = Versions.getVersion(mod.getVersion().getMajorVersion(), mod.getVersion().getMinorVersion(), mod.getVersion().getIncrementalVersion()); + addons.add(new EphemeralAddon(version, "forge:" + id)); + }); + + return addons; + } + + @Override + public @NotNull String platformName() { + return "Fabric"; + } + + @Override + public @NotNull WorldHandle getWorldHandle() { + return worldHandle; + } + + @Override + public @NotNull File getDataFolder() { + return dataFolder.value(); + } + + @Override + public @NotNull ItemHandle getItemHandle() { + return itemHandle; + } + + @Override + public void register(TypeRegistry registry) { + super.register(registry); + registry.registerLoader(PlatformBiome.class, (type, o, loader, depthTracker) -> parseBiome((String) o, depthTracker)) + .registerLoader(Identifier.class, (type, o, loader, depthTracker) -> { + Identifier identifier = Identifier.tryParse((String) o); + if(identifier == null) + throw new LoadException("Invalid identifier: " + o, depthTracker); + return identifier; + }) + .registerLoader(Precipitation.class, (type, o, loader, depthTracker) -> Precipitation.valueOf(((String) o).toUpperCase( + Locale.ROOT))) + .registerLoader(GrassColorModifier.class, (type, o, loader, depthTracker) -> GrassColorModifier.valueOf(((String) o).toUpperCase( + Locale.ROOT))); + } + + + private ProtoPlatformBiome parseBiome(String id, DepthTracker tracker) throws LoadException { + Identifier identifier = Identifier.tryParse(id); + if(BuiltinRegistries.BIOME.get(identifier) == null) throw new LoadException("Invalid Biome ID: " + identifier, tracker); // failure. + return new ProtoPlatformBiome(identifier); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/config/PostLoadCompatibilityOptions.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/config/PostLoadCompatibilityOptions.java new file mode 100644 index 000000000..1a8ad12ba --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/config/PostLoadCompatibilityOptions.java @@ -0,0 +1,28 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.config; + +import com.dfsek.tectonic.api.config.template.ConfigTemplate; + +import com.dfsek.terra.api.properties.Properties; + + +@SuppressWarnings("FieldMayBeFinal") +public class PostLoadCompatibilityOptions implements ConfigTemplate, Properties { + +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/config/PreLoadCompatibilityOptions.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/config/PreLoadCompatibilityOptions.java new file mode 100644 index 000000000..bf7c3b7bc --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/config/PreLoadCompatibilityOptions.java @@ -0,0 +1,60 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.config; + +import com.dfsek.tectonic.api.config.template.ConfigTemplate; +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; + +import com.dfsek.terra.api.properties.Properties; + + +@SuppressWarnings("FieldMayBeFinal") +public class PreLoadCompatibilityOptions implements ConfigTemplate, Properties { + @Value("fabric.use-vanilla-biomes") + @Default + private boolean vanillaBiomes = false; + + @Value("fabric.beard.enable") + @Default + private boolean beard = true; + + @Value("fabric.beard.threshold") + @Default + private double beardThreshold = 0.5; + + @Value("fabric.beard.air-threshold") + @Default + private double airThreshold = -0.5; + + public boolean useVanillaBiomes() { + return vanillaBiomes; + } + + public boolean isBeard() { + return beard; + } + + public double getBeardThreshold() { + return beardThreshold; + } + + public double getAirThreshold() { + return airThreshold; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/config/VanillaBiomeProperties.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/config/VanillaBiomeProperties.java new file mode 100644 index 000000000..b4baa1882 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/config/VanillaBiomeProperties.java @@ -0,0 +1,76 @@ +package com.dfsek.terra.forge.config; + +import com.dfsek.tectonic.api.config.template.ConfigTemplate; +import com.dfsek.tectonic.api.config.template.annotations.Default; +import com.dfsek.tectonic.api.config.template.annotations.Value; +import net.minecraft.world.biome.Biome.Precipitation; +import net.minecraft.world.biome.BiomeEffects.GrassColorModifier; + +import com.dfsek.terra.api.properties.Properties; + + +public class VanillaBiomeProperties implements ConfigTemplate, Properties { + @Value("colors.grass") + @Default + private Integer grassColor = null; + + @Value("colors.fog") + @Default + private Integer fogColor = null; + + @Value("colors.water") + @Default + private Integer waterColor = null; + + @Value("colors.water-fog") + @Default + private Integer waterFogColor = null; + + @Value("colors.foliage") + @Default + private Integer foliageColor = null; + + @Value("colors.sky") + @Default + private Integer skyColor = null; + + @Value("colors.modifier") + @Default + private GrassColorModifier modifier = null; + + @Value("climate.precipitation") + @Default + private Precipitation precipitation = null; + + public Integer getFogColor() { + return fogColor; + } + + public Integer getFoliageColor() { + return foliageColor; + } + + public Integer getGrassColor() { + return grassColor; + } + + public Integer getWaterColor() { + return waterColor; + } + + public Integer getWaterFogColor() { + return waterFogColor; + } + + public Integer getSkyColor() { + return skyColor; + } + + public Precipitation getPrecipitation() { + return precipitation; + } + + public GrassColorModifier getModifier() { + return modifier; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/data/Codecs.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/data/Codecs.java new file mode 100644 index 000000000..95bf25e1a --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/data/Codecs.java @@ -0,0 +1,65 @@ +package com.dfsek.terra.forge.data; + +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.registry.key.RegistryKey; +import com.dfsek.terra.forge.ForgeEntryPoint; +import com.dfsek.terra.forge.generation.FabricChunkGeneratorWrapper; +import com.dfsek.terra.forge.generation.TerraBiomeSource; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.util.dynamic.RegistryOps; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; + + +public final class Codecs { + public static final Codec TERRA_REGISTRY_KEY = RecordCodecBuilder + .create(registryKey -> registryKey.group(Codec.STRING.fieldOf("namespace") + .stable() + .forGetter(RegistryKey::getNamespace), + Codec.STRING.fieldOf("id") + .stable() + .forGetter(RegistryKey::getID)) + .apply(registryKey, registryKey.stable(RegistryKey::of))); + + public static final Codec CONFIG_PACK = RecordCodecBuilder + .create(config -> config.group(TERRA_REGISTRY_KEY.fieldOf("pack") + .stable() + .forGetter(ConfigPack::getRegistryKey)) + .apply(config, config.stable(id -> ForgeEntryPoint.getPlatform() + .getConfigRegistry() + .get(id) + .orElseThrow(() -> new IllegalArgumentException( + "No such config pack " + + id))))); + + public static final Codec TERRA_BIOME_SOURCE = RecordCodecBuilder + .create(instance -> instance.group(RegistryOps.createRegistryCodec(Registry.BIOME_KEY) + .fieldOf("biome_registry") + .stable() + .forGetter(TerraBiomeSource::getBiomeRegistry), + CONFIG_PACK.fieldOf("pack") + .stable() + .forGetter(TerraBiomeSource::getPack)) + .apply(instance, instance.stable(TerraBiomeSource::new))); + + public static final Codec FABRIC_CHUNK_GENERATOR_WRAPPER = RecordCodecBuilder + .create( + instance -> instance.group( + RegistryOps.createRegistryCodec(Registry.STRUCTURE_SET_KEY) + .fieldOf("structure_registry") + .stable() + .forGetter(FabricChunkGeneratorWrapper::getNoiseRegistry), + TERRA_BIOME_SOURCE.fieldOf("biome_source") + .stable() + .forGetter(FabricChunkGeneratorWrapper::getBiomeSource), + CONFIG_PACK.fieldOf("pack") + .stable() + .forGetter(FabricChunkGeneratorWrapper::getPack), + ChunkGeneratorSettings.REGISTRY_CODEC.fieldOf("settings") + .stable() + .forGetter(FabricChunkGeneratorWrapper::getSettings) + ).apply(instance, instance.stable(FabricChunkGeneratorWrapper::new)) + ); +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/FabricChunkGeneratorWrapper.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/FabricChunkGeneratorWrapper.java new file mode 100644 index 000000000..e31bb40b2 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/FabricChunkGeneratorWrapper.java @@ -0,0 +1,246 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.generation; + +import com.mojang.serialization.Codec; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.structure.StructureSet; +import net.minecraft.util.Util; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.random.CheckedRandom; +import net.minecraft.util.math.random.ChunkRandom; +import net.minecraft.util.math.random.RandomSeed; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryEntry; +import net.minecraft.world.ChunkRegion; +import net.minecraft.world.HeightLimitView; +import net.minecraft.world.Heightmap.Type; +import net.minecraft.world.SpawnHelper; +import net.minecraft.world.StructureWorldAccess; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.source.BiomeAccess; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.gen.GenerationStep.Carver; +import net.minecraft.world.gen.StructureAccessor; +import net.minecraft.world.gen.StructureWeightSampler; +import net.minecraft.world.gen.chunk.Blender; +import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; +import net.minecraft.world.gen.chunk.VerticalBlockSample; +import net.minecraft.world.gen.densityfunction.DensityFunction.UnblendedNoisePos; +import net.minecraft.world.gen.noise.NoiseConfig; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +import com.dfsek.terra.api.config.ConfigPack; +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.ProtoChunk; +import com.dfsek.terra.api.world.chunk.generation.ProtoWorld; +import com.dfsek.terra.api.world.chunk.generation.stage.Chunkified; +import com.dfsek.terra.api.world.chunk.generation.util.GeneratorWrapper; +import com.dfsek.terra.api.world.info.WorldProperties; +import com.dfsek.terra.forge.config.PreLoadCompatibilityOptions; +import com.dfsek.terra.forge.data.Codecs; +import com.dfsek.terra.forge.mixin.access.StructureAccessorAccessor; +import com.dfsek.terra.forge.util.FabricAdapter; + + +public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.ChunkGenerator implements GeneratorWrapper { + private static final Logger logger = LoggerFactory.getLogger(FabricChunkGeneratorWrapper.class); + + private final TerraBiomeSource biomeSource; + private final Registry noiseRegistry; + private final RegistryEntry settings; + private ChunkGenerator delegate; + private ConfigPack pack; + + public FabricChunkGeneratorWrapper(Registry noiseRegistry, TerraBiomeSource biomeSource, ConfigPack configPack, + RegistryEntry settingsSupplier) { + super(noiseRegistry, Optional.empty(), biomeSource); + this.noiseRegistry = noiseRegistry; + this.pack = configPack; + this.settings = settingsSupplier; + + this.delegate = pack.getGeneratorProvider().newInstance(pack); + logger.info("Loading world with config pack {}", pack.getID()); + this.biomeSource = biomeSource; + } + + public Registry getNoiseRegistry() { + return noiseRegistry; + } + + @Override + protected Codec getCodec() { + return Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER; + } + + @Override + public void buildSurface(ChunkRegion region, StructureAccessor structures, NoiseConfig noiseConfig, Chunk chunk) { + // no op + } + + @Override + public void populateEntities(ChunkRegion region) { + if(!this.settings.value().mobGenerationDisabled()) { + ChunkPos chunkPos = region.getCenterPos(); + RegistryEntry registryEntry = region.getBiome(chunkPos.getStartPos().withY(region.getTopY() - 1)); + ChunkRandom chunkRandom = new ChunkRandom(new CheckedRandom(RandomSeed.getSeed())); + chunkRandom.setPopulationSeed(region.getSeed(), chunkPos.getStartX(), chunkPos.getStartZ()); + SpawnHelper.populateEntities(region, registryEntry, chunkPos, chunkRandom); + } + } + + @Override + public int getWorldHeight() { + return settings.value().generationShapeConfig().height(); + } + + + @Override + public CompletableFuture populateNoise(Executor executor, Blender blender, NoiseConfig noiseConfig, + StructureAccessor structureAccessor, Chunk chunk) { + return CompletableFuture.supplyAsync(() -> { + ProtoWorld world = (ProtoWorld) ((StructureAccessorAccessor) structureAccessor).getWorld(); + BiomeProvider biomeProvider = pack.getBiomeProvider(); + delegate.generateChunkData((ProtoChunk) chunk, world, biomeProvider, chunk.getPos().x, chunk.getPos().z); + + PreLoadCompatibilityOptions compatibilityOptions = pack.getContext().get(PreLoadCompatibilityOptions.class); + if(compatibilityOptions.isBeard()) { + beard(structureAccessor, chunk, world, biomeProvider, compatibilityOptions); + } + return chunk; + }, Util.getMainWorkerExecutor()); + } + + private void beard(StructureAccessor structureAccessor, Chunk chunk, WorldProperties world, BiomeProvider biomeProvider, + PreLoadCompatibilityOptions compatibilityOptions) { + StructureWeightSampler structureWeightSampler = StructureWeightSampler.method_42695(structureAccessor, chunk.getPos()); + double threshold = compatibilityOptions.getBeardThreshold(); + double airThreshold = compatibilityOptions.getAirThreshold(); + int xi = chunk.getPos().x << 4; + int zi = chunk.getPos().z << 4; + for(int x = 0; x < 16; x++) { + for(int z = 0; z < 16; z++) { + int depth = 0; + for(int y = world.getMaxHeight(); y >= world.getMinHeight(); y--) { + double noise = structureWeightSampler.sample(new UnblendedNoisePos(x + xi, y, z + zi)); + if(noise > threshold) { + chunk.setBlockState(new BlockPos(x, y, z), (BlockState) delegate + .getPalette(x + xi, y, z + zi, world, biomeProvider) + .get(depth, x + xi, y, z + zi, world.getSeed()), false); + depth++; + } else if(noise < airThreshold) { + chunk.setBlockState(new BlockPos(x, y, z), Blocks.AIR.getDefaultState(), false); + } else { + depth = 0; + } + } + } + } + } + + @Override + public void generateFeatures(StructureWorldAccess world, Chunk chunk, StructureAccessor structureAccessor) { + super.generateFeatures(world, chunk, structureAccessor); + pack.getStages().forEach(populator -> { + if(!(populator instanceof Chunkified)) { + populator.populate((ProtoWorld) world); + } + }); + } + + @Override + public int getSeaLevel() { + return settings.value().seaLevel(); + } + + @Override + public int getMinimumY() { + return settings.value().generationShapeConfig().minimumY(); + } + + + @Override + public int getHeight(int x, int z, Type heightmap, HeightLimitView height, NoiseConfig noiseConfig) { + WorldProperties properties = FabricAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); + BiomeProvider biomeProvider = pack.getBiomeProvider(); + int min = height.getBottomY(); + for(int y = height.getTopY() - 1; y >= min; y--) { + if(heightmap + .getBlockPredicate() + .test((BlockState) delegate.getBlock(properties, x, y, z, biomeProvider))) return y + 1; + } + return min; + } + + @Override + public VerticalBlockSample getColumnSample(int x, int z, HeightLimitView height, NoiseConfig noiseConfig) { + BlockState[] array = new BlockState[height.getHeight()]; + WorldProperties properties = FabricAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); + BiomeProvider biomeProvider = pack.getBiomeProvider(); + for(int y = height.getTopY() - 1; y >= height.getBottomY(); y--) { + array[y - height.getBottomY()] = (BlockState) delegate.getBlock(properties, x, y, z, biomeProvider); + } + return new VerticalBlockSample(height.getBottomY(), array); + } + + @Override + public void getDebugHudText(List text, NoiseConfig noiseConfig, BlockPos pos) { + + } + + public ConfigPack getPack() { + return pack; + } + + public void setPack(ConfigPack pack) { + this.pack = pack; + this.delegate = pack.getGeneratorProvider().newInstance(pack); + biomeSource.setPack(pack); + + logger.debug("Loading world with config pack {}", pack.getID()); + } + + @Override + public void carve(ChunkRegion chunkRegion, long seed, NoiseConfig noiseConfig, BiomeAccess world, StructureAccessor structureAccessor, + Chunk chunk, Carver carverStep) { + // no op + } + + @Override + public ChunkGenerator getHandle() { + return delegate; + } + + public RegistryEntry getSettings() { + return settings; + } + + @Override + public TerraBiomeSource getBiomeSource() { + return biomeSource; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/TerraBiomeSource.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/TerraBiomeSource.java new file mode 100644 index 000000000..b43b38ce8 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/TerraBiomeSource.java @@ -0,0 +1,86 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.generation; + +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.world.biome.generation.BiomeProvider; +import com.dfsek.terra.forge.data.Codecs; +import com.dfsek.terra.forge.util.ProtoPlatformBiome; + +import com.dfsek.terra.forge.util.SeedHack; + +import com.mojang.serialization.Codec; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryEntry; +import net.minecraft.world.biome.source.BiomeSource; +import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.stream.StreamSupport; + + +public class TerraBiomeSource extends BiomeSource { + + private static final Logger LOGGER = LoggerFactory.getLogger(TerraBiomeSource.class); + private final Registry biomeRegistry; + private ConfigPack pack; + + public TerraBiomeSource(Registry biomes, ConfigPack pack) { + super(StreamSupport + .stream(pack.getBiomeProvider() + .getBiomes() + .spliterator(), false) + .map(b -> biomes.getOrCreateEntry(((ProtoPlatformBiome) b.getPlatformBiome()).getDelegate()))); + this.biomeRegistry = biomes; + this.pack = pack; + + LOGGER.debug("Biomes: " + getBiomes()); + } + + @Override + protected Codec getCodec() { + return Codecs.TERRA_BIOME_SOURCE; + } + + @Override + public RegistryEntry getBiome(int biomeX, int biomeY, int biomeZ, MultiNoiseSampler noiseSampler) { + return biomeRegistry + .entryOf(((ProtoPlatformBiome) pack + .getBiomeProvider() + .getBiome(biomeX << 2, biomeY << 2, biomeZ << 2, SeedHack.getSeed(noiseSampler)) + .getPlatformBiome()).getDelegate() + ); + } + + public BiomeProvider getProvider() { + return pack.getBiomeProvider(); + } + + public Registry getBiomeRegistry() { + return biomeRegistry; + } + + public ConfigPack getPack() { + return pack; + } + + public void setPack(ConfigPack pack) { + this.pack = pack; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/FabricItemHandle.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/FabricItemHandle.java new file mode 100644 index 000000000..cc7b0d1a6 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/FabricItemHandle.java @@ -0,0 +1,58 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.handle; + +import com.dfsek.terra.forge.ForgeEntryPoint; + +import com.mojang.brigadier.StringReader; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.command.CommandRegistryAccess; +import net.minecraft.command.argument.ItemStackArgumentType; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +import java.util.Set; +import java.util.stream.Collectors; + +import com.dfsek.terra.api.handle.ItemHandle; +import com.dfsek.terra.api.inventory.Item; +import com.dfsek.terra.api.inventory.item.Enchantment; + + +public class FabricItemHandle implements ItemHandle { + + @Override + public Item createItem(String data) { + try { + return (Item) new ItemStackArgumentType(new CommandRegistryAccess( + ForgeEntryPoint.getPlatform().getServer().getRegistryManager())).parse(new StringReader(data)).getItem(); + } catch(CommandSyntaxException e) { + throw new IllegalArgumentException("Invalid item data \"" + data + "\"", e); + } + } + + @Override + public Enchantment getEnchantment(String id) { + return (Enchantment) (Registry.ENCHANTMENT.get(Identifier.tryParse(id))); + } + + @Override + public Set getEnchantments() { + return Registry.ENCHANTMENT.stream().map(enchantment -> (Enchantment) enchantment).collect(Collectors.toSet()); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/FabricWorldHandle.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/FabricWorldHandle.java new file mode 100644 index 000000000..dd47858b8 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/FabricWorldHandle.java @@ -0,0 +1,59 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.handle; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.block.Blocks; +import net.minecraft.command.argument.BlockArgumentParser; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; +import net.minecraftforge.registries.ForgeRegistries; +import org.jetbrains.annotations.NotNull; + +import com.dfsek.terra.api.block.state.BlockState; +import com.dfsek.terra.api.entity.EntityType; +import com.dfsek.terra.api.handle.WorldHandle; + + +public class FabricWorldHandle implements WorldHandle { + + private static final BlockState AIR = (BlockState) Blocks.AIR.getDefaultState(); + + @Override + public @NotNull BlockState createBlockState(@NotNull String data) { + try { + net.minecraft.block.BlockState state = BlockArgumentParser.block(Registry.BLOCK, data, true).blockState(); + if(state == null) throw new IllegalArgumentException("Invalid data: " + data); + return (BlockState) state; + } catch(CommandSyntaxException e) { + throw new IllegalArgumentException(e); + } + } + + @Override + public @NotNull BlockState air() { + return AIR; + } + + @Override + public @NotNull EntityType getEntity(@NotNull String id) { + Identifier identifier = Identifier.tryParse(id); + if(identifier == null) identifier = Identifier.tryParse(id); + return (EntityType) ForgeRegistries.ENTITIES.getHolder(identifier).orElseThrow().value(); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/ChunkRegionAccessor.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/ChunkRegionAccessor.java new file mode 100644 index 000000000..58624dfe9 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/ChunkRegionAccessor.java @@ -0,0 +1,15 @@ +package com.dfsek.terra.forge.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/forge/src/main/java/com/dfsek/terra/forge/mixin/access/MobSpawnerLogicAccessor.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/MobSpawnerLogicAccessor.java new file mode 100644 index 000000000..20a900005 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/MobSpawnerLogicAccessor.java @@ -0,0 +1,30 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.access; + +import net.minecraft.world.MobSpawnerEntry; +import net.minecraft.world.MobSpawnerLogic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + + +@Mixin(MobSpawnerLogic.class) +public interface MobSpawnerLogicAccessor { + @Accessor("spawnEntry") + MobSpawnerEntry getSpawnEntry(); +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/StateAccessor.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/StateAccessor.java new file mode 100644 index 000000000..947118da9 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/StateAccessor.java @@ -0,0 +1,35 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.access; + +import net.minecraft.state.State; +import net.minecraft.state.property.Property; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; +import java.util.function.Function; + + +@Mixin(State.class) +public interface StateAccessor { + @Accessor("PROPERTY_MAP_PRINTER") + static Function, Comparable>, String> getPropertyMapPrinter() { + throw new UnsupportedOperationException(); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/StructureAccessorAccessor.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/StructureAccessorAccessor.java new file mode 100644 index 000000000..12ca75c9d --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/StructureAccessorAccessor.java @@ -0,0 +1,30 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.access; + +import net.minecraft.world.WorldAccess; +import net.minecraft.world.gen.StructureAccessor; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + + +@Mixin(StructureAccessor.class) +public interface StructureAccessorAccessor { + @Accessor + WorldAccess getWorld(); +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java new file mode 100644 index 000000000..53b2ac21d --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java @@ -0,0 +1,27 @@ +package com.dfsek.terra.forge.mixin.fix; + +import com.dfsek.terra.forge.ForgeEntryPoint; + +import net.minecraft.entity.passive.BeeEntity.MoveToFlowerGoal; +import net.minecraft.entity.passive.BeeEntity.MoveToHiveGoal; +import net.minecraft.util.math.random.CheckedRandom; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + + +/** + * Bees spawning uses world.random without synchronization. This causes issues when spawning bees during world generation. + */ +@Mixin({ + MoveToHiveGoal.class, + MoveToFlowerGoal.class +}) +public class BeeMoveGoalsUnsynchronizedRandomAccessFix { + @Redirect(method = "", at = @At(value = "FIELD", target = "Lnet/minecraft/world/World;random:Lnet/minecraft/util/math/random/Random;")) + public Random redirectRandomAccess(World instance) { + return new CheckedRandom(ForgeEntryPoint.getPlatform().getServer().getTicks()); // replace with new random seeded by tick time. + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/NetherFossilOptimization.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/NetherFossilOptimization.java new file mode 100644 index 000000000..c8def7e88 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/NetherFossilOptimization.java @@ -0,0 +1,29 @@ +package com.dfsek.terra.forge.mixin.fix; + +import com.dfsek.terra.forge.generation.FabricChunkGeneratorWrapper; + +import net.minecraft.world.gen.structure.NetherFossilStructure; +import net.minecraft.world.gen.structure.Structure.Context; +import net.minecraft.world.gen.structure.Structure.StructurePosition; +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; + +import java.util.Optional; + + +/** + * Disable fossil generation in Terra worlds, as they are very expensive due to consistently triggering cache misses. + * + * Currently, on Fabric, Terra cannot be specified as a Nether generator. TODO: logic to turn fossils back on if chunk generator is in nether. + */ +@Mixin(NetherFossilStructure.class) +public class NetherFossilOptimization { + @Inject(method = "getStructurePosition", at = @At("HEAD"), cancellable = true) + public void injectFossilPositions(Context context, CallbackInfoReturnable> cir) { + if(context.chunkGenerator() instanceof FabricChunkGeneratorWrapper) { + cir.setReturnValue(Optional.empty()); + } + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java new file mode 100644 index 000000000..19639e48a --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java @@ -0,0 +1,32 @@ +package com.dfsek.terra.forge.mixin.implementations.compat; + +import com.dfsek.terra.forge.mixin_ifaces.FloraFeatureHolder; + +import net.minecraft.world.biome.GenerationSettings; +import net.minecraft.world.gen.feature.ConfiguredFeature; +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.CallbackInfoReturnable; + +import java.util.List; + + +@Mixin(GenerationSettings.class) +@Implements(@Interface(iface = FloraFeatureHolder.class, prefix = "terra$")) +public class GenerationSettingsFloraFeaturesMixin { + private List> flora; + + public void terra$setFloraFeatures(List> features) { + this.flora = features; + } + + @Inject(method = "getFlowerFeatures", cancellable = true, at = @At("HEAD")) + public void inject(CallbackInfoReturnable>> cir) { + if(flora != null) { + cir.setReturnValue(flora); + } + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/BiomeMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/BiomeMixin.java new file mode 100644 index 000000000..3bf07cffc --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/BiomeMixin.java @@ -0,0 +1,31 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra; + +import net.minecraft.world.biome.Biome; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; + +import com.dfsek.terra.api.world.biome.PlatformBiome; + + +@Mixin(Biome.class) +@Implements(@Interface(iface = PlatformBiome.class, prefix = "terra$")) +public abstract class BiomeMixin { +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/HandleImplementationMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/HandleImplementationMixin.java new file mode 100644 index 000000000..936af09b3 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/HandleImplementationMixin.java @@ -0,0 +1,61 @@ +package com.dfsek.terra.forge.mixin.implementations.terra; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.LockableContainerBlockEntity; +import net.minecraft.block.entity.LootableContainerBlockEntity; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.world.ChunkRegion; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.chunk.ProtoChunk; +import net.minecraft.world.chunk.WorldChunk; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Intrinsic; +import org.spongepowered.asm.mixin.Mixin; + +import com.dfsek.terra.api.Handle; + + +/** + * A ton of Minecraft classes must implement Handle identically, we can just take care of it here + */ +@Mixin({ + ServerWorld.class, + ChunkRegion.class, + + Block.class, + BlockState.class, + + BlockEntity.class, + LootableContainerBlockEntity.class, + LockableContainerBlockEntity.class, + + ProtoChunk.class, + WorldChunk.class, + + Entity.class, + EntityType.class, + + ServerCommandSource.class, + + Item.class, + ItemStack.class, + Enchantment.class, + + Biome.class +}) +@Implements(@Interface(iface = Handle.class, prefix = "terra$")) +public class HandleImplementationMixin { + @Intrinsic + public Object terra$getHandle() { + return this; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/BlockMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/BlockMixin.java new file mode 100644 index 000000000..8df67e40a --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/BlockMixin.java @@ -0,0 +1,44 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.block; + +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; + +import com.dfsek.terra.api.block.BlockType; + + +@Mixin(Block.class) +@Implements(@Interface(iface = BlockType.class, prefix = "terra$")) +public abstract class BlockMixin { + public com.dfsek.terra.api.block.state.BlockState terra$getDefaultState() { + return (com.dfsek.terra.api.block.state.BlockState) ((Block) (Object) this).getDefaultState(); + } + + public boolean terra$isSolid() { + return ((Block) (Object) this).getDefaultState().isOpaque(); + } + + @SuppressWarnings("ConstantConditions") + public boolean terra$isWater() { + return ((Object) this) == Blocks.WATER; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/BlockEntityMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/BlockEntityMixin.java new file mode 100644 index 000000000..272c18812 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/BlockEntityMixin.java @@ -0,0 +1,54 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.block.entity; + +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; + +import com.dfsek.terra.api.block.entity.BlockEntity; +import com.dfsek.terra.api.block.state.BlockState; + + +@Mixin(net.minecraft.block.entity.BlockEntity.class) +@Implements(@Interface(iface = BlockEntity.class, prefix = "terra$")) +public abstract class BlockEntityMixin { + public boolean terra$update(boolean applyPhysics) { + if(((net.minecraft.block.entity.BlockEntity) (Object) this).hasWorld()) //noinspection ConstantConditions + ((net.minecraft.block.entity.BlockEntity) (Object) this).getWorld().getChunk( + ((net.minecraft.block.entity.BlockEntity) (Object) this).getPos()).setBlockEntity( + (net.minecraft.block.entity.BlockEntity) (Object) this); + return true; + } + + public int terra$getX() { + return ((net.minecraft.block.entity.BlockEntity) (Object) this).getPos().getX(); + } + + public int terra$getY() { + return ((net.minecraft.block.entity.BlockEntity) (Object) this).getPos().getY(); + } + + public int terra$getZ() { + return ((net.minecraft.block.entity.BlockEntity) (Object) this).getPos().getZ(); + } + + public BlockState terra$getBlockState() { + return (BlockState) ((net.minecraft.block.entity.BlockEntity) (Object) this).getCachedState(); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java new file mode 100644 index 000000000..123541696 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java @@ -0,0 +1,35 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.block.entity; + +import net.minecraft.block.entity.LootableContainerBlockEntity; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; + +import com.dfsek.terra.api.block.entity.Container; +import com.dfsek.terra.api.inventory.Inventory; + + +@Mixin(LootableContainerBlockEntity.class) +@Implements(@Interface(iface = Container.class, prefix = "terra$")) +public abstract class LootableContainerBlockEntityMixin extends BlockEntityMixin { + public Inventory terra$getInventory() { + return (Inventory) this; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java new file mode 100644 index 000000000..60bafaefb --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java @@ -0,0 +1,131 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.block.entity; + +import com.dfsek.terra.forge.ForgeEntryPoint; +import com.dfsek.terra.forge.mixin.access.MobSpawnerLogicAccessor; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.block.entity.MobSpawnerBlockEntity; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.MobSpawnerLogic; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import com.dfsek.terra.api.block.entity.MobSpawner; +import com.dfsek.terra.api.block.entity.SerialState; +import com.dfsek.terra.api.entity.EntityType; + + +@Mixin(MobSpawnerBlockEntity.class) +@Implements(@Interface(iface = MobSpawner.class, prefix = "terra$")) +public abstract class MobSpawnerBlockEntityMixin extends BlockEntity { + private MobSpawnerBlockEntityMixin(BlockEntityType type, BlockPos pos, BlockState state) { + super(type, pos, state); + } + + @Shadow + public abstract MobSpawnerLogic getLogic(); + + public EntityType terra$getSpawnedType() { + return (EntityType) Registry.ENTITY_TYPE.get( + Identifier.tryParse(((MobSpawnerLogicAccessor) getLogic()).getSpawnEntry().getNbt().getString("id"))); + } + + public void terra$setSpawnedType(@NotNull EntityType creatureType) { + getLogic().setEntityId((net.minecraft.entity.EntityType) creatureType); + } + + public int terra$getDelay() { + return 0; + } + + public void terra$setDelay(int delay) { + + } + + public int terra$getMinSpawnDelay() { + return 0; + } + + public void terra$setMinSpawnDelay(int delay) { + + } + + public int terra$getMaxSpawnDelay() { + return 0; + } + + public void terra$setMaxSpawnDelay(int delay) { + + } + + public int terra$getSpawnCount() { + return 0; + } + + public void terra$setSpawnCount(int spawnCount) { + + } + + public int terra$getMaxNearbyEntities() { + return 0; + } + + public void terra$setMaxNearbyEntities(int maxNearbyEntities) { + + } + + public int terra$getRequiredPlayerRange() { + return 0; + } + + public void terra$setRequiredPlayerRange(int requiredPlayerRange) { + + } + + public int terra$getSpawnRange() { + return 0; + } + + public void terra$setSpawnRange(int spawnRange) { + + } + + public void terra$applyState(String state) { + SerialState.parse(state).forEach((k, v) -> { + switch(k) { + case "type" -> terra$setSpawnedType(ForgeEntryPoint.getPlatform().getWorldHandle().getEntity(v)); + case "delay" -> terra$setDelay(Integer.parseInt(v)); + case "min_delay" -> terra$setMinSpawnDelay(Integer.parseInt(v)); + case "max_delay" -> terra$setMaxSpawnDelay(Integer.parseInt(v)); + case "spawn_count" -> terra$setSpawnCount(Integer.parseInt(v)); + case "spawn_range" -> terra$setSpawnRange(Integer.parseInt(v)); + case "max_nearby" -> terra$setMaxNearbyEntities(Integer.parseInt(v)); + case "required_player_range" -> terra$setRequiredPlayerRange(Integer.parseInt(v)); + default -> throw new IllegalArgumentException("Invalid property: " + k); + } + }); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java new file mode 100644 index 000000000..400a176ca --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java @@ -0,0 +1,65 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.block.entity; + +import net.minecraft.block.entity.SignBlockEntity; +import net.minecraft.text.Text; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import com.dfsek.terra.api.block.entity.SerialState; +import com.dfsek.terra.api.block.entity.Sign; + + +@Mixin(SignBlockEntity.class) +@Implements(@Interface(iface = Sign.class, prefix = "terra$")) +public abstract class SignBlockEntityMixin { + @Shadow + @Final + private Text[] texts; + + @Shadow + public abstract void setTextOnRow(int row, Text text); + + public void terra$setLine(int index, @NotNull String line) throws IndexOutOfBoundsException { + setTextOnRow(index, Text.literal(line)); + } + + public @NotNull String[] terra$getLines() { + String[] lines = new String[texts.length]; + for(int i = 0; i < texts.length; i++) { + lines[i] = texts[i].getString(); + } + return lines; + } + + public @NotNull String terra$getLine(int index) throws IndexOutOfBoundsException { + return texts[index].getString(); + } + + public void terra$applyState(String state) { + SerialState.parse(state).forEach((k, v) -> { + if(!k.startsWith("text")) throw new IllegalArgumentException("Invalid property: " + k); + terra$setLine(Integer.parseInt(k.substring(4)), v); + }); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/state/BlockStateMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/state/BlockStateMixin.java new file mode 100644 index 000000000..c0076820c --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/state/BlockStateMixin.java @@ -0,0 +1,83 @@ +package com.dfsek.terra.forge.mixin.implementations.terra.block.state; + + +import com.dfsek.terra.forge.mixin.access.StateAccessor; +import com.google.common.collect.ImmutableMap; +import com.mojang.serialization.MapCodec; +import net.minecraft.block.AbstractBlock.AbstractBlockState; +import net.minecraft.block.Block; +import net.minecraft.state.State; +import net.minecraft.util.registry.Registry; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Intrinsic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.stream.Collectors; + +import com.dfsek.terra.api.block.BlockType; +import com.dfsek.terra.api.block.state.BlockState; +import com.dfsek.terra.api.block.state.properties.Property; + + +@Mixin(AbstractBlockState.class) +@Implements(@Interface(iface = BlockState.class, prefix = "terra$")) +public abstract class BlockStateMixin extends State { + private BlockStateMixin(Block owner, ImmutableMap, Comparable> entries, + MapCodec codec) { + super(owner, entries, codec); + } + + @Shadow + public abstract Block getBlock(); + + @Shadow + public abstract boolean isAir(); + + public boolean terra$matches(BlockState other) { + return getBlock() == ((net.minecraft.block.BlockState) other).getBlock(); + } + + @Intrinsic + public > boolean terra$has(Property property) { + if(property instanceof net.minecraft.state.property.Property minecraftProperty) { + return contains(minecraftProperty); + } + return false; + } + + @SuppressWarnings("unchecked") + @Intrinsic + public > T terra$get(Property property) { + return get((net.minecraft.state.property.Property) property); + } + + @SuppressWarnings("unchecked") + @Intrinsic + public > BlockState terra$set(Property property, T value) { + return (BlockState) with((net.minecraft.state.property.Property) property, value); + } + + @Intrinsic + public BlockType terra$getBlockType() { + return (BlockType) getBlock(); + } + + @Intrinsic + public String terra$getAsString(boolean properties) { + StringBuilder data = new StringBuilder(Registry.BLOCK.getId(getBlock()).toString()); + if(properties && !getEntries().isEmpty()) { + data.append('['); + data.append( + getEntries().entrySet().stream().map(StateAccessor.getPropertyMapPrinter()).collect(Collectors.joining(","))); + data.append(']'); + } + return data.toString(); + } + + @Intrinsic + public boolean terra$isAir() { + return isAir(); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/state/PropertyMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/state/PropertyMixin.java new file mode 100644 index 000000000..ce7d41e20 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/state/PropertyMixin.java @@ -0,0 +1,43 @@ +package com.dfsek.terra.forge.mixin.implementations.terra.block.state; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Interface.Remap; +import org.spongepowered.asm.mixin.Intrinsic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Collection; + +import com.dfsek.terra.api.block.state.properties.Property; + + +@Mixin(net.minecraft.state.property.Property.class) +@Implements(@Interface(iface = Property.class, prefix = "terra$", remap = Remap.NONE)) +public abstract class PropertyMixin { + @Shadow + @Final + private Class type; + @Shadow + @Final + private String name; + + @Shadow + public abstract Collection getValues(); + + @Intrinsic + public Collection terra$values() { + return getValues(); + } + + @Intrinsic + public Class terra$getType() { + return type; + } + + @Intrinsic + public String terra$getID() { + return name; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/ChunkRegionMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/ChunkRegionMixin.java new file mode 100644 index 000000000..96bbe0715 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/ChunkRegionMixin.java @@ -0,0 +1,58 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.chunk; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.ChunkRegion; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import com.dfsek.terra.api.block.state.BlockState; +import com.dfsek.terra.api.world.chunk.Chunk; + + +@Mixin(ChunkRegion.class) +@Implements(@Interface(iface = Chunk.class, prefix = "terraChunk$")) +public abstract class ChunkRegionMixin { + + @Shadow + @Final + private net.minecraft.world.chunk.Chunk centerPos; + + public void terraChunk$setBlock(int x, int y, int z, @NotNull BlockState blockState, boolean physics) { + ((ChunkRegion) (Object) this).setBlockState(new BlockPos(x + (centerPos.getPos().x << 4), y, z + (centerPos.getPos().z << 4)), + (net.minecraft.block.BlockState) blockState, 0); + } + + public @NotNull BlockState terraChunk$getBlock(int x, int y, int z) { + return (BlockState) ((ChunkRegion) (Object) this).getBlockState( + new BlockPos(x + (centerPos.getPos().x << 4), y, z + (centerPos.getPos().z << 4))); + } + + public int terraChunk$getX() { + return centerPos.getPos().x; + } + + public int terraChunk$getZ() { + return centerPos.getPos().z; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/WorldChunkMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/WorldChunkMixin.java new file mode 100644 index 000000000..b6aecff61 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/WorldChunkMixin.java @@ -0,0 +1,75 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.chunk; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.chunk.WorldChunk; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Intrinsic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import com.dfsek.terra.api.block.state.BlockState; +import com.dfsek.terra.api.world.ServerWorld; +import com.dfsek.terra.api.world.chunk.Chunk; + + +@Mixin(WorldChunk.class) +@Implements(@Interface(iface = Chunk.class, prefix = "terra$")) +public abstract class WorldChunkMixin { + @Final + @Shadow + net.minecraft.world.World world; + + @Shadow + public abstract net.minecraft.block.BlockState getBlockState(BlockPos pos); + + @Shadow + @Nullable + public abstract net.minecraft.block.BlockState setBlockState(BlockPos pos, net.minecraft.block.BlockState state, boolean moved); + + public void terra$setBlock(int x, int y, int z, BlockState data, boolean physics) { + setBlockState(new BlockPos(x, y, z), (net.minecraft.block.BlockState) data, false); + } + + public void terra$setBlock(int x, int y, int z, @NotNull BlockState blockState) { + ((net.minecraft.world.chunk.Chunk) (Object) this).setBlockState(new BlockPos(x, y, z), (net.minecraft.block.BlockState) blockState, + false); + } + + @Intrinsic + public @NotNull BlockState terra$getBlock(int x, int y, int z) { + return (BlockState) getBlockState(new BlockPos(x, y, z)); + } + + public int terra$getX() { + return ((net.minecraft.world.chunk.Chunk) (Object) this).getPos().x; + } + + public int terra$getZ() { + return ((net.minecraft.world.chunk.Chunk) (Object) this).getPos().z; + } + + public ServerWorld terra$getWorld() { + return (ServerWorld) world; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java new file mode 100644 index 000000000..918df4f42 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java @@ -0,0 +1,53 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.chunk.data; + +import com.dfsek.terra.api.block.state.BlockState; +import com.dfsek.terra.api.world.chunk.generation.ProtoChunk; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.HeightLimitView; +import org.jetbrains.annotations.NotNull; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + + +@Mixin(net.minecraft.world.chunk.ProtoChunk.class) +@Implements(@Interface(iface = ProtoChunk.class, prefix = "terra$")) +public abstract class ProtoChunkMixin { + @Shadow + public abstract net.minecraft.block.BlockState getBlockState(BlockPos pos); + + @Shadow + public abstract HeightLimitView getHeightLimitView(); + + public void terra$setBlock(int x, int y, int z, @NotNull BlockState blockState) { + ((net.minecraft.world.chunk.Chunk) (Object) this).setBlockState(new BlockPos(x, y, z), (net.minecraft.block.BlockState) blockState, + false); + } + + public @NotNull BlockState terra$getBlock(int x, int y, int z) { + return (BlockState) getBlockState(new BlockPos(x, y, z)); + } + + public int terra$getMaxHeight() { + return getHeightLimitView().getTopY(); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityMixin.java new file mode 100644 index 000000000..96e7be2d5 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityMixin.java @@ -0,0 +1,55 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.entity; + +import com.dfsek.terra.forge.util.FabricAdapter; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.BlockPos; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import com.dfsek.terra.api.util.vector.Vector3; +import com.dfsek.terra.api.world.ServerWorld; + + +@Mixin(Entity.class) +@Implements(@Interface(iface = com.dfsek.terra.api.entity.Entity.class, prefix = "terra$")) +public abstract class EntityMixin { + @Shadow + public net.minecraft.world.World world; + + @Shadow + private BlockPos blockPos; + + @Shadow + public abstract void teleport(double destX, double destY, double destZ); + + public Vector3 terra$position() { + return FabricAdapter.adapt(blockPos); + } + + public void terra$position(Vector3 location) { + teleport(location.getX(), location.getY(), location.getZ()); + } + + public ServerWorld terra$world() { + return (ServerWorld) world; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityTypeMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityTypeMixin.java new file mode 100644 index 000000000..1c73c1efb --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityTypeMixin.java @@ -0,0 +1,29 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.entity; + +import net.minecraft.entity.EntityType; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; + + +@Mixin(EntityType.class) +@Implements(@Interface(iface = com.dfsek.terra.api.entity.EntityType.class, prefix = "terra$")) +public abstract class EntityTypeMixin { +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/PlayerEntityMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/PlayerEntityMixin.java new file mode 100644 index 000000000..f08df6293 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/PlayerEntityMixin.java @@ -0,0 +1,31 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.entity; + +import net.minecraft.entity.player.PlayerEntity; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; + +import com.dfsek.terra.api.entity.Player; + + +@Mixin(PlayerEntity.class) +@Implements(@Interface(iface = Player.class, prefix = "terra$")) +public abstract class PlayerEntityMixin extends EntityMixin { +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/ServerCommandSourceMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/ServerCommandSourceMixin.java new file mode 100644 index 000000000..ce91be261 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/ServerCommandSourceMixin.java @@ -0,0 +1,66 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.entity; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Optional; + +import com.dfsek.terra.api.command.CommandSender; +import com.dfsek.terra.api.entity.Entity; +import com.dfsek.terra.api.entity.Player; + + +@Mixin(ServerCommandSource.class) +@Implements(@Interface(iface = CommandSender.class, prefix = "terra$")) +public abstract class ServerCommandSourceMixin { + @Shadow + public abstract void sendFeedback(Text message, boolean broadcastToOps); + + @Shadow + public abstract ServerPlayerEntity getPlayer() throws CommandSyntaxException; + + @Shadow + @Nullable + public abstract net.minecraft.entity.@Nullable Entity getEntity(); + + public void terra$sendMessage(String message) { + sendFeedback(Text.literal(message), true); + } + + @Nullable + public Optional terra$getEntity() { + return Optional.ofNullable((Entity) getEntity()); + } + + public Optional terra$getPlayer() { + try { + return Optional.ofNullable((Player) getPlayer()); + } catch(CommandSyntaxException e) { + return Optional.empty(); + } + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java new file mode 100644 index 000000000..40f6111db --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java @@ -0,0 +1,47 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.inventory; + +import net.minecraft.block.entity.LockableContainerBlockEntity; +import net.minecraft.item.Items; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; + +import com.dfsek.terra.api.inventory.Inventory; +import com.dfsek.terra.api.inventory.ItemStack; + + +@Mixin(LockableContainerBlockEntity.class) +@Implements(@Interface(iface = Inventory.class, prefix = "terra$")) +public class LockableContainerBlockEntityMixin { + @SuppressWarnings("ConstantConditions") + public void terra$setItem(int slot, ItemStack newStack) { + ((LockableContainerBlockEntity) (Object) this).setStack(slot, (net.minecraft.item.ItemStack) (Object) newStack); + } + + public int terra$getSize() { + return ((LockableContainerBlockEntity) (Object) this).size(); + } + + @SuppressWarnings("ConstantConditions") + public ItemStack terra$getItem(int slot) { + net.minecraft.item.ItemStack itemStack = ((LockableContainerBlockEntity) (Object) this).getStack(slot); + return itemStack.getItem() == Items.AIR ? null : (ItemStack) (Object) itemStack; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/item/ItemMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/item/ItemMixin.java new file mode 100644 index 000000000..e48b5341c --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/item/ItemMixin.java @@ -0,0 +1,43 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.inventory.item; + +import net.minecraft.item.Item; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import com.dfsek.terra.api.inventory.ItemStack; + + +@Mixin(Item.class) +@Implements(@Interface(iface = com.dfsek.terra.api.inventory.Item.class, prefix = "terra$")) +public abstract class ItemMixin { + @Shadow + public abstract int getMaxDamage(); + + @SuppressWarnings("ConstantConditions") + public ItemStack terra$newItemStack(int amount) { + return (ItemStack) (Object) new net.minecraft.item.ItemStack((Item) (Object) this, amount); + } + + public double terra$getMaxDurability() { + return getMaxDamage(); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/item/ItemStackMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/item/ItemStackMixin.java new file mode 100644 index 000000000..7bb42595a --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/item/ItemStackMixin.java @@ -0,0 +1,76 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.inventory.item; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Intrinsic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import com.dfsek.terra.api.inventory.Item; +import com.dfsek.terra.api.inventory.item.ItemMeta; + + +@Mixin(ItemStack.class) +@Implements(@Interface(iface = com.dfsek.terra.api.inventory.ItemStack.class, prefix = "terra$")) +public abstract class ItemStackMixin { + @Shadow + public abstract int getCount(); + + @Shadow + public abstract void setCount(int count); + + @Shadow + public abstract net.minecraft.item.Item getItem(); + + @Shadow + public abstract boolean isDamageable(); + + @Shadow + public abstract void setNbt(@Nullable NbtCompound tag); + + public int terra$getAmount() { + return getCount(); + } + + public void terra$setAmount(int i) { + setCount(i); + } + + public Item terra$getType() { + return (Item) getItem(); + } + + public ItemMeta terra$getItemMeta() { + return (ItemMeta) this; + } + + @SuppressWarnings("ConstantConditions") + public void terra$setItemMeta(ItemMeta meta) { + setNbt(((ItemStack) (Object) meta).getNbt()); + } + + @Intrinsic + public boolean terra$isDamageable() { + return isDamageable(); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java new file mode 100644 index 000000000..358cd7a95 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java @@ -0,0 +1,53 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.inventory.meta; + +import net.minecraft.enchantment.Enchantment; +import net.minecraft.util.registry.Registry; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Objects; + +import com.dfsek.terra.api.inventory.ItemStack; + + +@Mixin(Enchantment.class) +@Implements(@Interface(iface = com.dfsek.terra.api.inventory.item.Enchantment.class, prefix = "terra$")) +public abstract class EnchantmentMixin { + @Shadow + public abstract boolean isAcceptableItem(net.minecraft.item.ItemStack stack); + + @Shadow + public abstract boolean canCombine(Enchantment other); + + @SuppressWarnings("ConstantConditions") + public boolean terra$canEnchantItem(ItemStack itemStack) { + return isAcceptableItem((net.minecraft.item.ItemStack) (Object) itemStack); + } + + public boolean terra$conflictsWith(com.dfsek.terra.api.inventory.item.Enchantment other) { + return !canCombine((Enchantment) other); + } + + public String terra$getID() { + return Objects.requireNonNull(Registry.ENCHANTMENT.getId((Enchantment) (Object) this)).toString(); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java new file mode 100644 index 000000000..d70b1732d --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java @@ -0,0 +1,55 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.inventory.meta; + +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Intrinsic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import com.dfsek.terra.api.inventory.item.Damageable; + + +@Mixin(ItemStack.class) +@Implements(@Interface(iface = Damageable.class, prefix = "terra$")) +public abstract class ItemStackDamageableMixin { + @Shadow + public abstract boolean isDamaged(); + + @Shadow + public abstract int getDamage(); + + @Shadow + public abstract void setDamage(int damage); + + @Intrinsic + public int terra$getDamage() { + return getDamage(); + } + + @Intrinsic + public void terra$setDamage(int damage) { + setDamage(damage); + } + + public boolean terra$hasDamage() { + return isDamaged(); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java new file mode 100644 index 000000000..17bf068a1 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java @@ -0,0 +1,65 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.inventory.meta; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtList; +import net.minecraft.util.registry.Registry; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Intrinsic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import com.dfsek.terra.api.inventory.item.Enchantment; +import com.dfsek.terra.api.inventory.item.ItemMeta; + + +@Mixin(ItemStack.class) +@Implements(@Interface(iface = ItemMeta.class, prefix = "terra$")) +public abstract class ItemStackMetaMixin { + @Shadow + public abstract boolean hasEnchantments(); + + @Shadow + public abstract NbtList getEnchantments(); + + @Shadow + public abstract void addEnchantment(net.minecraft.enchantment.Enchantment enchantment, int level); + + public void terra$addEnchantment(Enchantment enchantment, int level) { + addEnchantment((net.minecraft.enchantment.Enchantment) enchantment, level); + } + + @Intrinsic(displace = true) + public Map terra$getEnchantments() { + if(!hasEnchantments()) return Collections.emptyMap(); + Map map = new HashMap<>(); + + getEnchantments().forEach(enchantment -> { + NbtCompound eTag = (NbtCompound) enchantment; + map.put((Enchantment) Registry.ENCHANTMENT.get(eTag.getInt("id")), eTag.getInt("lvl")); + }); + return map; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/package-info.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/package-info.java new file mode 100644 index 000000000..0899793d3 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/package-info.java @@ -0,0 +1,23 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +/** + * Mixins in this package implement Terra + * interfaces in Minecraft classes. + */ + +package com.dfsek.terra.forge.mixin.implementations.terra; \ No newline at end of file diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ChunkRegionMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ChunkRegionMixin.java new file mode 100644 index 000000000..6ba8768ab --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ChunkRegionMixin.java @@ -0,0 +1,149 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.world; + +import com.dfsek.terra.forge.generation.FabricChunkGeneratorWrapper; +import net.minecraft.block.FluidBlock; +import net.minecraft.fluid.Fluid; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.ChunkRegion; +import net.minecraft.world.WorldAccess; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.tick.MultiTickScheduler; +import net.minecraft.world.tick.OrderedTick; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Intrinsic; +import org.spongepowered.asm.mixin.Mixin; +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 java.util.List; + +import com.dfsek.terra.api.block.entity.BlockEntity; +import com.dfsek.terra.api.block.state.BlockState; +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.entity.Entity; +import com.dfsek.terra.api.entity.EntityType; +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.forge.util.FabricUtil; + + +@Mixin(ChunkRegion.class) +@Implements(@Interface(iface = ProtoWorld.class, prefix = "terraWorld$")) +public abstract class ChunkRegionMixin { + private ConfigPack terra$config; + + + @Shadow + @Final + private net.minecraft.server.world.ServerWorld world; + + @Shadow + @Final + private long seed; + @Shadow + @Final + private Chunk centerPos; + + @Shadow + @Final + private MultiTickScheduler fluidTickScheduler; + + + @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.terra$config = ((ServerWorld) world).getPack(); + } + + + @Intrinsic(displace = true) + public void terraWorld$setBlockState(int x, int y, int z, BlockState data, boolean physics) { + BlockPos pos = new BlockPos(x, y, z); + ((ChunkRegion) (Object) this).setBlockState(pos, (net.minecraft.block.BlockState) data, physics ? 3 : 1042); + if(physics && ((net.minecraft.block.BlockState) data).getBlock() instanceof FluidBlock) { + fluidTickScheduler.scheduleTick( + OrderedTick.create(((FluidBlock) ((net.minecraft.block.BlockState) data).getBlock()).getFluidState( + (net.minecraft.block.BlockState) data).getFluid(), pos)); + } + } + + @Intrinsic + public long terraWorld$getSeed() { + return seed; + } + + public int terraWorld$getMaxHeight() { + return world.getTopY(); + } + + @Intrinsic(displace = true) + public BlockState terraWorld$getBlockState(int x, int y, int z) { + BlockPos pos = new BlockPos(x, y, z); + return (BlockState) ((ChunkRegion) (Object) this).getBlockState(pos); + } + + public BlockEntity terraWorld$getBlockEntity(int x, int y, int z) { + return FabricUtil.createState((WorldAccess) this, new BlockPos(x, y, z)); + } + + public int terraWorld$getMinHeight() { + return world.getBottomY(); + } + + public ChunkGenerator terraWorld$getGenerator() { + return ((FabricChunkGeneratorWrapper) world.getChunkManager().getChunkGenerator()).getHandle(); + } + + public BiomeProvider terraWorld$getBiomeProvider() { + return terra$config.getBiomeProvider(); + } + + public Entity terraWorld$spawnEntity(double x, double y, double z, EntityType entityType) { + net.minecraft.entity.Entity entity = ((net.minecraft.entity.EntityType) entityType).create(world); + entity.setPos(x, y, z); + ((ChunkRegion) (Object) this).spawnEntity(entity); + return (Entity) entity; + } + + public int terraWorld$centerChunkX() { + return centerPos.getPos().x; + } + + public int terraWorld$centerChunkZ() { + return centerPos.getPos().z; + } + + public ServerWorld terraWorld$getWorld() { + return (ServerWorld) world; + } + + public ConfigPack terraWorld$getPack() { + return terra$config; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ServerWorldMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ServerWorldMixin.java new file mode 100644 index 000000000..fc9158d4c --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ServerWorldMixin.java @@ -0,0 +1,102 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.implementations.terra.world; + +import com.dfsek.terra.forge.generation.FabricChunkGeneratorWrapper; +import com.dfsek.terra.forge.generation.TerraBiomeSource; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.WorldAccess; +import org.spongepowered.asm.mixin.Implements; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Intrinsic; +import org.spongepowered.asm.mixin.Mixin; + +import com.dfsek.terra.api.block.entity.BlockEntity; +import com.dfsek.terra.api.block.state.BlockState; +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.entity.Entity; +import com.dfsek.terra.api.entity.EntityType; +import com.dfsek.terra.api.world.ServerWorld; +import com.dfsek.terra.api.world.biome.generation.BiomeProvider; +import com.dfsek.terra.api.world.chunk.Chunk; +import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator; +import com.dfsek.terra.forge.util.FabricUtil; + + +@Mixin(net.minecraft.server.world.ServerWorld.class) +@Implements(@Interface(iface = ServerWorld.class, prefix = "terra$")) +public abstract class ServerWorldMixin { + public Entity terra$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); + ((net.minecraft.server.world.ServerWorld) (Object) this).spawnEntity(entity); + return (Entity) entity; + } + + public void terra$setBlockState(int x, int y, int z, BlockState data, boolean physics) { + BlockPos pos = new BlockPos(x, y, z); + ((net.minecraft.server.world.ServerWorld) (Object) this).setBlockState(pos, (net.minecraft.block.BlockState) data, + physics ? 3 : 1042); + } + + @Intrinsic + public long terra$getSeed() { + return ((net.minecraft.server.world.ServerWorld) (Object) this).getSeed(); + } + + public int terra$getMaxHeight() { + return (((net.minecraft.server.world.ServerWorld) (Object) this).getBottomY()) + + ((net.minecraft.server.world.ServerWorld) (Object) this).getHeight(); + } + + public Chunk terra$getChunkAt(int x, int z) { + return (Chunk) ((net.minecraft.server.world.ServerWorld) (Object) this).getChunk(x, z); + } + + public BlockState terra$getBlockState(int x, int y, int z) { + return (BlockState) ((net.minecraft.server.world.ServerWorld) (Object) this).getBlockState(new BlockPos(x, y, z)); + } + + public BlockEntity terra$getBlockEntity(int x, int y, int z) { + return FabricUtil.createState((WorldAccess) this, new BlockPos(x, y, z)); + } + + public int terra$getMinHeight() { + return ((net.minecraft.server.world.ServerWorld) (Object) this).getBottomY(); + } + + public ChunkGenerator terra$getGenerator() { + return ((FabricChunkGeneratorWrapper) ((net.minecraft.server.world.ServerWorld) (Object) this).getChunkManager() + .getChunkGenerator()).getHandle(); + } + + public BiomeProvider terra$getBiomeProvider() { + return ((TerraBiomeSource) ((net.minecraft.server.world.ServerWorld) (Object) this).getChunkManager() + .getChunkGenerator() + .getBiomeSource()).getProvider(); + } + + public ConfigPack terra$getPack() { + net.minecraft.world.gen.chunk.ChunkGenerator generator = + (((net.minecraft.server.world.ServerWorld) (Object) this).getChunkManager()).getChunkGenerator(); + if(generator instanceof FabricChunkGeneratorWrapper fabricChunkGeneratorWrapper) { + return fabricChunkGeneratorWrapper.getPack(); + } + return null; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/DataPackContentsMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/DataPackContentsMixin.java new file mode 100644 index 000000000..fefb67df4 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/DataPackContentsMixin.java @@ -0,0 +1,28 @@ +package com.dfsek.terra.forge.mixin.lifecycle; + +import com.dfsek.terra.forge.util.BiomeUtil; +import com.dfsek.terra.forge.util.TagUtil; +import net.minecraft.server.DataPackContents; +import net.minecraft.util.registry.DynamicRegistryManager; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.biome.Biome; +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; + + +@Mixin(DataPackContents.class) +public class DataPackContentsMixin { + /* + * #refresh populates all tags in the registries + */ + @Inject(method = "refresh(Lnet/minecraft/util/registry/DynamicRegistryManager;)V", at = @At("RETURN")) + private void injectReload(DynamicRegistryManager dynamicRegistryManager, CallbackInfo ci) { + TagUtil.registerWorldPresetTags(dynamicRegistryManager.get(Registry.WORLD_PRESET_KEY)); + + Registry biomeRegistry = dynamicRegistryManager.get(Registry.BIOME_KEY); + TagUtil.registerBiomeTags(biomeRegistry); + BiomeUtil.registerFlora(biomeRegistry); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/MinecraftServerMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/MinecraftServerMixin.java new file mode 100644 index 000000000..a524a9df7 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/MinecraftServerMixin.java @@ -0,0 +1,32 @@ +package com.dfsek.terra.forge.mixin.lifecycle; + +import com.dfsek.terra.forge.ForgeEntryPoint; + +import com.mojang.datafixers.DataFixer; +import net.minecraft.resource.ResourcePackManager; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.SaveLoader; +import net.minecraft.server.WorldGenerationProgressListenerFactory; +import net.minecraft.util.ApiServices; +import net.minecraft.world.level.storage.LevelStorage; +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.net.Proxy; + + +@Mixin(MinecraftServer.class) +public class MinecraftServerMixin { + @Inject(method = "(Ljava/lang/Thread;Lnet/minecraft/world/level/storage/LevelStorage$Session;" + + "Lnet/minecraft/resource/ResourcePackManager;Lnet/minecraft/server/SaveLoader;Ljava/net/Proxy;" + + "Lcom/mojang/datafixers/DataFixer;Lnet/minecraft/util/ApiServices;" + + "Lnet/minecraft/server/WorldGenerationProgressListenerFactory;)V", + at = @At("RETURN")) + private void injectConstructor(Thread serverThread, LevelStorage.Session session, ResourcePackManager dataPackManager, + SaveLoader saveLoader, Proxy proxy, DataFixer dataFixer, ApiServices apiServices, + WorldGenerationProgressListenerFactory worldGenerationProgressListenerFactory, CallbackInfo ci) { + ForgeEntryPoint.getPlatform().setServer((MinecraftServer) (Object) this); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java new file mode 100644 index 000000000..67008fbba --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java @@ -0,0 +1,31 @@ +package com.dfsek.terra.forge.mixin.lifecycle; + +import com.dfsek.terra.forge.util.SeedHack; + +import net.minecraft.util.math.noise.DoublePerlinNoiseSampler; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; +import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; +import net.minecraft.world.gen.noise.NoiseConfig; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +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; + + +/** + * Hack to map noise sampler to seeds + */ +@Mixin(NoiseConfig.class) +public class NoiseConfigMixin { + @Shadow + @Final + private MultiNoiseSampler multiNoiseSampler; + + @Inject(method = "(Lnet/minecraft/world/gen/chunk/ChunkGeneratorSettings;Lnet/minecraft/util/registry/Registry;J)V", at = @At("TAIL")) + private void mapMultiNoise(ChunkGeneratorSettings chunkGeneratorSettings, Registry noiseRegistry, long seed, CallbackInfo ci) { + SeedHack.register(multiNoiseSampler, seed); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/RegistryMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/RegistryMixin.java new file mode 100644 index 000000000..18633dc0f --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/RegistryMixin.java @@ -0,0 +1,20 @@ +package com.dfsek.terra.forge.mixin.lifecycle; + + +import net.minecraft.util.registry.Registry; +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 com.dfsek.terra.forge.ForgeEntryPoint; + + +// Register Terra things to the builtin registries. +@Mixin(Registry.class) +public class RegistryMixin { + @Inject(method = "", at = @At("RETURN")) + private static void registerTerraGenerators(CallbackInfo ci) { + ForgeEntryPoint.register(); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/client/MinecraftClientMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/client/MinecraftClientMixin.java new file mode 100644 index 000000000..ee2e01268 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/client/MinecraftClientMixin.java @@ -0,0 +1,41 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.lifecycle.client; + +import com.dfsek.terra.forge.util.LifecycleUtil; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.RunArgs; +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; + + +@Mixin(MinecraftClient.class) +public class MinecraftClientMixin { + @Inject(method = "", at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/util/WindowProvider;createWindow" + + "(Lnet/minecraft/client/WindowSettings;Ljava/lang/String;Ljava/lang/String;)" + + "Lnet/minecraft/client/util/Window;", + // sorta arbitrary position, after mod init, before window opens + shift = At.Shift.BEFORE)) + public void injectConstructor(RunArgs args, CallbackInfo callbackInfo) { + LifecycleUtil.initialize(); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/package-info.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/package-info.java new file mode 100644 index 000000000..eba8981f7 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/package-info.java @@ -0,0 +1,22 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +/** + * Mixins that inject behavior into the client/server lifecycle. + */ + +package com.dfsek.terra.forge.mixin.lifecycle; \ No newline at end of file diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/server/ServerMainMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/server/ServerMainMixin.java new file mode 100644 index 000000000..70d93969e --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/server/ServerMainMixin.java @@ -0,0 +1,40 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.mixin.lifecycle.server; + +import com.dfsek.terra.forge.util.LifecycleUtil; + +import net.minecraft.server.Main; +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; + + +@Mixin(Main.class) +public class ServerMainMixin { + @Inject(method = "main([Ljava/lang/String;)V", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/resource/ResourcePackManager;(Lnet/minecraft/resource/ResourceType;" + + "[Lnet/minecraft/resource/ResourcePackProvider;)V") + // after registry manager creation + ) + private static void injectConstructor(String[] args, CallbackInfo ci) { + LifecycleUtil.initialize(); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin_ifaces/FloraFeatureHolder.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin_ifaces/FloraFeatureHolder.java new file mode 100644 index 000000000..2797691f4 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin_ifaces/FloraFeatureHolder.java @@ -0,0 +1,10 @@ +package com.dfsek.terra.forge.mixin_ifaces; + +import net.minecraft.world.gen.feature.ConfiguredFeature; + +import java.util.List; + + +public interface FloraFeatureHolder { + void setFloraFeatures(List> features); +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java new file mode 100644 index 000000000..9e4c1e257 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java @@ -0,0 +1,169 @@ +package com.dfsek.terra.forge.util; + +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.world.biome.Biome; +import com.dfsek.terra.forge.ForgeEntryPoint; +import com.dfsek.terra.forge.config.PreLoadCompatibilityOptions; +import com.dfsek.terra.forge.config.VanillaBiomeProperties; + +import com.dfsek.terra.forge.mixin_ifaces.FloraFeatureHolder; + +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.BuiltinRegistries; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.world.biome.Biome.Builder; +import net.minecraft.world.biome.BiomeEffects; +import net.minecraft.world.biome.GenerationSettings; +import net.minecraft.world.gen.feature.ConfiguredFeature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + + +public final class BiomeUtil { + private static final Logger logger = LoggerFactory.getLogger(BiomeUtil.class); + + private static final Map> + TERRA_BIOME_MAP = new HashMap<>(); + + private BiomeUtil() { + + } + + public static String createBiomeID(ConfigPack pack, com.dfsek.terra.api.registry.key.RegistryKey biomeID) { + return pack.getID() + .toLowerCase() + "/" + biomeID.getNamespace().toLowerCase(Locale.ROOT) + "/" + biomeID.getID().toLowerCase(Locale.ROOT); + } + + public static void registerBiomes() { + logger.info("Registering biomes..."); + ForgeEntryPoint.getPlatform().getConfigRegistry().forEach(pack -> { // Register all Terra biomes. + pack.getCheckedRegistry(Biome.class) + .forEach((id, biome) -> registerBiome(biome, pack, id)); + }); + registerFlora(BuiltinRegistries.BIOME); + logger.info("Terra biomes registered."); + } + + /** + * Clones a Vanilla biome and injects Terra data to create a Terra-vanilla biome delegate. + * + * @param biome The Terra BiomeBuilder. + * @param pack The ConfigPack this biome belongs to. + */ + private static void registerBiome(Biome biome, ConfigPack pack, + com.dfsek.terra.api.registry.key.RegistryKey id) { + Registry registry = BuiltinRegistries.BIOME; + RegistryKey vanilla = ((ProtoPlatformBiome) biome.getPlatformBiome()).get(registry); + + + if(pack.getContext().get(PreLoadCompatibilityOptions.class).useVanillaBiomes()) { + ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(vanilla); + } else { + net.minecraft.world.biome.Biome minecraftBiome = createBiome(biome, registry.get(vanilla)); + + Identifier identifier = new Identifier("terra", createBiomeID(pack, id)); + + if(registry.containsId(identifier)) { + ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(FabricUtil.getEntry(registry, identifier) + .orElseThrow() + .getKey() + .orElseThrow()); + } else { + ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(BuiltinRegistries.add(registry, + registerKey(identifier).getValue(), + minecraftBiome).getKey().orElseThrow()); + } + + TERRA_BIOME_MAP.computeIfAbsent(vanilla.getValue(), i -> new ArrayList<>()).add(identifier); + } + } + + public static void registerFlora(Registry biomes) { + logger.info("Injecting flora into Terra biomes..."); + TERRA_BIOME_MAP + .forEach((vb, terraBiomes) -> + biomes.getOrEmpty(vb) + .ifPresentOrElse(vanilla -> terraBiomes + .forEach(tb -> biomes.getOrEmpty(tb) + .ifPresentOrElse( + terra -> { + List> flowerFeatures = List.copyOf(vanilla.getGenerationSettings().getFlowerFeatures()); + logger.debug("Injecting flora into biome {} : {}", tb, flowerFeatures); + ((FloraFeatureHolder) terra.getGenerationSettings()).setFloraFeatures(flowerFeatures); + }, + () -> logger.error( + "No such biome: {}", + tb))), + () -> logger.error("No vanilla biome: {}", vb))); + + } + + public static Map> getTerraBiomeMap() { + return Map.copyOf(TERRA_BIOME_MAP); + } + + private static RegistryKey registerKey(Identifier identifier) { + return RegistryKey.of(Registry.BIOME_KEY, identifier); + } + + public static net.minecraft.world.biome.Biome createBiome(Biome biome, net.minecraft.world.biome.Biome vanilla) { + GenerationSettings.Builder generationSettings = new GenerationSettings.Builder(); + + BiomeEffects.Builder effects = new BiomeEffects.Builder(); + + net.minecraft.world.biome.Biome.Builder builder = new Builder(); + + if(biome.getContext().has(VanillaBiomeProperties.class)) { + VanillaBiomeProperties vanillaBiomeProperties = biome.getContext().get(VanillaBiomeProperties.class); + + effects.waterColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterColor(), vanilla.getWaterColor())) + .waterFogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterFogColor(), vanilla.getWaterFogColor())) + .fogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getFogColor(), vanilla.getFogColor())) + .skyColor(Objects.requireNonNullElse(vanillaBiomeProperties.getSkyColor(), vanilla.getSkyColor())) + .grassColorModifier( + Objects.requireNonNullElse(vanillaBiomeProperties.getModifier(), vanilla.getEffects().getGrassColorModifier())); + + + if(vanillaBiomeProperties.getGrassColor() == null) { + vanilla.getEffects().getGrassColor().ifPresent(effects::grassColor); + } else { + effects.grassColor(vanillaBiomeProperties.getGrassColor()); + } + + if(vanillaBiomeProperties.getFoliageColor() == null) { + vanilla.getEffects().getFoliageColor().ifPresent(effects::foliageColor); + } else { + effects.foliageColor(vanillaBiomeProperties.getFoliageColor()); + } + + builder.precipitation(Objects.requireNonNullElse(vanillaBiomeProperties.getPrecipitation(), vanilla.getPrecipitation())); + + } else { + effects.waterColor(vanilla.getWaterColor()) + .waterFogColor(vanilla.getWaterFogColor()) + .fogColor(vanilla.getFogColor()) + .skyColor(vanilla.getSkyColor()); + vanilla.getEffects().getFoliageColor().ifPresent(effects::foliageColor); + vanilla.getEffects().getGrassColor().ifPresent(effects::grassColor); + + builder.precipitation(vanilla.getPrecipitation()); + } + + vanilla.getLoopSound().ifPresent(effects::loopSound); + vanilla.getAdditionsSound().ifPresent(effects::additionsSound); + vanilla.getMoodSound().ifPresent(effects::moodSound); + vanilla.getMusic().ifPresent(effects::music); + vanilla.getParticleConfig().ifPresent(effects::particleConfig); + + return builder + .temperature(vanilla.getTemperature()) + .downfall(vanilla.getDownfall()) + .effects(effects.build()) + .spawnSettings(vanilla.getSpawnSettings()) + .generationSettings(generationSettings.build()) + .build(); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/FabricAdapter.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/FabricAdapter.java new file mode 100644 index 000000000..b7bc9f010 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/FabricAdapter.java @@ -0,0 +1,185 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.util; + +import net.minecraft.block.enums.BlockHalf; +import net.minecraft.block.enums.WallShape; +import net.minecraft.block.enums.WireConnection; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.HeightLimitView; + +import com.dfsek.terra.api.block.state.properties.enums.Axis; +import com.dfsek.terra.api.block.state.properties.enums.Half; +import com.dfsek.terra.api.block.state.properties.enums.RailShape; +import com.dfsek.terra.api.block.state.properties.enums.RedstoneConnection; +import com.dfsek.terra.api.block.state.properties.enums.WallHeight; +import com.dfsek.terra.api.util.vector.Vector3; +import com.dfsek.terra.api.world.info.WorldProperties; + + +public final class FabricAdapter { + public static BlockPos adapt(Vector3 v) { + return new BlockPos(v.getBlockX(), v.getBlockY(), v.getBlockZ()); + } + + public static Vector3 adapt(BlockPos pos) { + return Vector3.of(pos.getX(), pos.getY(), pos.getZ()); + } + + public static Direction adapt(com.dfsek.terra.api.block.state.properties.enums.Direction direction) { + return switch(direction) { + case SOUTH -> Direction.SOUTH; + case NORTH -> Direction.NORTH; + case WEST -> Direction.WEST; + case EAST -> Direction.EAST; + case UP -> Direction.UP; + case DOWN -> Direction.DOWN; + }; + } + + public static WorldProperties adapt(HeightLimitView height, long seed) { + return new WorldProperties() { + @Override + public long getSeed() { + return seed; + } + + @Override + public int getMaxHeight() { + return height.getTopY(); + } + + @Override + public int getMinHeight() { + return height.getBottomY(); + } + + @Override + public Object getHandle() { + return height; + } + }; + } + + public static com.dfsek.terra.api.block.state.properties.enums.Direction adapt(Direction direction) { + return switch(direction) { + case SOUTH -> com.dfsek.terra.api.block.state.properties.enums.Direction.SOUTH; + case NORTH -> com.dfsek.terra.api.block.state.properties.enums.Direction.NORTH; + case WEST -> com.dfsek.terra.api.block.state.properties.enums.Direction.WEST; + case EAST -> com.dfsek.terra.api.block.state.properties.enums.Direction.EAST; + case UP -> com.dfsek.terra.api.block.state.properties.enums.Direction.UP; + case DOWN -> com.dfsek.terra.api.block.state.properties.enums.Direction.DOWN; + }; + } + + public static WallHeight adapt(WallShape shape) { + return switch(shape) { + case LOW -> WallHeight.LOW; + case NONE -> WallHeight.NONE; + case TALL -> WallHeight.TALL; + }; + } + + public static WallShape adapt(WallHeight shape) { + return switch(shape) { + case LOW -> WallShape.LOW; + case NONE -> WallShape.NONE; + case TALL -> WallShape.TALL; + }; + } + + public static RedstoneConnection adapt(WireConnection connection) { + return switch(connection) { + case NONE -> RedstoneConnection.NONE; + case UP -> RedstoneConnection.UP; + case SIDE -> RedstoneConnection.SIDE; + }; + } + + public static WireConnection adapt(RedstoneConnection connection) { + return switch(connection) { + case NONE -> WireConnection.NONE; + case UP -> WireConnection.UP; + case SIDE -> WireConnection.SIDE; + }; + } + + + public static Half adapt(BlockHalf half) { + return switch(half) { + case BOTTOM -> Half.BOTTOM; + case TOP -> Half.TOP; + }; + } + + public static BlockHalf adapt(Half half) { + return switch(half) { + case TOP -> BlockHalf.TOP; + case BOTTOM -> BlockHalf.BOTTOM; + default -> throw new IllegalStateException(); + }; + } + + public static RailShape adapt(net.minecraft.block.enums.RailShape railShape) { + return switch(railShape) { + case EAST_WEST -> RailShape.EAST_WEST; + case NORTH_EAST -> RailShape.NORTH_EAST; + case NORTH_WEST -> RailShape.NORTH_WEST; + case SOUTH_EAST -> RailShape.SOUTH_EAST; + case SOUTH_WEST -> RailShape.SOUTH_WEST; + case NORTH_SOUTH -> RailShape.NORTH_SOUTH; + case ASCENDING_EAST -> RailShape.ASCENDING_EAST; + case ASCENDING_NORTH -> RailShape.ASCENDING_NORTH; + case ASCENDING_SOUTH -> RailShape.ASCENDING_SOUTH; + case ASCENDING_WEST -> RailShape.ASCENDING_WEST; + }; + } + + public static net.minecraft.block.enums.RailShape adapt(RailShape railShape) { + return switch(railShape) { + case EAST_WEST -> net.minecraft.block.enums.RailShape.EAST_WEST; + case NORTH_EAST -> net.minecraft.block.enums.RailShape.NORTH_EAST; + case NORTH_WEST -> net.minecraft.block.enums.RailShape.NORTH_WEST; + case SOUTH_EAST -> net.minecraft.block.enums.RailShape.SOUTH_EAST; + case SOUTH_WEST -> net.minecraft.block.enums.RailShape.SOUTH_WEST; + case NORTH_SOUTH -> net.minecraft.block.enums.RailShape.NORTH_SOUTH; + case ASCENDING_EAST -> net.minecraft.block.enums.RailShape.ASCENDING_EAST; + case ASCENDING_NORTH -> net.minecraft.block.enums.RailShape.ASCENDING_NORTH; + case ASCENDING_SOUTH -> net.minecraft.block.enums.RailShape.ASCENDING_SOUTH; + case ASCENDING_WEST -> net.minecraft.block.enums.RailShape.ASCENDING_WEST; + }; + } + + + public static Axis adapt(Direction.Axis axis) { + return switch(axis) { + case X -> Axis.X; + case Y -> Axis.Y; + case Z -> Axis.Z; + }; + } + + public static Direction.Axis adapt(Axis axis) { + return switch(axis) { + case Z -> Direction.Axis.Z; + case Y -> Direction.Axis.Y; + case X -> Direction.Axis.X; + }; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/FabricUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/FabricUtil.java new file mode 100644 index 000000000..8f854186f --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/FabricUtil.java @@ -0,0 +1,61 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.util; + +import net.minecraft.block.entity.LootableContainerBlockEntity; +import net.minecraft.block.entity.MobSpawnerBlockEntity; +import net.minecraft.block.entity.SignBlockEntity; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryEntry; +import net.minecraft.world.WorldAccess; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Optional; + +import com.dfsek.terra.api.block.entity.BlockEntity; +import com.dfsek.terra.api.block.entity.Container; +import com.dfsek.terra.api.block.entity.MobSpawner; +import com.dfsek.terra.api.block.entity.Sign; + + +public final class FabricUtil { + private FabricUtil() { + + } + + public static BlockEntity createState(WorldAccess worldAccess, BlockPos pos) { + net.minecraft.block.entity.BlockEntity entity = worldAccess.getBlockEntity(pos); + if(entity instanceof SignBlockEntity) { + return (Sign) entity; + } else if(entity instanceof MobSpawnerBlockEntity) { + return (MobSpawner) entity; + } else if(entity instanceof LootableContainerBlockEntity) { + return (Container) entity; + } + return null; + } + + public static Optional> getEntry(Registry registry, Identifier identifier) { + return registry.getOrEmpty(identifier) + .flatMap(registry::getKey) + .map(registry::getOrCreateEntry); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java new file mode 100644 index 000000000..560a200bc --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java @@ -0,0 +1,100 @@ +package com.dfsek.terra.forge.util; + +import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; +import com.dfsek.terra.forge.ForgeEntryPoint; +import com.dfsek.terra.forge.generation.FabricChunkGeneratorWrapper; +import com.dfsek.terra.forge.generation.TerraBiomeSource; + +import net.minecraft.structure.StructureSet; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.noise.DoublePerlinNoiseSampler.NoiseParameters; +import net.minecraft.util.registry.BuiltinRegistries; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryEntry; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.source.MultiNoiseBiomeSource; +import net.minecraft.world.biome.source.TheEndBiomeSource; +import net.minecraft.world.dimension.DimensionOptions; +import net.minecraft.world.dimension.DimensionType; +import net.minecraft.world.dimension.DimensionTypes; +import net.minecraft.world.gen.WorldPreset; +import net.minecraft.world.gen.chunk.ChunkGenerator; +import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; +import net.minecraft.world.gen.chunk.NoiseChunkGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; + + +public class LifecycleUtil { + private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleUtil.class); + + private static final List PRESETS = new ArrayList<>(); + public static void initialize() { + ForgeEntryPoint.getPlatform().getEventManager().callEvent( + new PlatformInitializationEvent()); + BiomeUtil.registerBiomes(); + + + LOGGER.info("Registering Terra world types..."); + + Registry dimensionTypeRegistry = BuiltinRegistries.DIMENSION_TYPE; + Registry chunkGeneratorSettingsRegistry = BuiltinRegistries.CHUNK_GENERATOR_SETTINGS; + Registry structureSetRegistry = BuiltinRegistries.STRUCTURE_SET; + Registry noiseParametersRegistry = BuiltinRegistries.NOISE_PARAMETERS; + Registry biomeRegistry = BuiltinRegistries.BIOME; + + RegistryEntry theNetherDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.THE_NETHER); + RegistryEntry + netherChunkGeneratorSettings = chunkGeneratorSettingsRegistry.getOrCreateEntry(ChunkGeneratorSettings.NETHER); + DimensionOptions netherDimensionOptions = new DimensionOptions(theNetherDimensionType, + new NoiseChunkGenerator(structureSetRegistry, + noiseParametersRegistry, + MultiNoiseBiomeSource.Preset.NETHER.getBiomeSource( + biomeRegistry), + netherChunkGeneratorSettings)); + RegistryEntry theEndDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.THE_END); + RegistryEntry endChunkGeneratorSettings = chunkGeneratorSettingsRegistry.getOrCreateEntry( + ChunkGeneratorSettings.END); + DimensionOptions endDimensionOptions = new DimensionOptions(theEndDimensionType, + new NoiseChunkGenerator(structureSetRegistry, noiseParametersRegistry, + new TheEndBiomeSource(biomeRegistry), + endChunkGeneratorSettings)); + + RegistryEntry overworldDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.OVERWORLD); + + RegistryEntry overworld = chunkGeneratorSettingsRegistry.getOrCreateEntry(ChunkGeneratorSettings.OVERWORLD); + ForgeEntryPoint + .getPlatform() + .getRawConfigRegistry() + .forEach((id, pack) -> { + Identifier generatorID = Identifier.of("terra", pack.getID().toLowerCase(Locale.ROOT) + "/" + pack.getNamespace().toLowerCase( + Locale.ROOT)); + + PRESETS.add(generatorID); + + TerraBiomeSource biomeSource = new TerraBiomeSource(biomeRegistry, pack); + ChunkGenerator generator = new FabricChunkGeneratorWrapper(structureSetRegistry, biomeSource, pack, overworld); + + DimensionOptions dimensionOptions = new DimensionOptions(overworldDimensionType, generator); + WorldPreset preset = new WorldPreset( + Map.of( + DimensionOptions.OVERWORLD, dimensionOptions, + DimensionOptions.NETHER, netherDimensionOptions, + DimensionOptions.END, endDimensionOptions + ) + ); + BuiltinRegistries.add(BuiltinRegistries.WORLD_PRESET, generatorID, preset); + LOGGER.info("Registered world type \"{}\"", generatorID); + } + ); + } + + public static List getPresets() { + return PRESETS; + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java new file mode 100644 index 000000000..b67932f0b --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java @@ -0,0 +1,55 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.util; + +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.world.biome.Biome; + +import java.util.Objects; + +import com.dfsek.terra.api.world.biome.PlatformBiome; + + +public class ProtoPlatformBiome implements PlatformBiome { + private final Identifier identifier; + + private RegistryKey delegate; + + public ProtoPlatformBiome(Identifier identifier) { + this.identifier = identifier; + } + + public RegistryKey get(Registry registry) { + return FabricUtil.getEntry(registry, identifier).orElseThrow().getKey().orElseThrow(); + } + + @Override + public Object getHandle() { + return identifier; + } + + public RegistryKey getDelegate() { + return delegate; + } + + public void setDelegate(RegistryKey delegate) { + this.delegate = Objects.requireNonNull(delegate); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/SeedHack.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/SeedHack.java new file mode 100644 index 000000000..5eaf38093 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/SeedHack.java @@ -0,0 +1,29 @@ +package com.dfsek.terra.forge.util; + +import it.unimi.dsi.fastutil.objects.Object2LongMap; +import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; +import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * Holder for hacky biome source seed workaround + */ +public class SeedHack { + private static final Logger LOGGER = LoggerFactory.getLogger(SeedHack.class); + + private static final Object2LongMap seedMap = new Object2LongOpenHashMap<>(); + + public static long getSeed(MultiNoiseSampler sampler) { + if(!seedMap.containsKey(sampler)) { + throw new IllegalArgumentException("Sampler is not registered: " + sampler); + } + return seedMap.getLong(sampler); + } + + public static void register(MultiNoiseSampler sampler, long seed) { + LOGGER.info("Registered seed {} to sampler {}", seed, sampler.hashCode()); + seedMap.put(sampler, seed); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java new file mode 100644 index 000000000..27b33a210 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java @@ -0,0 +1,103 @@ +package com.dfsek.terra.forge.util; + +import com.google.common.collect.ImmutableMap; +import net.minecraft.tag.TagKey; +import net.minecraft.tag.WorldPresetTags; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryEntry; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.gen.WorldPreset; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +public final class TagUtil { + private static final Logger logger = LoggerFactory.getLogger(TagUtil.class); + + private TagUtil() { + + } + + private static Map, List>> tagsToMutableMap(Registry registry) { + return registry + .streamTagsAndEntries() + .collect(HashMap::new, + (map, pair) -> + map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())), + HashMap::putAll); + } + + public static void registerWorldPresetTags(Registry registry) { + logger.info("Doing preset tag garbage...."); + Map, List>> collect = tagsToMutableMap(registry); + + LifecycleUtil + .getPresets() + .forEach(id -> FabricUtil + .getEntry(registry, id) + .ifPresentOrElse( + preset -> collect + .computeIfAbsent(WorldPresetTags.NORMAL, tag -> new ArrayList<>()) + .add(preset), + () -> logger.error("Preset {} does not exist!", id))); + + registry.clearTags(); + registry.populateTags(ImmutableMap.copyOf(collect)); + } + + public static void registerBiomeTags(Registry registry) { + logger.info("Doing biome tag garbage...."); + Map, List>> collect = tagsToMutableMap(registry); + + BiomeUtil + .getTerraBiomeMap() + .forEach((vb, terraBiomes) -> + FabricUtil + .getEntry(registry, vb) + .ifPresentOrElse( + vanilla -> terraBiomes + .forEach(tb -> FabricUtil + .getEntry(registry, tb) + .ifPresentOrElse( + terra -> { + logger.debug( + vanilla.getKey() + .orElseThrow() + .getValue() + + " (vanilla for " + + terra.getKey() + .orElseThrow() + .getValue() + + ": " + + vanilla.streamTags() + .toList()); + + vanilla.streamTags() + .forEach( + tag -> collect + .computeIfAbsent( + tag, + t -> new ArrayList<>()) + .add(terra)); + }, + () -> logger.error( + "No such biome: {}", + tb))), + () -> logger.error("No vanilla biome: {}", vb))); + + registry.clearTags(); + registry.populateTags(ImmutableMap.copyOf(collect)); + + if(logger.isDebugEnabled()) { + registry.streamEntries() + .map(e -> e.registryKey().getValue() + ": " + + e.streamTags().reduce("", (s, t) -> t.id() + ", " + s, String::concat)) + .forEach(logger::debug); + } + } +} diff --git a/platforms/forge/src/main/resources/META-INF/mods.toml b/platforms/forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 000000000..ae314f8d3 --- /dev/null +++ b/platforms/forge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,24 @@ +modLoader = "javafml" +loaderVersion = "[41,)" +license = "GNU General Public License, v3.0" +issueTrackerURL="https://github.com/PolyhedralDev/Terra/issues" + +[[mods]] +modId = "terra" +version = "@VERSION@" +displayName = "Terra" +description = "@DESCRIPTION@" + +[[dependencies.terra]] +modId = "forge" +mandatory = true +versionRange = "[41,)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.terra]] +modId = "minecraft" +mandatory = true +versionRange = "[1.19,)" +ordering = "NONE" +side = "BOTH" \ No newline at end of file diff --git a/platforms/forge/src/main/resources/assets/terra/icon.png b/platforms/forge/src/main/resources/assets/terra/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a8f458866a0d1cd397e5fa592ef1707a97722f1f GIT binary patch literal 129860 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%0DMHvKS|?`Q93A21D4 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

C7Im@Ow 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 Date: Sun, 19 Jun 2022 22:46:46 -0700 Subject: [PATCH 03/38] graceful fallback if resource cannot be loaded --- .../src/main/java/com/dfsek/terra/AbstractPlatform.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/common/implementation/base/src/main/java/com/dfsek/terra/AbstractPlatform.java b/common/implementation/base/src/main/java/com/dfsek/terra/AbstractPlatform.java index fe04ef97e..81933014f 100644 --- a/common/implementation/base/src/main/java/com/dfsek/terra/AbstractPlatform.java +++ b/common/implementation/base/src/main/java/com/dfsek/terra/AbstractPlatform.java @@ -111,8 +111,12 @@ public abstract class AbstractPlatform implements Platform { logger.info("Loading config.yml"); File configFile = new File(getDataFolder(), "config.yml"); if(!configFile.exists()) { - logger.info("Writing new config.yml..."); - FileUtils.copyInputStreamToFile(stream, configFile); + logger.info("Dumping config.yml..."); + if(stream == null) { + logger.warn("Could not find config.yml in JAR"); + } else { + FileUtils.copyInputStreamToFile(stream, configFile); + } } } catch(IOException e) { logger.error("Error loading config.yml resource from jar", e); From 924783adb2d48c445ec6c5ede933ea5fe39b7639 Mon Sep 17 00:00:00 2001 From: dfsek Date: Sun, 19 Jun 2022 22:47:06 -0700 Subject: [PATCH 04/38] clean up buildscript --- platforms/forge/build.gradle.kts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/platforms/forge/build.gradle.kts b/platforms/forge/build.gradle.kts index 31c5632f2..14eaa5bde 100644 --- a/platforms/forge/build.gradle.kts +++ b/platforms/forge/build.gradle.kts @@ -1,14 +1,9 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import java.util.* -import net.fabricmc.loom.task.RemapJarTask - plugins { id("dev.architectury.loom") version Versions.Forge.architecuryLoom } dependencies { shadedApi(project(":common:implementation:base")) - forgeRuntimeLibrary(project(":common:implementation:base")) forge(group = "net.minecraftforge", name = "forge", version = Versions.Forge.forge) @@ -23,10 +18,11 @@ loom { forge { mixinConfigs.set(listOf("terra.mixins.json")) - } } + + tasks { jar { manifest { From 08299602320517d371528541518e4f307dc14f0a Mon Sep 17 00:00:00 2001 From: dfsek Date: Sun, 19 Jun 2022 23:08:52 -0700 Subject: [PATCH 05/38] simplify Fabric buildscript --- platforms/fabric/build.gradle.kts | 52 +++++++------------------------ 1 file changed, 12 insertions(+), 40 deletions(-) diff --git a/platforms/fabric/build.gradle.kts b/platforms/fabric/build.gradle.kts index a89870146..9a98e394e 100644 --- a/platforms/fabric/build.gradle.kts +++ b/platforms/fabric/build.gradle.kts @@ -1,10 +1,5 @@ -import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import com.modrinth.minotaur.TaskModrinthUpload -import net.fabricmc.loom.task.RemapJarTask - plugins { id("fabric-loom") version Versions.Fabric.loom - id("com.modrinth.minotaur") version Versions.Fabric.minotaur id("io.github.juuxel.loom-quiltflower") version Versions.Fabric.loomQuiltflower } @@ -38,44 +33,21 @@ loom { } - addonDir(project.file("./run/config/Terra/addons"), tasks.named("runClient").get()) addonDir(project.file("./run/config/Terra/addons"), tasks.named("runServer").get()) -tasks.withType().configureEach { - options.release.set(17) -} -tasks.getByName("shadowJar") { - exclude("org/slf4j/**") -} +tasks { + compileJava { + options.release.set(17) + } -val remapped = tasks.register("remapShadedJar") { - dependsOn("installAddons") - group = "fabric" - val shadowJar = tasks.getByName("shadowJar") - dependsOn(shadowJar) - inputFile.set(shadowJar.archiveFile) - archiveFileName.set(shadowJar.archiveFileName.get().replace(Regex("-shaded\\.jar$"), "-shaded-mapped.jar")) - addNestedDependencies.set(true) + shadowJar { + exclude("org/slf4j/**") + } + + remapJar { + inputFile.set(shadowJar.get().archiveFile) + archiveFileName.set("${rootProject.name.capitalize()}-${project.version}.jar") + } } - -tasks.named("assemble").configure { - dependsOn("remapShadedJar") -} - -tasks.withType { - finalizedBy(remapped) -} - -tasks.register("publishModrinth") { - dependsOn("remapShadedJar") - group = "fabric" - token = System.getenv("MODRINTH_SECRET") - projectId = "FIlZB9L0" - versionNumber = "${project.version}-fabric" - uploadFile = remapped.get().archiveFile.get().asFile - releaseType = "beta" - addGameVersion(Versions.Fabric.minecraft) - addLoader("fabric") -} \ No newline at end of file From cb4c8f28ef793d0fa66d15bfb435a16200603d3f Mon Sep 17 00:00:00 2001 From: dfsek Date: Sun, 19 Jun 2022 23:27:30 -0700 Subject: [PATCH 06/38] clean up bukkit buildscript --- platforms/bukkit/build.gradle.kts | 194 +++--------------------------- 1 file changed, 18 insertions(+), 176 deletions(-) diff --git a/platforms/bukkit/build.gradle.kts b/platforms/bukkit/build.gradle.kts index e0a1bc48a..7221c9f90 100644 --- a/platforms/bukkit/build.gradle.kts +++ b/platforms/bukkit/build.gradle.kts @@ -1,20 +1,9 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import java.net.URL -import java.nio.channels.Channels -import java.nio.file.Files -import java.nio.file.StandardCopyOption plugins { id("xyz.jpenilla.run-paper") version "1.0.6" } -val testDir = "target/server" -val testMem = "3G" - -val paperBuild = 350 -val paperURL = "https://papermc.io/api/v2/projects/paper/versions/%version%/builds/$paperBuild/downloads/paper-%version%-$paperBuild.jar" -val purpurURL = "https://api.purpurmc.org/v2/purpur/%version%/latest/download" - repositories { maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") } @@ -26,174 +15,27 @@ dependencies { shaded("xyz.jpenilla", "reflection-remapper", Versions.Bukkit.reflectionRemapper) } -val throttleCoreCount = 0 - -val jvmFlags = mutableListOf( - "-XX:+UseG1GC", "-XX:+ParallelRefProcEnabled", "-XX:MaxGCPauseMillis=200", - "-XX:+UnlockExperimentalVMOptions", "-XX:+DisableExplicitGC", "-XX:+AlwaysPreTouch", - "-XX:G1NewSizePercent=30", "-XX:G1MaxNewSizePercent=40", "-XX:G1HeapRegionSize=8M", - "-XX:G1ReservePercent=20", "-XX:G1HeapWastePercent=5", "-XX:G1MixedGCCountTarget=4", - "-XX:InitiatingHeapOccupancyPercent=15", "-XX:G1MixedGCLiveThresholdPercent=90", - "-XX:G1RSetUpdatingPauseTimePercent=5", "-XX:SurvivorRatio=32", "-XX:+PerfDisableSharedMem", - "-XX:MaxTenuringThreshold=1", "-Dusing.aikars.flags=https://mcflags.emc.gs", - "-Daikars.new.flags=true", "-DIReallyKnowWhatIAmDoingISwear", /*"-javaagent:paperclip.jar"*/ - ) -if(throttleCoreCount > 0) { - jvmFlags.add("-XX:ActiveProcessorCount=$throttleCoreCount") -} - - -fun downloadPaperclip(url: String, dir: String) { - val clip = URL(url.replace("%version%", Versions.Bukkit.minecraft)) - val clipReadableByteChannel = Channels.newChannel(clip.openStream()) - val clipFile = file("$testDir/$dir/paperclip.jar") - val clipOutputStream = clipFile.outputStream() - val clipFileChannel = clipOutputStream.channel - clipFileChannel.transferFrom(clipReadableByteChannel, 0, Long.MAX_VALUE) -} - -fun copyTerra(dir: String) { - file("$testDir/$dir").walk().forEach { - if (it.name.startsWith("Terra-bukkit") && it.name.endsWith(".jar")) it.delete() // Delete old Terra jar(s) - } - copy { - from("$buildDir/libs/Terra-bukkit-$version-shaded.jar") - into("$testDir/$dir/plugins/") - } -} - -fun installServer(dir: String) { - // clean - file("$testDir/$dir").deleteRecursively() - file("$testDir/$dir/plugins").mkdirs() - // Cloning test setup. - gitClone("https://github.com/PolyhedralDev/WorldGenTestServer") - // Copying plugins - Files.move( - file("WorldGenTestServer/plugins").toPath(), - file("$testDir/$dir/plugins").toPath(), - StandardCopyOption.REPLACE_EXISTING - ) - // Copying config - val serverText = URL("https://raw.githubusercontent.com/PolyhedralDev/WorldGenTestServer/master/server.properties").readText() - file("$testDir/$dir/server.properties").writeText(serverText) - val bukkitText = URL("https://raw.githubusercontent.com/PolyhedralDev/WorldGenTestServer/master/bukkit.yml").readText() - file("$testDir/$dir/bukkit.yml").writeText(bukkitText.replace("\${world}", "world").replace("\${gen}", "Terra:DEFAULT")) - - println("By proceeding, you are agreeing to the Minecraft EULA: https://account.mojang.com/documents/minecraft_eula") - file("$testDir/$dir/eula.txt").writeText("eula=true") - - // clean up - file("WorldGenTestServer").deleteRecursively() -} - -fun deleteFolder(folder: File) { - if (folder.exists()) folder.deleteRecursively() -} - -fun deleteFile(file: File) { - if (file.exists()) file.delete() -} - -tasks.create("cleanWorlds") { - group = "bukkit" - doFirst { - deleteFolder(file("$testDir/paper/world")) - deleteFolder(file("$testDir/paper/world_nether")) - deleteFolder(file("$testDir/paper/world_the_end")) - - deleteFolder(file("$testDir/purpur/world")) - deleteFolder(file("$testDir/purpur/world_nether")) - deleteFolder(file("$testDir/purpur/world_the_end")) - } -} - -tasks.create("updatePaper") { - group = "bukkit" - doFirst { - deleteFile(file("$testDir/paper/paperclip.jar")) - downloadPaperclip(paperURL, "paper") - } -} - -tasks.create("updatePurpur") { - group = "bukkit" - doFirst { - deleteFile(file("$testDir/paper/paperclip.jar")) - downloadPaperclip(purpurURL, "purpur") - } -} - -tasks.create("installPaper") { - group = "bukkit" - dependsOn("shadowJar") - doFirst { - installServer("paper") - // Downloading latest paper jar. - downloadPaperclip(paperURL, "paper") - } -} - -tasks.create("installPurpur") { - group = "bukkit" - dependsOn("shadowJar") - doFirst { - installServer("purpur") - // Downloading latest paper jar. - downloadPaperclip(purpurURL, "purpur") - } -} - -task(name = "runPaper") { - group = "bukkit" - standardInput = System.`in` - dependsOn("shadowJar") - // Copy Terra into dir - doFirst { - copyTerra("paper") +tasks { + shadowJar { + relocate("org.bstats.bukkit", "com.dfsek.terra.lib.bstats") + relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib") + relocate("com.google.common", "com.dfsek.terra.lib.google.common") + relocate("org.apache.logging.slf4j", "com.dfsek.terra.lib.slf4j-over-log4j") + exclude("org/slf4j/**") + exclude("org/checkerframework/**") + exclude("org/jetbrains/annotations/**") + exclude("org/intellij/**") + exclude("com/google/errorprone/**") + exclude("com/google/j2objc/**") + exclude("javax/**") } - mainClass.set("io.papermc.paperclip.Paperclip") - jvmArgs = jvmFlags - maxHeapSize = testMem - minHeapSize = testMem - args = listOf("nogui") - workingDir = file("$testDir/paper") - classpath = files("$testDir/paper/paperclip.jar") -} - -task(name = "runPurpur") { - group = "bukkit" - standardInput = System.`in` - dependsOn("shadowJar") - // Copy Terra into dir - doFirst { - copyTerra("purpur") + runServer { + minecraftVersion("1.19") + dependsOn(shadowJar) + pluginJars(shadowJar.get().archiveFile) } - - mainClass.set("io.papermc.paperclip.Paperclip") - jvmArgs = jvmFlags - maxHeapSize = testMem - minHeapSize = testMem - //args = listOf("nogui") - workingDir = file("$testDir/purpur") - classpath = files("$testDir/purpur/paperclip.jar") -} - -tasks.named("shadowJar") { - relocate("org.bstats.bukkit", "com.dfsek.terra.lib.bstats") - relocate("io.papermc.lib", "com.dfsek.terra.lib.paperlib") - relocate("com.google.common", "com.dfsek.terra.lib.google.common") - relocate("org.apache.logging.slf4j", "com.dfsek.terra.lib.slf4j-over-log4j") - exclude("org/slf4j/**") - exclude("org/checkerframework/**") - exclude("org/jetbrains/annotations/**") - exclude("org/intellij/**") - exclude("com/google/errorprone/**") - exclude("com/google/j2objc/**") - exclude("javax/**") } -addonDir(project.file("./target/server/paper/plugins/Terra/addons"), tasks.named("runPaper").get()) -addonDir(project.file("./target/server/purpur/plugins/Terra/addons"), tasks.named("runPurpur").get()) +addonDir(project.file("./target/server/paper/plugins/Terra/addons"), tasks.named("runServer").get()) From c6428cff66763ef18dac2c165a42f1c9d02ac829 Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 20 Jun 2022 13:58:45 -0700 Subject: [PATCH 07/38] make slf4j compileOnlyAPI --- common/api/build.gradle.kts | 2 +- platforms/fabric/build.gradle.kts | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/common/api/build.gradle.kts b/common/api/build.gradle.kts index fae96eac5..fe36f682e 100644 --- a/common/api/build.gradle.kts +++ b/common/api/build.gradle.kts @@ -1,6 +1,6 @@ dependencies { api("ca.solo-studios", "strata", Versions.Libraries.strata) - api("org.slf4j", "slf4j-api", Versions.Libraries.slf4j) + compileOnlyApi("org.slf4j", "slf4j-api", Versions.Libraries.slf4j) api("cloud.commandframework", "cloud-core", Versions.Libraries.cloud) api("com.dfsek.tectonic", "common", Versions.Libraries.tectonic) diff --git a/platforms/fabric/build.gradle.kts b/platforms/fabric/build.gradle.kts index 9a98e394e..401cea107 100644 --- a/platforms/fabric/build.gradle.kts +++ b/platforms/fabric/build.gradle.kts @@ -41,10 +41,6 @@ tasks { compileJava { options.release.set(17) } - - shadowJar { - exclude("org/slf4j/**") - } remapJar { inputFile.set(shadowJar.get().archiveFile) From f3329bbff1ad57cdd49261e962e180f38f1c94ac Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 20 Jun 2022 18:33:28 -0700 Subject: [PATCH 08/38] rename mixin configs --- platforms/fabric/src/main/resources/fabric.mod.json | 2 +- .../resources/{terra.mixins.json => terra.fabric.mixins.json} | 0 platforms/forge/build.gradle.kts | 2 +- .../resources/{terra.mixins.json => terra.forge.mixins.json} | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename platforms/fabric/src/main/resources/{terra.mixins.json => terra.fabric.mixins.json} (100%) rename platforms/forge/src/main/resources/{terra.mixins.json => terra.forge.mixins.json} (100%) diff --git a/platforms/fabric/src/main/resources/fabric.mod.json b/platforms/fabric/src/main/resources/fabric.mod.json index dcc277954..e6e490c1a 100644 --- a/platforms/fabric/src/main/resources/fabric.mod.json +++ b/platforms/fabric/src/main/resources/fabric.mod.json @@ -21,7 +21,7 @@ ] }, "mixins": [ - "terra.mixins.json" + "terra.fabric.mixins.json" ], "depends": { "fabricloader": ">=0.14.2", diff --git a/platforms/fabric/src/main/resources/terra.mixins.json b/platforms/fabric/src/main/resources/terra.fabric.mixins.json similarity index 100% rename from platforms/fabric/src/main/resources/terra.mixins.json rename to platforms/fabric/src/main/resources/terra.fabric.mixins.json diff --git a/platforms/forge/build.gradle.kts b/platforms/forge/build.gradle.kts index 14eaa5bde..63db47bf2 100644 --- a/platforms/forge/build.gradle.kts +++ b/platforms/forge/build.gradle.kts @@ -17,7 +17,7 @@ loom { } forge { - mixinConfigs.set(listOf("terra.mixins.json")) + mixinConfigs.set(listOf("terra.forge.mixins.json")) } } diff --git a/platforms/forge/src/main/resources/terra.mixins.json b/platforms/forge/src/main/resources/terra.forge.mixins.json similarity index 100% rename from platforms/forge/src/main/resources/terra.mixins.json rename to platforms/forge/src/main/resources/terra.forge.mixins.json From e85afd7dd6c9b7db17257ef60f687f4d251cee60 Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 20 Jun 2022 19:37:17 -0700 Subject: [PATCH 09/38] convert most lifecycle mixins to event listeners --- .../mixin/lifecycle/NoiseConfigMixin.java | 5 +-- .../dfsek/terra/forge/ForgeEntryPoint.java | 6 ++- .../com/dfsek/terra/forge/PlatformImpl.java | 11 +++-- .../mixin/access/ChunkRegionAccessor.java | 15 ------- .../mixin/lifecycle/MinecraftServerMixin.java | 32 --------------- .../mixin/lifecycle/NoiseConfigMixin.java | 24 +++++++---- .../client/MinecraftClientMixin.java | 41 ------------------- .../lifecycle/server/ServerMainMixin.java | 40 ------------------ .../main/resources/terra.forge.mixins.json | 4 -- 9 files changed, 27 insertions(+), 151 deletions(-) delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/ChunkRegionAccessor.java delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/MinecraftServerMixin.java delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/client/MinecraftClientMixin.java delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/server/ServerMainMixin.java diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/NoiseConfigMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/NoiseConfigMixin.java index 6f9af2ed8..b1ddda34f 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/NoiseConfigMixin.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/NoiseConfigMixin.java @@ -1,10 +1,7 @@ package com.dfsek.terra.fabric.mixin.lifecycle; -import com.dfsek.terra.fabric.util.SeedHack; - import net.minecraft.util.math.noise.DoublePerlinNoiseSampler; import net.minecraft.util.registry.Registry; -import net.minecraft.world.biome.source.util.MultiNoiseUtil; import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; import net.minecraft.world.gen.noise.NoiseConfig; @@ -15,6 +12,8 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import com.dfsek.terra.fabric.util.SeedHack; + /** * Hack to map noise sampler to seeds diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java index 22194ac6e..e2aeef71e 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java @@ -27,9 +27,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.dfsek.terra.forge.data.Codecs; +import com.dfsek.terra.forge.util.LifecycleUtil; @Mod("terra") public class ForgeEntryPoint { + public static final String MODID = "terra"; + private static final Logger logger = LoggerFactory.getLogger(ForgeEntryPoint.class); private static final PlatformImpl TERRA_PLUGIN = new PlatformImpl(); @@ -50,7 +53,8 @@ public class ForgeEntryPoint { modEventBus.addListener(this::commonSetup); } - private void commonSetup(final FMLCommonSetupEvent event) { + private void commonSetup(FMLCommonSetupEvent event) { logger.info("Initializing Terra Forge mod..."); + LifecycleUtil.initialize(); } } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java index 3e3791142..3e15ce880 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java @@ -29,7 +29,10 @@ import net.minecraft.util.Identifier; import net.minecraft.util.registry.BuiltinRegistries; import net.minecraft.world.biome.Biome.Precipitation; import net.minecraft.world.biome.BiomeEffects.GrassColorModifier; +import net.minecraftforge.common.ForgeConfig.Common; import net.minecraftforge.fml.loading.FMLLoader; +import net.minecraftforge.fml.loading.targets.FMLServerLaunchHandler; +import net.minecraftforge.server.ServerLifecycleHooks; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -58,18 +61,13 @@ public class PlatformImpl extends AbstractPlatform { private final ItemHandle itemHandle = new FabricItemHandle(); private final WorldHandle worldHandle = new FabricWorldHandle(); private final Lazy dataFolder = Lazy.lazy(() -> new File("./config/Terra")); - private MinecraftServer server; public PlatformImpl() { load(); } - public void setServer(MinecraftServer server) { - this.server = server; - } - public MinecraftServer getServer() { - return server; + return ServerLifecycleHooks.getCurrentServer(); } @Override @@ -78,6 +76,7 @@ public class PlatformImpl extends AbstractPlatform { getRawConfigRegistry().clear(); boolean succeed = getRawConfigRegistry().loadAll(this); + MinecraftServer server = getServer(); if(server != null) { server.reloadResources(server.getDataPackManager().getNames()).exceptionally(throwable -> { diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/ChunkRegionAccessor.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/ChunkRegionAccessor.java deleted file mode 100644 index 58624dfe9..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/ChunkRegionAccessor.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.dfsek.terra.forge.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/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/MinecraftServerMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/MinecraftServerMixin.java deleted file mode 100644 index a524a9df7..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/MinecraftServerMixin.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.dfsek.terra.forge.mixin.lifecycle; - -import com.dfsek.terra.forge.ForgeEntryPoint; - -import com.mojang.datafixers.DataFixer; -import net.minecraft.resource.ResourcePackManager; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.SaveLoader; -import net.minecraft.server.WorldGenerationProgressListenerFactory; -import net.minecraft.util.ApiServices; -import net.minecraft.world.level.storage.LevelStorage; -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.net.Proxy; - - -@Mixin(MinecraftServer.class) -public class MinecraftServerMixin { - @Inject(method = "(Ljava/lang/Thread;Lnet/minecraft/world/level/storage/LevelStorage$Session;" + - "Lnet/minecraft/resource/ResourcePackManager;Lnet/minecraft/server/SaveLoader;Ljava/net/Proxy;" + - "Lcom/mojang/datafixers/DataFixer;Lnet/minecraft/util/ApiServices;" + - "Lnet/minecraft/server/WorldGenerationProgressListenerFactory;)V", - at = @At("RETURN")) - private void injectConstructor(Thread serverThread, LevelStorage.Session session, ResourcePackManager dataPackManager, - SaveLoader saveLoader, Proxy proxy, DataFixer dataFixer, ApiServices apiServices, - WorldGenerationProgressListenerFactory worldGenerationProgressListenerFactory, CallbackInfo ci) { - ForgeEntryPoint.getPlatform().setServer((MinecraftServer) (Object) this); - } -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java index 67008fbba..ca1f00a99 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java @@ -2,17 +2,18 @@ package com.dfsek.terra.forge.mixin.lifecycle; import com.dfsek.terra.forge.util.SeedHack; -import net.minecraft.util.math.noise.DoublePerlinNoiseSampler; -import net.minecraft.util.registry.Registry; +import net.minecraft.util.math.random.RandomSplitter; import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; -import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; +import net.minecraft.world.biome.source.util.MultiNoiseUtil.NoiseHypercube; +import net.minecraft.world.gen.densityfunction.DensityFunction; import net.minecraft.world.gen.noise.NoiseConfig; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; 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.Redirect; + +import java.util.List; /** @@ -22,10 +23,15 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; public class NoiseConfigMixin { @Shadow @Final - private MultiNoiseSampler multiNoiseSampler; + private long legacyWorldSeed; - @Inject(method = "(Lnet/minecraft/world/gen/chunk/ChunkGeneratorSettings;Lnet/minecraft/util/registry/Registry;J)V", at = @At("TAIL")) - private void mapMultiNoise(ChunkGeneratorSettings chunkGeneratorSettings, Registry noiseRegistry, long seed, CallbackInfo ci) { - SeedHack.register(multiNoiseSampler, seed); + @Redirect(method = "(Lnet/minecraft/world/gen/chunk/ChunkGeneratorSettings;Lnet/minecraft/util/registry/Registry;J)V", at = @At(value = "NEW", target = "net/minecraft/world/biome/source/util/MultiNoiseUtil$MultiNoiseSampler.")) + private MultiNoiseSampler t(DensityFunction densityFunction, DensityFunction densityFunction2, DensityFunction densityFunction3, + DensityFunction densityFunction4, DensityFunction densityFunction5, DensityFunction densityFunction6, + List list) { + MultiNoiseSampler sampler = new MultiNoiseSampler(densityFunction, densityFunction2, densityFunction3, densityFunction4, + densityFunction5, densityFunction6, list); + SeedHack.register(sampler, legacyWorldSeed); + return null; } } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/client/MinecraftClientMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/client/MinecraftClientMixin.java deleted file mode 100644 index ee2e01268..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/client/MinecraftClientMixin.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.forge.mixin.lifecycle.client; - -import com.dfsek.terra.forge.util.LifecycleUtil; - -import net.minecraft.client.MinecraftClient; -import net.minecraft.client.RunArgs; -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; - - -@Mixin(MinecraftClient.class) -public class MinecraftClientMixin { - @Inject(method = "", at = @At(value = "INVOKE", - target = "Lnet/minecraft/client/util/WindowProvider;createWindow" + - "(Lnet/minecraft/client/WindowSettings;Ljava/lang/String;Ljava/lang/String;)" + - "Lnet/minecraft/client/util/Window;", - // sorta arbitrary position, after mod init, before window opens - shift = At.Shift.BEFORE)) - public void injectConstructor(RunArgs args, CallbackInfo callbackInfo) { - LifecycleUtil.initialize(); - } -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/server/ServerMainMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/server/ServerMainMixin.java deleted file mode 100644 index 70d93969e..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/server/ServerMainMixin.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.forge.mixin.lifecycle.server; - -import com.dfsek.terra.forge.util.LifecycleUtil; - -import net.minecraft.server.Main; -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; - - -@Mixin(Main.class) -public class ServerMainMixin { - @Inject(method = "main([Ljava/lang/String;)V", - at = @At(value = "INVOKE", - target = "Lnet/minecraft/resource/ResourcePackManager;(Lnet/minecraft/resource/ResourceType;" + - "[Lnet/minecraft/resource/ResourcePackProvider;)V") - // after registry manager creation - ) - private static void injectConstructor(String[] args, CallbackInfo ci) { - LifecycleUtil.initialize(); - } -} diff --git a/platforms/forge/src/main/resources/terra.forge.mixins.json b/platforms/forge/src/main/resources/terra.forge.mixins.json index e1dd26479..77d2c9e44 100644 --- a/platforms/forge/src/main/resources/terra.forge.mixins.json +++ b/platforms/forge/src/main/resources/terra.forge.mixins.json @@ -4,7 +4,6 @@ "package": "com.dfsek.terra.forge.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ - "access.ChunkRegionAccessor", "access.MobSpawnerLogicAccessor", "access.StateAccessor", "access.StructureAccessorAccessor", @@ -36,15 +35,12 @@ "implementations.terra.world.ChunkRegionMixin", "implementations.terra.world.ServerWorldMixin", "lifecycle.DataPackContentsMixin", - "lifecycle.MinecraftServerMixin", "lifecycle.NoiseConfigMixin", "lifecycle.RegistryMixin" ], "client": [ - "lifecycle.client.MinecraftClientMixin" ], "server": [ - "lifecycle.server.ServerMainMixin" ], "injectors": { "defaultRequire": 1 From cce9b69c45aa96f5245d85d28ea1ec6ce8b8b2fa Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 20 Jun 2022 20:05:02 -0700 Subject: [PATCH 10/38] load terra data on RegisterEvent --- .../com/dfsek/terra/forge/ForgeEntryPoint.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java index e2aeef71e..64b58c67d 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java @@ -19,10 +19,15 @@ package com.dfsek.terra.forge; import net.minecraft.util.Identifier; import net.minecraft.util.registry.Registry; +import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.ForgeRegistries.Keys; +import net.minecraftforge.registries.RegisterEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,10 +56,18 @@ public class ForgeEntryPoint { IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); modEventBus.addListener(this::commonSetup); + modEventBus.addListener(EventPriority.LOWEST, this::registerBiomes); } private void commonSetup(FMLCommonSetupEvent event) { logger.info("Initializing Terra Forge mod..."); - LifecycleUtil.initialize(); + } + + private void registerBiomes(RegisterEvent event) { + event.register(Keys.BIOMES, helper -> { + logger.info("Loading Terra data..."); + LifecycleUtil.initialize(); + }); + event.register(Keys.BLOCKS, helper -> logger.debug("Block registration detected.")); } } From 14273268c897d8432787d263fd80d50ef11c6edf Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 20 Jun 2022 21:03:30 -0700 Subject: [PATCH 11/38] remove RegistryMixin --- .../dfsek/terra/forge/ForgeEntryPoint.java | 9 ++++----- .../forge/mixin/lifecycle/RegistryMixin.java | 20 ------------------- .../main/resources/terra.forge.mixins.json | 3 +-- 3 files changed, 5 insertions(+), 27 deletions(-) delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/RegistryMixin.java diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java index 64b58c67d..d00d3622f 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java @@ -17,6 +17,8 @@ package com.dfsek.terra.forge; +import com.dfsek.terra.api.util.generic.Lazy; + import net.minecraft.util.Identifier; import net.minecraft.util.registry.Registry; import net.minecraftforge.eventbus.api.EventPriority; @@ -47,11 +49,6 @@ public class ForgeEntryPoint { return TERRA_PLUGIN; } - public static void register() { // register the things - Registry.register(Registry.CHUNK_GENERATOR, new Identifier("terra:terra"), Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER); - Registry.register(Registry.BIOME_SOURCE, new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE); - } - public ForgeEntryPoint() { IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); @@ -60,6 +57,8 @@ public class ForgeEntryPoint { } private void commonSetup(FMLCommonSetupEvent event) { + Registry.register(Registry.CHUNK_GENERATOR, new Identifier("terra:terra"), Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER); + Registry.register(Registry.BIOME_SOURCE, new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE); logger.info("Initializing Terra Forge mod..."); } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/RegistryMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/RegistryMixin.java deleted file mode 100644 index 18633dc0f..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/RegistryMixin.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.dfsek.terra.forge.mixin.lifecycle; - - -import net.minecraft.util.registry.Registry; -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 com.dfsek.terra.forge.ForgeEntryPoint; - - -// Register Terra things to the builtin registries. -@Mixin(Registry.class) -public class RegistryMixin { - @Inject(method = "", at = @At("RETURN")) - private static void registerTerraGenerators(CallbackInfo ci) { - ForgeEntryPoint.register(); - } -} diff --git a/platforms/forge/src/main/resources/terra.forge.mixins.json b/platforms/forge/src/main/resources/terra.forge.mixins.json index 77d2c9e44..e68b6351b 100644 --- a/platforms/forge/src/main/resources/terra.forge.mixins.json +++ b/platforms/forge/src/main/resources/terra.forge.mixins.json @@ -35,8 +35,7 @@ "implementations.terra.world.ChunkRegionMixin", "implementations.terra.world.ServerWorldMixin", "lifecycle.DataPackContentsMixin", - "lifecycle.NoiseConfigMixin", - "lifecycle.RegistryMixin" + "lifecycle.NoiseConfigMixin" ], "client": [ ], From a47541cfeb9ba5fb234379ff735053f308bb26f0 Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 20 Jun 2022 21:34:52 -0700 Subject: [PATCH 12/38] use annotation event subscriptions --- .../com/dfsek/terra/forge/ForgeEntryPoint.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java index d00d3622f..36dc78fe4 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java @@ -25,6 +25,8 @@ import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.registries.ForgeRegistries; @@ -37,6 +39,7 @@ import com.dfsek.terra.forge.data.Codecs; import com.dfsek.terra.forge.util.LifecycleUtil; @Mod("terra") +@EventBusSubscriber(bus = Bus.MOD) public class ForgeEntryPoint { public static final String MODID = "terra"; @@ -50,19 +53,15 @@ public class ForgeEntryPoint { } public ForgeEntryPoint() { - IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); - - modEventBus.addListener(this::commonSetup); - modEventBus.addListener(EventPriority.LOWEST, this::registerBiomes); - } - - private void commonSetup(FMLCommonSetupEvent event) { Registry.register(Registry.CHUNK_GENERATOR, new Identifier("terra:terra"), Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER); Registry.register(Registry.BIOME_SOURCE, new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE); - logger.info("Initializing Terra Forge mod..."); + IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); + + modEventBus.register(this); } - private void registerBiomes(RegisterEvent event) { + @SubscribeEvent(priority = EventPriority.LOWEST) + public void registerBiomes(RegisterEvent event) { event.register(Keys.BIOMES, helper -> { logger.info("Loading Terra data..."); LifecycleUtil.initialize(); From c120ab76d06f9a9d74e9502355f240c73900902f Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 20 Jun 2022 21:35:32 -0700 Subject: [PATCH 13/38] Revert "remove RegistryMixin" This reverts commit 14273268 --- .../dfsek/terra/forge/ForgeEntryPoint.java | 7 +++++-- .../forge/mixin/lifecycle/RegistryMixin.java | 20 +++++++++++++++++++ .../main/resources/terra.forge.mixins.json | 3 ++- 3 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/RegistryMixin.java diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java index 36dc78fe4..692bc838d 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java @@ -17,8 +17,6 @@ package com.dfsek.terra.forge; -import com.dfsek.terra.api.util.generic.Lazy; - import net.minecraft.util.Identifier; import net.minecraft.util.registry.Registry; import net.minecraftforge.eventbus.api.EventPriority; @@ -52,6 +50,11 @@ public class ForgeEntryPoint { return TERRA_PLUGIN; } + public static void register() { // register the things + Registry.register(Registry.CHUNK_GENERATOR, new Identifier("terra:terra"), Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER); + Registry.register(Registry.BIOME_SOURCE, new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE); + } + public ForgeEntryPoint() { Registry.register(Registry.CHUNK_GENERATOR, new Identifier("terra:terra"), Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER); Registry.register(Registry.BIOME_SOURCE, new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE); diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/RegistryMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/RegistryMixin.java new file mode 100644 index 000000000..18633dc0f --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/RegistryMixin.java @@ -0,0 +1,20 @@ +package com.dfsek.terra.forge.mixin.lifecycle; + + +import net.minecraft.util.registry.Registry; +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 com.dfsek.terra.forge.ForgeEntryPoint; + + +// Register Terra things to the builtin registries. +@Mixin(Registry.class) +public class RegistryMixin { + @Inject(method = "", at = @At("RETURN")) + private static void registerTerraGenerators(CallbackInfo ci) { + ForgeEntryPoint.register(); + } +} diff --git a/platforms/forge/src/main/resources/terra.forge.mixins.json b/platforms/forge/src/main/resources/terra.forge.mixins.json index e68b6351b..77d2c9e44 100644 --- a/platforms/forge/src/main/resources/terra.forge.mixins.json +++ b/platforms/forge/src/main/resources/terra.forge.mixins.json @@ -35,7 +35,8 @@ "implementations.terra.world.ChunkRegionMixin", "implementations.terra.world.ServerWorldMixin", "lifecycle.DataPackContentsMixin", - "lifecycle.NoiseConfigMixin" + "lifecycle.NoiseConfigMixin", + "lifecycle.RegistryMixin" ], "client": [ ], From 13497a02a4f37a3743460689a211c28541e1a2e7 Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 20 Jun 2022 21:46:06 -0700 Subject: [PATCH 14/38] register stuff with events --- .../dfsek/terra/forge/ForgeEntryPoint.java | 10 ++-------- .../forge/mixin/lifecycle/RegistryMixin.java | 20 ------------------- .../main/resources/terra.forge.mixins.json | 3 +-- 3 files changed, 3 insertions(+), 30 deletions(-) delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/RegistryMixin.java diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java index 692bc838d..305dee743 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java @@ -50,16 +50,8 @@ public class ForgeEntryPoint { return TERRA_PLUGIN; } - public static void register() { // register the things - Registry.register(Registry.CHUNK_GENERATOR, new Identifier("terra:terra"), Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER); - Registry.register(Registry.BIOME_SOURCE, new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE); - } - public ForgeEntryPoint() { - Registry.register(Registry.CHUNK_GENERATOR, new Identifier("terra:terra"), Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER); - Registry.register(Registry.BIOME_SOURCE, new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE); IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); - modEventBus.register(this); } @@ -69,6 +61,8 @@ public class ForgeEntryPoint { logger.info("Loading Terra data..."); LifecycleUtil.initialize(); }); + event.register(Registry.CHUNK_GENERATOR_KEY, helper -> helper.register(new Identifier("terra:terra"), Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER)); + event.register(Registry.BIOME_SOURCE_KEY, helper -> helper.register(new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE)); event.register(Keys.BLOCKS, helper -> logger.debug("Block registration detected.")); } } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/RegistryMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/RegistryMixin.java deleted file mode 100644 index 18633dc0f..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/RegistryMixin.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.dfsek.terra.forge.mixin.lifecycle; - - -import net.minecraft.util.registry.Registry; -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 com.dfsek.terra.forge.ForgeEntryPoint; - - -// Register Terra things to the builtin registries. -@Mixin(Registry.class) -public class RegistryMixin { - @Inject(method = "", at = @At("RETURN")) - private static void registerTerraGenerators(CallbackInfo ci) { - ForgeEntryPoint.register(); - } -} diff --git a/platforms/forge/src/main/resources/terra.forge.mixins.json b/platforms/forge/src/main/resources/terra.forge.mixins.json index 77d2c9e44..e68b6351b 100644 --- a/platforms/forge/src/main/resources/terra.forge.mixins.json +++ b/platforms/forge/src/main/resources/terra.forge.mixins.json @@ -35,8 +35,7 @@ "implementations.terra.world.ChunkRegionMixin", "implementations.terra.world.ServerWorldMixin", "lifecycle.DataPackContentsMixin", - "lifecycle.NoiseConfigMixin", - "lifecycle.RegistryMixin" + "lifecycle.NoiseConfigMixin" ], "client": [ ], From a0225d6ece8217cf5bee8cebbf840faef6c5205b Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 20 Jun 2022 22:59:59 -0700 Subject: [PATCH 15/38] legitimately evil hack to fix forge weirdness --- .../dfsek/terra/forge/AwfulForgeHacks.java | 80 +++++++++++++++++++ .../dfsek/terra/forge/ForgeEntryPoint.java | 8 +- 2 files changed, 86 insertions(+), 2 deletions(-) create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/AwfulForgeHacks.java diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/AwfulForgeHacks.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/AwfulForgeHacks.java new file mode 100644 index 000000000..2a362dadf --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/AwfulForgeHacks.java @@ -0,0 +1,80 @@ +package com.dfsek.terra.forge; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.file.FileVisitOption; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.jar.JarFile; +import java.util.stream.Stream; + + +/** + * Forge is really wacky and screws with class resolution in the addon loader. Loading every single Terra class *manually* on startup + * fixes it. If you know of a better way to fix this, PLEASE let us know. + */ +public final class AwfulForgeHacks { + private static final Logger LOGGER = LoggerFactory.getLogger(AwfulForgeHacks.class); + + /** + * Forge tampers with code source to make the *normal* way of getting the current JAR file useless, so this awful hack is + * needed. + * + * + * Class.class.getProtectionDomain() + * .getCodeSource() + * .getLocation() + * .toURI() + * .getPath() + * + * + */ + public static JarFile getTerraJar() throws IOException { + LOGGER.info("Scanning for Terra JAR..."); + return Files.walk(Path.of("./", "mods"), 1, FileVisitOption.FOLLOW_LINKS) + .filter(it -> it.getFileName().toString().endsWith(".jar")) + .peek(path -> LOGGER.info("Found mod: {}", path)) + .map(Path::toFile) + .flatMap(path -> { + try { + return Stream.of(new JarFile(path)); + } catch(IOException e) { + LOGGER.error("Malformed mod JAR: {}: {}", path, e); + return Stream.of(); + } + }) + .filter(jar -> jar + .stream() + .anyMatch(entry -> entry + .getName() + .equals(ForgeEntryPoint.class.getName().replace('.', '/') + ".class"))) + .findFirst() + .orElseThrow(() -> new IllegalStateException("Could not find Terra JAR")); + + } + + public static void loadAllTerraClasses() { + + try(JarFile jar = getTerraJar()) { + jar.stream() + .forEach(jarEntry -> { + if(jarEntry.getName().startsWith("com/dfsek/terra/forge/mixin")) { + return; + } + if(jarEntry.getName().endsWith(".class")) { + String name = jarEntry.getName().replace('/', '.'); + name = name.substring(0, name.length() - 6); + try { + Class.forName(name); + } catch(ClassNotFoundException | NoClassDefFoundError e) { + LOGGER.warn("Failed to load class {}: {}", name, e); + } + } + }); + } catch(IOException e) { + throw new IllegalStateException("Could not load all Terra classes", e); + } + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java index 305dee743..1f20dd2e3 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java @@ -39,12 +39,16 @@ import com.dfsek.terra.forge.util.LifecycleUtil; @Mod("terra") @EventBusSubscriber(bus = Bus.MOD) public class ForgeEntryPoint { + static { + AwfulForgeHacks.loadAllTerraClasses(); + TERRA_PLUGIN = new PlatformImpl(); + } + public static final String MODID = "terra"; private static final Logger logger = LoggerFactory.getLogger(ForgeEntryPoint.class); - private static final PlatformImpl TERRA_PLUGIN = new PlatformImpl(); - + private static final PlatformImpl TERRA_PLUGIN; public static PlatformImpl getPlatform() { return TERRA_PLUGIN; From e1656bac205d665df610b4bff5db4dd8699b75f9 Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 20 Jun 2022 23:25:03 -0700 Subject: [PATCH 16/38] create registry sanity check --- .../dfsek/terra/forge/AwfulForgeHacks.java | 69 +++++++++++++------ .../dfsek/terra/forge/ForgeEntryPoint.java | 20 ++++-- .../dfsek/terra/forge/util/LifecycleUtil.java | 22 +++--- 3 files changed, 73 insertions(+), 38 deletions(-) diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/AwfulForgeHacks.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/AwfulForgeHacks.java index 2a362dadf..5565fd1ba 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/AwfulForgeHacks.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/AwfulForgeHacks.java @@ -7,6 +7,8 @@ import java.io.IOException; import java.nio.file.FileVisitOption; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; import java.util.jar.JarFile; import java.util.stream.Stream; @@ -23,13 +25,12 @@ public final class AwfulForgeHacks { * needed. * * - * Class.class.getProtectionDomain() - * .getCodeSource() - * .getLocation() - * .toURI() - * .getPath() + * Class.class.getProtectionDomain() + * .getCodeSource() + * .getLocation() + * .toURI() + * .getPath() * - * */ public static JarFile getTerraJar() throws IOException { LOGGER.info("Scanning for Terra JAR..."); @@ -52,29 +53,55 @@ public final class AwfulForgeHacks { .equals(ForgeEntryPoint.class.getName().replace('.', '/') + ".class"))) .findFirst() .orElseThrow(() -> new IllegalStateException("Could not find Terra JAR")); - + } public static void loadAllTerraClasses() { try(JarFile jar = getTerraJar()) { jar.stream() - .forEach(jarEntry -> { - if(jarEntry.getName().startsWith("com/dfsek/terra/forge/mixin")) { - return; - } - if(jarEntry.getName().endsWith(".class")) { - String name = jarEntry.getName().replace('/', '.'); - name = name.substring(0, name.length() - 6); - try { - Class.forName(name); - } catch(ClassNotFoundException | NoClassDefFoundError e) { - LOGGER.warn("Failed to load class {}: {}", name, e); - } - } - }); + .forEach(jarEntry -> { + if(jarEntry.getName().startsWith("com/dfsek/terra/forge/mixin")) { + return; + } + if(jarEntry.getName().endsWith(".class")) { + String name = jarEntry.getName().replace('/', '.'); + name = name.substring(0, name.length() - 6); + try { + Class.forName(name); + } catch(ClassNotFoundException | NoClassDefFoundError e) { + LOGGER.warn("Failed to load class {}: {}", name, e); + } + } + }); } catch(IOException e) { throw new IllegalStateException("Could not load all Terra classes", e); } } + + public enum RegistryStep { + BLOCK, + BIOME, + WORLD_TYPE, + DONE; + } + + + public static class RegistrySanityCheck { + private final AtomicReference step = new AtomicReference<>(RegistryStep.BLOCK); + + public void progress(RegistryStep expected, Runnable action) { + step.getAndUpdate(s -> { + if(s != expected) { + LOGGER.error("Registry sanity check failed, expected to find {}, found {}", expected, step); + } + action.run(); + RegistryStep[] registrySteps = RegistryStep.values(); + if(s.ordinal() < registrySteps.length - 1) { + return registrySteps[s.ordinal() + 1]; + } + return s; + }); + } + } } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java index 1f20dd2e3..2e963734f 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java @@ -17,6 +17,9 @@ package com.dfsek.terra.forge; +import com.dfsek.terra.forge.AwfulForgeHacks.RegistrySanityCheck; +import com.dfsek.terra.forge.AwfulForgeHacks.RegistryStep; + import net.minecraft.util.Identifier; import net.minecraft.util.registry.Registry; import net.minecraftforge.eventbus.api.EventPriority; @@ -25,9 +28,7 @@ import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; -import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistries.Keys; import net.minecraftforge.registries.RegisterEvent; import org.slf4j.Logger; @@ -36,9 +37,14 @@ import org.slf4j.LoggerFactory; import com.dfsek.terra.forge.data.Codecs; import com.dfsek.terra.forge.util.LifecycleUtil; +import java.util.concurrent.atomic.AtomicReference; + + @Mod("terra") @EventBusSubscriber(bus = Bus.MOD) public class ForgeEntryPoint { + private final RegistrySanityCheck sanityCheck = new RegistrySanityCheck(); + static { AwfulForgeHacks.loadAllTerraClasses(); TERRA_PLUGIN = new PlatformImpl(); @@ -61,12 +67,12 @@ public class ForgeEntryPoint { @SubscribeEvent(priority = EventPriority.LOWEST) public void registerBiomes(RegisterEvent event) { - event.register(Keys.BIOMES, helper -> { - logger.info("Loading Terra data..."); - LifecycleUtil.initialize(); - }); + event.register(Keys.BLOCKS, helper -> sanityCheck.progress(RegistryStep.BLOCK, () -> logger.debug("Block registration detected."))); + event.register(Keys.BIOMES, helper -> sanityCheck.progress(RegistryStep.BIOME, LifecycleUtil::initialize)); + event.register(Registry.WORLD_PRESET_KEY, helper -> sanityCheck.progress(RegistryStep.WORLD_TYPE, () -> LifecycleUtil.registerWorldTypes(helper))); + + event.register(Registry.CHUNK_GENERATOR_KEY, helper -> helper.register(new Identifier("terra:terra"), Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER)); event.register(Registry.BIOME_SOURCE_KEY, helper -> helper.register(new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE)); - event.register(Keys.BLOCKS, helper -> logger.debug("Block registration detected.")); } } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java index 560a200bc..7ff4b1a1b 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java @@ -21,6 +21,7 @@ import net.minecraft.world.gen.WorldPreset; import net.minecraft.world.gen.chunk.ChunkGenerator; import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; import net.minecraft.world.gen.chunk.NoiseChunkGenerator; +import net.minecraftforge.registries.RegisterEvent.RegisterHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,16 +39,17 @@ public class LifecycleUtil { ForgeEntryPoint.getPlatform().getEventManager().callEvent( new PlatformInitializationEvent()); BiomeUtil.registerBiomes(); - - + } + + public static void registerWorldTypes(RegisterHelper helper) { LOGGER.info("Registering Terra world types..."); - + Registry dimensionTypeRegistry = BuiltinRegistries.DIMENSION_TYPE; Registry chunkGeneratorSettingsRegistry = BuiltinRegistries.CHUNK_GENERATOR_SETTINGS; Registry structureSetRegistry = BuiltinRegistries.STRUCTURE_SET; Registry noiseParametersRegistry = BuiltinRegistries.NOISE_PARAMETERS; Registry biomeRegistry = BuiltinRegistries.BIOME; - + RegistryEntry theNetherDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.THE_NETHER); RegistryEntry netherChunkGeneratorSettings = chunkGeneratorSettingsRegistry.getOrCreateEntry(ChunkGeneratorSettings.NETHER); @@ -64,9 +66,9 @@ public class LifecycleUtil { new NoiseChunkGenerator(structureSetRegistry, noiseParametersRegistry, new TheEndBiomeSource(biomeRegistry), endChunkGeneratorSettings)); - + RegistryEntry overworldDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.OVERWORLD); - + RegistryEntry overworld = chunkGeneratorSettingsRegistry.getOrCreateEntry(ChunkGeneratorSettings.OVERWORLD); ForgeEntryPoint .getPlatform() @@ -74,12 +76,12 @@ public class LifecycleUtil { .forEach((id, pack) -> { Identifier generatorID = Identifier.of("terra", pack.getID().toLowerCase(Locale.ROOT) + "/" + pack.getNamespace().toLowerCase( Locale.ROOT)); - + PRESETS.add(generatorID); - + TerraBiomeSource biomeSource = new TerraBiomeSource(biomeRegistry, pack); ChunkGenerator generator = new FabricChunkGeneratorWrapper(structureSetRegistry, biomeSource, pack, overworld); - + DimensionOptions dimensionOptions = new DimensionOptions(overworldDimensionType, generator); WorldPreset preset = new WorldPreset( Map.of( @@ -88,7 +90,7 @@ public class LifecycleUtil { DimensionOptions.END, endDimensionOptions ) ); - BuiltinRegistries.add(BuiltinRegistries.WORLD_PRESET, generatorID, preset); + helper.register(generatorID, preset); LOGGER.info("Registered world type \"{}\"", generatorID); } ); From 7c2982aa0a2bfed411dc08f8abb5db0edf8fc8b9 Mon Sep 17 00:00:00 2001 From: dfsek Date: Mon, 20 Jun 2022 23:33:14 -0700 Subject: [PATCH 17/38] use registerhelper to register biomes --- .../dfsek/terra/forge/ForgeEntryPoint.java | 2 +- .../com/dfsek/terra/forge/PlatformImpl.java | 2 +- .../com/dfsek/terra/forge/util/BiomeUtil.java | 25 ++++++++----------- .../dfsek/terra/forge/util/LifecycleUtil.java | 4 +-- .../terra/forge/util/ProtoPlatformBiome.java | 6 +++++ 5 files changed, 21 insertions(+), 18 deletions(-) diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java index 2e963734f..2c7da3437 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java @@ -68,7 +68,7 @@ public class ForgeEntryPoint { @SubscribeEvent(priority = EventPriority.LOWEST) public void registerBiomes(RegisterEvent event) { event.register(Keys.BLOCKS, helper -> sanityCheck.progress(RegistryStep.BLOCK, () -> logger.debug("Block registration detected."))); - event.register(Keys.BIOMES, helper -> sanityCheck.progress(RegistryStep.BIOME, LifecycleUtil::initialize)); + event.register(Keys.BIOMES, helper -> sanityCheck.progress(RegistryStep.BIOME, () -> LifecycleUtil.initialize(helper))); event.register(Registry.WORLD_PRESET_KEY, helper -> sanityCheck.progress(RegistryStep.WORLD_TYPE, () -> LifecycleUtil.registerWorldTypes(helper))); diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java index 3e15ce880..0e5c4119e 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java @@ -83,7 +83,7 @@ public class PlatformImpl extends AbstractPlatform { LOGGER.warn("Failed to execute reload", throwable); return null; }).join(); - BiomeUtil.registerBiomes(); + //BiomeUtil.registerBiomes(); server.getWorlds().forEach(world -> { if(world.getChunkManager().getChunkGenerator() instanceof FabricChunkGeneratorWrapper chunkGeneratorWrapper) { getConfigRegistry().get(chunkGeneratorWrapper.getPack().getRegistryKey()).ifPresent(pack -> { diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java index 9e4c1e257..5612372b4 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java @@ -16,6 +16,8 @@ import net.minecraft.world.biome.Biome.Builder; import net.minecraft.world.biome.BiomeEffects; import net.minecraft.world.biome.GenerationSettings; import net.minecraft.world.gen.feature.ConfiguredFeature; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegisterEvent.RegisterHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,11 +39,11 @@ public final class BiomeUtil { .toLowerCase() + "/" + biomeID.getNamespace().toLowerCase(Locale.ROOT) + "/" + biomeID.getID().toLowerCase(Locale.ROOT); } - public static void registerBiomes() { + public static void registerBiomes(RegisterHelper helper) { logger.info("Registering biomes..."); ForgeEntryPoint.getPlatform().getConfigRegistry().forEach(pack -> { // Register all Terra biomes. pack.getCheckedRegistry(Biome.class) - .forEach((id, biome) -> registerBiome(biome, pack, id)); + .forEach((id, biome) -> registerBiome(biome, pack, id, helper)); }); registerFlora(BuiltinRegistries.BIOME); logger.info("Terra biomes registered."); @@ -54,27 +56,22 @@ public final class BiomeUtil { * @param pack The ConfigPack this biome belongs to. */ private static void registerBiome(Biome biome, ConfigPack pack, - com.dfsek.terra.api.registry.key.RegistryKey id) { - Registry registry = BuiltinRegistries.BIOME; - RegistryKey vanilla = ((ProtoPlatformBiome) biome.getPlatformBiome()).get(registry); + com.dfsek.terra.api.registry.key.RegistryKey id, RegisterHelper helper) { + RegistryKey vanilla = ((ProtoPlatformBiome) biome.getPlatformBiome()).get(ForgeRegistries.BIOMES); if(pack.getContext().get(PreLoadCompatibilityOptions.class).useVanillaBiomes()) { ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(vanilla); } else { - net.minecraft.world.biome.Biome minecraftBiome = createBiome(biome, registry.get(vanilla)); + net.minecraft.world.biome.Biome minecraftBiome = createBiome(biome, ForgeRegistries.BIOMES.getDelegateOrThrow(vanilla).value()); Identifier identifier = new Identifier("terra", createBiomeID(pack, id)); - if(registry.containsId(identifier)) { - ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(FabricUtil.getEntry(registry, identifier) - .orElseThrow() - .getKey() - .orElseThrow()); + if(ForgeRegistries.BIOMES.containsKey(identifier)) { + ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(ForgeRegistries.BIOMES.getHolder(identifier).orElseThrow().getKey().orElseThrow()); } else { - ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(BuiltinRegistries.add(registry, - registerKey(identifier).getValue(), - minecraftBiome).getKey().orElseThrow()); + helper.register(registerKey(identifier).getValue(), minecraftBiome); + ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(ForgeRegistries.BIOMES.getHolder(identifier).orElseThrow().getKey().orElseThrow()); } TERRA_BIOME_MAP.computeIfAbsent(vanilla.getValue(), i -> new ArrayList<>()).add(identifier); diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java index 7ff4b1a1b..209d95057 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java @@ -35,10 +35,10 @@ public class LifecycleUtil { private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleUtil.class); private static final List PRESETS = new ArrayList<>(); - public static void initialize() { + public static void initialize(RegisterHelper helper) { ForgeEntryPoint.getPlatform().getEventManager().callEvent( new PlatformInitializationEvent()); - BiomeUtil.registerBiomes(); + BiomeUtil.registerBiomes(helper); } public static void registerWorldTypes(RegisterHelper helper) { diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java index b67932f0b..49fbbb211 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java @@ -26,6 +26,8 @@ import java.util.Objects; import com.dfsek.terra.api.world.biome.PlatformBiome; +import net.minecraftforge.registries.IForgeRegistry; + public class ProtoPlatformBiome implements PlatformBiome { private final Identifier identifier; @@ -40,6 +42,10 @@ public class ProtoPlatformBiome implements PlatformBiome { return FabricUtil.getEntry(registry, identifier).orElseThrow().getKey().orElseThrow(); } + public RegistryKey get(IForgeRegistry registry) { + return registry.getHolder(identifier).orElseThrow().getKey().orElseThrow(); + } + @Override public Object getHandle() { return identifier; From 111eb6b5931cccce0f854c020715866a677f0abf Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 21 Jun 2022 07:22:07 -0700 Subject: [PATCH 18/38] fix NoiseConfigMixin --- .../terra/forge/mixin/lifecycle/NoiseConfigMixin.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java index ca1f00a99..7360045af 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java @@ -2,15 +2,20 @@ package com.dfsek.terra.forge.mixin.lifecycle; import com.dfsek.terra.forge.util.SeedHack; +import net.minecraft.util.math.noise.DoublePerlinNoiseSampler; +import net.minecraft.util.math.noise.DoublePerlinNoiseSampler.NoiseParameters; import net.minecraft.util.math.random.RandomSplitter; +import net.minecraft.util.registry.Registry; import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; import net.minecraft.world.biome.source.util.MultiNoiseUtil.NoiseHypercube; +import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; import net.minecraft.world.gen.densityfunction.DensityFunction; import net.minecraft.world.gen.noise.NoiseConfig; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; 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.Redirect; import java.util.List; @@ -25,13 +30,13 @@ public class NoiseConfigMixin { @Final private long legacyWorldSeed; - @Redirect(method = "(Lnet/minecraft/world/gen/chunk/ChunkGeneratorSettings;Lnet/minecraft/util/registry/Registry;J)V", at = @At(value = "NEW", target = "net/minecraft/world/biome/source/util/MultiNoiseUtil$MultiNoiseSampler.")) + @Redirect(method = "(Lnet/minecraft/world/gen/chunk/ChunkGeneratorSettings;Lnet/minecraft/util/registry/Registry;J)V", at = @At(value = "NEW", target = "(Lnet/minecraft/world/gen/densityfunction/DensityFunction;Lnet/minecraft/world/gen/densityfunction/DensityFunction;Lnet/minecraft/world/gen/densityfunction/DensityFunction;Lnet/minecraft/world/gen/densityfunction/DensityFunction;Lnet/minecraft/world/gen/densityfunction/DensityFunction;Lnet/minecraft/world/gen/densityfunction/DensityFunction;Ljava/util/List;)Lnet/minecraft/world/biome/source/util/MultiNoiseUtil$MultiNoiseSampler;")) private MultiNoiseSampler t(DensityFunction densityFunction, DensityFunction densityFunction2, DensityFunction densityFunction3, DensityFunction densityFunction4, DensityFunction densityFunction5, DensityFunction densityFunction6, List list) { MultiNoiseSampler sampler = new MultiNoiseSampler(densityFunction, densityFunction2, densityFunction3, densityFunction4, densityFunction5, densityFunction6, list); SeedHack.register(sampler, legacyWorldSeed); - return null; + return sampler; } } From 546431bbef8fc8a1280910e266a33186fef9632b Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 21 Jun 2022 09:59:16 -0700 Subject: [PATCH 19/38] clean up adapter --- .../FabricChunkGeneratorWrapper.java | 6 +- .../terra/entity/EntityMixin.java | 4 +- .../dfsek/terra/forge/util/FabricAdapter.java | 185 ------------------ .../dfsek/terra/forge/util/ForgeAdapter.java | 56 ++++++ 4 files changed, 61 insertions(+), 190 deletions(-) delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/util/FabricAdapter.java create mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/util/ForgeAdapter.java diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/FabricChunkGeneratorWrapper.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/FabricChunkGeneratorWrapper.java index e31bb40b2..f58b12deb 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/FabricChunkGeneratorWrapper.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/FabricChunkGeneratorWrapper.java @@ -64,7 +64,7 @@ import com.dfsek.terra.api.world.info.WorldProperties; import com.dfsek.terra.forge.config.PreLoadCompatibilityOptions; import com.dfsek.terra.forge.data.Codecs; import com.dfsek.terra.forge.mixin.access.StructureAccessorAccessor; -import com.dfsek.terra.forge.util.FabricAdapter; +import com.dfsek.terra.forge.util.ForgeAdapter; public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.ChunkGenerator implements GeneratorWrapper { @@ -185,7 +185,7 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C @Override public int getHeight(int x, int z, Type heightmap, HeightLimitView height, NoiseConfig noiseConfig) { - WorldProperties properties = FabricAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); + WorldProperties properties = ForgeAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); BiomeProvider biomeProvider = pack.getBiomeProvider(); int min = height.getBottomY(); for(int y = height.getTopY() - 1; y >= min; y--) { @@ -199,7 +199,7 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C @Override public VerticalBlockSample getColumnSample(int x, int z, HeightLimitView height, NoiseConfig noiseConfig) { BlockState[] array = new BlockState[height.getHeight()]; - WorldProperties properties = FabricAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); + WorldProperties properties = ForgeAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); BiomeProvider biomeProvider = pack.getBiomeProvider(); for(int y = height.getTopY() - 1; y >= height.getBottomY(); y--) { array[y - height.getBottomY()] = (BlockState) delegate.getBlock(properties, x, y, z, biomeProvider); diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityMixin.java index 96e7be2d5..a300693b7 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityMixin.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityMixin.java @@ -17,7 +17,7 @@ package com.dfsek.terra.forge.mixin.implementations.terra.entity; -import com.dfsek.terra.forge.util.FabricAdapter; +import com.dfsek.terra.forge.util.ForgeAdapter; import net.minecraft.entity.Entity; import net.minecraft.util.math.BlockPos; import org.spongepowered.asm.mixin.Implements; @@ -42,7 +42,7 @@ public abstract class EntityMixin { public abstract void teleport(double destX, double destY, double destZ); public Vector3 terra$position() { - return FabricAdapter.adapt(blockPos); + return ForgeAdapter.adapt(blockPos); } public void terra$position(Vector3 location) { diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/FabricAdapter.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/FabricAdapter.java deleted file mode 100644 index b7bc9f010..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/FabricAdapter.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.forge.util; - -import net.minecraft.block.enums.BlockHalf; -import net.minecraft.block.enums.WallShape; -import net.minecraft.block.enums.WireConnection; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.HeightLimitView; - -import com.dfsek.terra.api.block.state.properties.enums.Axis; -import com.dfsek.terra.api.block.state.properties.enums.Half; -import com.dfsek.terra.api.block.state.properties.enums.RailShape; -import com.dfsek.terra.api.block.state.properties.enums.RedstoneConnection; -import com.dfsek.terra.api.block.state.properties.enums.WallHeight; -import com.dfsek.terra.api.util.vector.Vector3; -import com.dfsek.terra.api.world.info.WorldProperties; - - -public final class FabricAdapter { - public static BlockPos adapt(Vector3 v) { - return new BlockPos(v.getBlockX(), v.getBlockY(), v.getBlockZ()); - } - - public static Vector3 adapt(BlockPos pos) { - return Vector3.of(pos.getX(), pos.getY(), pos.getZ()); - } - - public static Direction adapt(com.dfsek.terra.api.block.state.properties.enums.Direction direction) { - return switch(direction) { - case SOUTH -> Direction.SOUTH; - case NORTH -> Direction.NORTH; - case WEST -> Direction.WEST; - case EAST -> Direction.EAST; - case UP -> Direction.UP; - case DOWN -> Direction.DOWN; - }; - } - - public static WorldProperties adapt(HeightLimitView height, long seed) { - return new WorldProperties() { - @Override - public long getSeed() { - return seed; - } - - @Override - public int getMaxHeight() { - return height.getTopY(); - } - - @Override - public int getMinHeight() { - return height.getBottomY(); - } - - @Override - public Object getHandle() { - return height; - } - }; - } - - public static com.dfsek.terra.api.block.state.properties.enums.Direction adapt(Direction direction) { - return switch(direction) { - case SOUTH -> com.dfsek.terra.api.block.state.properties.enums.Direction.SOUTH; - case NORTH -> com.dfsek.terra.api.block.state.properties.enums.Direction.NORTH; - case WEST -> com.dfsek.terra.api.block.state.properties.enums.Direction.WEST; - case EAST -> com.dfsek.terra.api.block.state.properties.enums.Direction.EAST; - case UP -> com.dfsek.terra.api.block.state.properties.enums.Direction.UP; - case DOWN -> com.dfsek.terra.api.block.state.properties.enums.Direction.DOWN; - }; - } - - public static WallHeight adapt(WallShape shape) { - return switch(shape) { - case LOW -> WallHeight.LOW; - case NONE -> WallHeight.NONE; - case TALL -> WallHeight.TALL; - }; - } - - public static WallShape adapt(WallHeight shape) { - return switch(shape) { - case LOW -> WallShape.LOW; - case NONE -> WallShape.NONE; - case TALL -> WallShape.TALL; - }; - } - - public static RedstoneConnection adapt(WireConnection connection) { - return switch(connection) { - case NONE -> RedstoneConnection.NONE; - case UP -> RedstoneConnection.UP; - case SIDE -> RedstoneConnection.SIDE; - }; - } - - public static WireConnection adapt(RedstoneConnection connection) { - return switch(connection) { - case NONE -> WireConnection.NONE; - case UP -> WireConnection.UP; - case SIDE -> WireConnection.SIDE; - }; - } - - - public static Half adapt(BlockHalf half) { - return switch(half) { - case BOTTOM -> Half.BOTTOM; - case TOP -> Half.TOP; - }; - } - - public static BlockHalf adapt(Half half) { - return switch(half) { - case TOP -> BlockHalf.TOP; - case BOTTOM -> BlockHalf.BOTTOM; - default -> throw new IllegalStateException(); - }; - } - - public static RailShape adapt(net.minecraft.block.enums.RailShape railShape) { - return switch(railShape) { - case EAST_WEST -> RailShape.EAST_WEST; - case NORTH_EAST -> RailShape.NORTH_EAST; - case NORTH_WEST -> RailShape.NORTH_WEST; - case SOUTH_EAST -> RailShape.SOUTH_EAST; - case SOUTH_WEST -> RailShape.SOUTH_WEST; - case NORTH_SOUTH -> RailShape.NORTH_SOUTH; - case ASCENDING_EAST -> RailShape.ASCENDING_EAST; - case ASCENDING_NORTH -> RailShape.ASCENDING_NORTH; - case ASCENDING_SOUTH -> RailShape.ASCENDING_SOUTH; - case ASCENDING_WEST -> RailShape.ASCENDING_WEST; - }; - } - - public static net.minecraft.block.enums.RailShape adapt(RailShape railShape) { - return switch(railShape) { - case EAST_WEST -> net.minecraft.block.enums.RailShape.EAST_WEST; - case NORTH_EAST -> net.minecraft.block.enums.RailShape.NORTH_EAST; - case NORTH_WEST -> net.minecraft.block.enums.RailShape.NORTH_WEST; - case SOUTH_EAST -> net.minecraft.block.enums.RailShape.SOUTH_EAST; - case SOUTH_WEST -> net.minecraft.block.enums.RailShape.SOUTH_WEST; - case NORTH_SOUTH -> net.minecraft.block.enums.RailShape.NORTH_SOUTH; - case ASCENDING_EAST -> net.minecraft.block.enums.RailShape.ASCENDING_EAST; - case ASCENDING_NORTH -> net.minecraft.block.enums.RailShape.ASCENDING_NORTH; - case ASCENDING_SOUTH -> net.minecraft.block.enums.RailShape.ASCENDING_SOUTH; - case ASCENDING_WEST -> net.minecraft.block.enums.RailShape.ASCENDING_WEST; - }; - } - - - public static Axis adapt(Direction.Axis axis) { - return switch(axis) { - case X -> Axis.X; - case Y -> Axis.Y; - case Z -> Axis.Z; - }; - } - - public static Direction.Axis adapt(Axis axis) { - return switch(axis) { - case Z -> Direction.Axis.Z; - case Y -> Direction.Axis.Y; - case X -> Direction.Axis.X; - }; - } -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ForgeAdapter.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ForgeAdapter.java new file mode 100644 index 000000000..469b80349 --- /dev/null +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ForgeAdapter.java @@ -0,0 +1,56 @@ +/* + * This file is part of Terra. + * + * Terra 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 + * (at your option) any later version. + * + * Terra 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 Terra. If not, see . + */ + +package com.dfsek.terra.forge.util; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.HeightLimitView; + +import com.dfsek.terra.api.util.vector.Vector3; +import com.dfsek.terra.api.world.info.WorldProperties; + + +public final class ForgeAdapter { + + public static Vector3 adapt(BlockPos pos) { + return Vector3.of(pos.getX(), pos.getY(), pos.getZ()); + } + + public static WorldProperties adapt(HeightLimitView height, long seed) { + return new WorldProperties() { + @Override + public long getSeed() { + return seed; + } + + @Override + public int getMaxHeight() { + return height.getTopY(); + } + + @Override + public int getMinHeight() { + return height.getBottomY(); + } + + @Override + public Object getHandle() { + return height; + } + }; + } +} From 0c02e4cb9a32ee4d79ef7cd614ca4666f2342e40 Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 21 Jun 2022 09:59:54 -0700 Subject: [PATCH 20/38] rename architectury implementation util class --- .../mixin/implementations/terra/world/ChunkRegionMixin.java | 4 ++-- .../mixin/implementations/terra/world/ServerWorldMixin.java | 4 ++-- .../terra/forge/util/{FabricUtil.java => ForgeUtil.java} | 6 ++---- .../java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java | 2 +- .../src/main/java/com/dfsek/terra/forge/util/TagUtil.java | 6 +++--- 5 files changed, 10 insertions(+), 12 deletions(-) rename platforms/forge/src/main/java/com/dfsek/terra/forge/util/{FabricUtil.java => ForgeUtil.java} (94%) diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ChunkRegionMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ChunkRegionMixin.java index 6ba8768ab..d766b82e2 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ChunkRegionMixin.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ChunkRegionMixin.java @@ -48,7 +48,7 @@ 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.forge.util.FabricUtil; +import com.dfsek.terra.forge.util.ForgeUtil; @Mixin(ChunkRegion.class) @@ -109,7 +109,7 @@ public abstract class ChunkRegionMixin { } public BlockEntity terraWorld$getBlockEntity(int x, int y, int z) { - return FabricUtil.createState((WorldAccess) this, new BlockPos(x, y, z)); + return ForgeUtil.createState((WorldAccess) this, new BlockPos(x, y, z)); } public int terraWorld$getMinHeight() { diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ServerWorldMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ServerWorldMixin.java index fc9158d4c..bec9c2f36 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ServerWorldMixin.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ServerWorldMixin.java @@ -35,7 +35,7 @@ import com.dfsek.terra.api.world.ServerWorld; import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.chunk.Chunk; import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator; -import com.dfsek.terra.forge.util.FabricUtil; +import com.dfsek.terra.forge.util.ForgeUtil; @Mixin(net.minecraft.server.world.ServerWorld.class) @@ -73,7 +73,7 @@ public abstract class ServerWorldMixin { } public BlockEntity terra$getBlockEntity(int x, int y, int z) { - return FabricUtil.createState((WorldAccess) this, new BlockPos(x, y, z)); + return ForgeUtil.createState((WorldAccess) this, new BlockPos(x, y, z)); } public int terra$getMinHeight() { diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/FabricUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ForgeUtil.java similarity index 94% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/util/FabricUtil.java rename to platforms/forge/src/main/java/com/dfsek/terra/forge/util/ForgeUtil.java index 8f854186f..cb577de6f 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/FabricUtil.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ForgeUtil.java @@ -25,8 +25,6 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.RegistryEntry; import net.minecraft.world.WorldAccess; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.util.Optional; @@ -36,8 +34,8 @@ import com.dfsek.terra.api.block.entity.MobSpawner; import com.dfsek.terra.api.block.entity.Sign; -public final class FabricUtil { - private FabricUtil() { +public final class ForgeUtil { + private ForgeUtil() { } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java index 49fbbb211..e06ebf0f8 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java @@ -39,7 +39,7 @@ public class ProtoPlatformBiome implements PlatformBiome { } public RegistryKey get(Registry registry) { - return FabricUtil.getEntry(registry, identifier).orElseThrow().getKey().orElseThrow(); + return ForgeUtil.getEntry(registry, identifier).orElseThrow().getKey().orElseThrow(); } public RegistryKey get(IForgeRegistry registry) { diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java index 27b33a210..4486aad0b 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java @@ -38,7 +38,7 @@ public final class TagUtil { LifecycleUtil .getPresets() - .forEach(id -> FabricUtil + .forEach(id -> ForgeUtil .getEntry(registry, id) .ifPresentOrElse( preset -> collect @@ -57,11 +57,11 @@ public final class TagUtil { BiomeUtil .getTerraBiomeMap() .forEach((vb, terraBiomes) -> - FabricUtil + ForgeUtil .getEntry(registry, vb) .ifPresentOrElse( vanilla -> terraBiomes - .forEach(tb -> FabricUtil + .forEach(tb -> ForgeUtil .getEntry(registry, tb) .ifPresentOrElse( terra -> { From aeb2da4ede8ad21e1377c94bc534806f37e2ab56 Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 21 Jun 2022 10:25:23 -0700 Subject: [PATCH 21/38] refactor chunk generator wrapper name --- .../java/com/dfsek/terra/forge/PlatformImpl.java | 7 ++----- .../java/com/dfsek/terra/forge/data/Codecs.java | 14 +++++++------- ...rapper.java => ForgeChunkGeneratorWrapper.java} | 8 ++++---- .../forge/mixin/fix/NetherFossilOptimization.java | 4 ++-- .../terra/world/ChunkRegionMixin.java | 4 ++-- .../terra/world/ServerWorldMixin.java | 10 +++++----- .../com/dfsek/terra/forge/util/LifecycleUtil.java | 4 ++-- 7 files changed, 24 insertions(+), 27 deletions(-) rename platforms/forge/src/main/java/com/dfsek/terra/forge/generation/{FabricChunkGeneratorWrapper.java => ForgeChunkGeneratorWrapper.java} (96%) diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java index 0e5c4119e..ca0d34af8 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java @@ -29,9 +29,7 @@ import net.minecraft.util.Identifier; import net.minecraft.util.registry.BuiltinRegistries; import net.minecraft.world.biome.Biome.Precipitation; import net.minecraft.world.biome.BiomeEffects.GrassColorModifier; -import net.minecraftforge.common.ForgeConfig.Common; import net.minecraftforge.fml.loading.FMLLoader; -import net.minecraftforge.fml.loading.targets.FMLServerLaunchHandler; import net.minecraftforge.server.ServerLifecycleHooks; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; @@ -49,10 +47,9 @@ import com.dfsek.terra.api.handle.ItemHandle; import com.dfsek.terra.api.handle.WorldHandle; import com.dfsek.terra.api.util.generic.Lazy; import com.dfsek.terra.api.world.biome.PlatformBiome; -import com.dfsek.terra.forge.generation.FabricChunkGeneratorWrapper; +import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper; import com.dfsek.terra.forge.handle.FabricItemHandle; import com.dfsek.terra.forge.handle.FabricWorldHandle; -import com.dfsek.terra.forge.util.BiomeUtil; import com.dfsek.terra.forge.util.ProtoPlatformBiome; @@ -85,7 +82,7 @@ public class PlatformImpl extends AbstractPlatform { }).join(); //BiomeUtil.registerBiomes(); server.getWorlds().forEach(world -> { - if(world.getChunkManager().getChunkGenerator() instanceof FabricChunkGeneratorWrapper chunkGeneratorWrapper) { + if(world.getChunkManager().getChunkGenerator() instanceof ForgeChunkGeneratorWrapper chunkGeneratorWrapper) { getConfigRegistry().get(chunkGeneratorWrapper.getPack().getRegistryKey()).ifPresent(pack -> { chunkGeneratorWrapper.setPack(pack); LOGGER.info("Replaced pack in chunk generator for world {}", world); diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/data/Codecs.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/data/Codecs.java index 95bf25e1a..d93e176e7 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/data/Codecs.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/data/Codecs.java @@ -3,7 +3,7 @@ package com.dfsek.terra.forge.data; import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.registry.key.RegistryKey; import com.dfsek.terra.forge.ForgeEntryPoint; -import com.dfsek.terra.forge.generation.FabricChunkGeneratorWrapper; +import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper; import com.dfsek.terra.forge.generation.TerraBiomeSource; import com.mojang.serialization.Codec; @@ -44,22 +44,22 @@ public final class Codecs { .forGetter(TerraBiomeSource::getPack)) .apply(instance, instance.stable(TerraBiomeSource::new))); - public static final Codec FABRIC_CHUNK_GENERATOR_WRAPPER = RecordCodecBuilder + public static final Codec FABRIC_CHUNK_GENERATOR_WRAPPER = RecordCodecBuilder .create( instance -> instance.group( RegistryOps.createRegistryCodec(Registry.STRUCTURE_SET_KEY) .fieldOf("structure_registry") .stable() - .forGetter(FabricChunkGeneratorWrapper::getNoiseRegistry), + .forGetter(ForgeChunkGeneratorWrapper::getNoiseRegistry), TERRA_BIOME_SOURCE.fieldOf("biome_source") .stable() - .forGetter(FabricChunkGeneratorWrapper::getBiomeSource), + .forGetter(ForgeChunkGeneratorWrapper::getBiomeSource), CONFIG_PACK.fieldOf("pack") .stable() - .forGetter(FabricChunkGeneratorWrapper::getPack), + .forGetter(ForgeChunkGeneratorWrapper::getPack), ChunkGeneratorSettings.REGISTRY_CODEC.fieldOf("settings") .stable() - .forGetter(FabricChunkGeneratorWrapper::getSettings) - ).apply(instance, instance.stable(FabricChunkGeneratorWrapper::new)) + .forGetter(ForgeChunkGeneratorWrapper::getSettings) + ).apply(instance, instance.stable(ForgeChunkGeneratorWrapper::new)) ); } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/FabricChunkGeneratorWrapper.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/ForgeChunkGeneratorWrapper.java similarity index 96% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/generation/FabricChunkGeneratorWrapper.java rename to platforms/forge/src/main/java/com/dfsek/terra/forge/generation/ForgeChunkGeneratorWrapper.java index f58b12deb..c38547524 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/FabricChunkGeneratorWrapper.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/ForgeChunkGeneratorWrapper.java @@ -67,8 +67,8 @@ import com.dfsek.terra.forge.mixin.access.StructureAccessorAccessor; import com.dfsek.terra.forge.util.ForgeAdapter; -public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.ChunkGenerator implements GeneratorWrapper { - private static final Logger logger = LoggerFactory.getLogger(FabricChunkGeneratorWrapper.class); +public class ForgeChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.ChunkGenerator implements GeneratorWrapper { + private static final Logger logger = LoggerFactory.getLogger(ForgeChunkGeneratorWrapper.class); private final TerraBiomeSource biomeSource; private final Registry noiseRegistry; @@ -76,8 +76,8 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C private ChunkGenerator delegate; private ConfigPack pack; - public FabricChunkGeneratorWrapper(Registry noiseRegistry, TerraBiomeSource biomeSource, ConfigPack configPack, - RegistryEntry settingsSupplier) { + public ForgeChunkGeneratorWrapper(Registry noiseRegistry, TerraBiomeSource biomeSource, ConfigPack configPack, + RegistryEntry settingsSupplier) { super(noiseRegistry, Optional.empty(), biomeSource); this.noiseRegistry = noiseRegistry; this.pack = configPack; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/NetherFossilOptimization.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/NetherFossilOptimization.java index c8def7e88..297d1acfc 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/NetherFossilOptimization.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/NetherFossilOptimization.java @@ -1,6 +1,6 @@ package com.dfsek.terra.forge.mixin.fix; -import com.dfsek.terra.forge.generation.FabricChunkGeneratorWrapper; +import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper; import net.minecraft.world.gen.structure.NetherFossilStructure; import net.minecraft.world.gen.structure.Structure.Context; @@ -22,7 +22,7 @@ import java.util.Optional; public class NetherFossilOptimization { @Inject(method = "getStructurePosition", at = @At("HEAD"), cancellable = true) public void injectFossilPositions(Context context, CallbackInfoReturnable> cir) { - if(context.chunkGenerator() instanceof FabricChunkGeneratorWrapper) { + if(context.chunkGenerator() instanceof ForgeChunkGeneratorWrapper) { cir.setReturnValue(Optional.empty()); } } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ChunkRegionMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ChunkRegionMixin.java index d766b82e2..22f3733a0 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ChunkRegionMixin.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ChunkRegionMixin.java @@ -17,7 +17,7 @@ package com.dfsek.terra.forge.mixin.implementations.terra.world; -import com.dfsek.terra.forge.generation.FabricChunkGeneratorWrapper; +import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper; import net.minecraft.block.FluidBlock; import net.minecraft.fluid.Fluid; import net.minecraft.util.math.BlockPos; @@ -117,7 +117,7 @@ public abstract class ChunkRegionMixin { } public ChunkGenerator terraWorld$getGenerator() { - return ((FabricChunkGeneratorWrapper) world.getChunkManager().getChunkGenerator()).getHandle(); + return ((ForgeChunkGeneratorWrapper) world.getChunkManager().getChunkGenerator()).getHandle(); } public BiomeProvider terraWorld$getBiomeProvider() { diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ServerWorldMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ServerWorldMixin.java index bec9c2f36..698d49bfe 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ServerWorldMixin.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ServerWorldMixin.java @@ -17,7 +17,7 @@ package com.dfsek.terra.forge.mixin.implementations.terra.world; -import com.dfsek.terra.forge.generation.FabricChunkGeneratorWrapper; +import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper; import com.dfsek.terra.forge.generation.TerraBiomeSource; import net.minecraft.util.math.BlockPos; import net.minecraft.world.WorldAccess; @@ -81,8 +81,8 @@ public abstract class ServerWorldMixin { } public ChunkGenerator terra$getGenerator() { - return ((FabricChunkGeneratorWrapper) ((net.minecraft.server.world.ServerWorld) (Object) this).getChunkManager() - .getChunkGenerator()).getHandle(); + return ((ForgeChunkGeneratorWrapper) ((net.minecraft.server.world.ServerWorld) (Object) this).getChunkManager() + .getChunkGenerator()).getHandle(); } public BiomeProvider terra$getBiomeProvider() { @@ -94,8 +94,8 @@ public abstract class ServerWorldMixin { public ConfigPack terra$getPack() { net.minecraft.world.gen.chunk.ChunkGenerator generator = (((net.minecraft.server.world.ServerWorld) (Object) this).getChunkManager()).getChunkGenerator(); - if(generator instanceof FabricChunkGeneratorWrapper fabricChunkGeneratorWrapper) { - return fabricChunkGeneratorWrapper.getPack(); + if(generator instanceof ForgeChunkGeneratorWrapper forgeChunkGeneratorWrapper) { + return forgeChunkGeneratorWrapper.getPack(); } return null; } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java index 209d95057..ac0efc605 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java @@ -2,7 +2,7 @@ package com.dfsek.terra.forge.util; import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; import com.dfsek.terra.forge.ForgeEntryPoint; -import com.dfsek.terra.forge.generation.FabricChunkGeneratorWrapper; +import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper; import com.dfsek.terra.forge.generation.TerraBiomeSource; import net.minecraft.structure.StructureSet; @@ -80,7 +80,7 @@ public class LifecycleUtil { PRESETS.add(generatorID); TerraBiomeSource biomeSource = new TerraBiomeSource(biomeRegistry, pack); - ChunkGenerator generator = new FabricChunkGeneratorWrapper(structureSetRegistry, biomeSource, pack, overworld); + ChunkGenerator generator = new ForgeChunkGeneratorWrapper(structureSetRegistry, biomeSource, pack, overworld); DimensionOptions dimensionOptions = new DimensionOptions(overworldDimensionType, generator); WorldPreset preset = new WorldPreset( From e2bb2d8712f76d14445b97a8b2758977581b0903 Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 21 Jun 2022 10:25:52 -0700 Subject: [PATCH 22/38] refactor handles --- .../src/main/java/com/dfsek/terra/forge/PlatformImpl.java | 8 ++++---- .../{FabricItemHandle.java => ForgeItemHandle.java} | 2 +- .../{FabricWorldHandle.java => ForgeWorldHandle.java} | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) rename platforms/forge/src/main/java/com/dfsek/terra/forge/handle/{FabricItemHandle.java => ForgeItemHandle.java} (97%) rename platforms/forge/src/main/java/com/dfsek/terra/forge/handle/{FabricWorldHandle.java => ForgeWorldHandle.java} (97%) diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java index ca0d34af8..53f42ee5a 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java @@ -48,15 +48,15 @@ import com.dfsek.terra.api.handle.WorldHandle; import com.dfsek.terra.api.util.generic.Lazy; import com.dfsek.terra.api.world.biome.PlatformBiome; import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper; -import com.dfsek.terra.forge.handle.FabricItemHandle; -import com.dfsek.terra.forge.handle.FabricWorldHandle; +import com.dfsek.terra.forge.handle.ForgeItemHandle; +import com.dfsek.terra.forge.handle.ForgeWorldHandle; import com.dfsek.terra.forge.util.ProtoPlatformBiome; public class PlatformImpl extends AbstractPlatform { private static final Logger LOGGER = LoggerFactory.getLogger(PlatformImpl.class); - private final ItemHandle itemHandle = new FabricItemHandle(); - private final WorldHandle worldHandle = new FabricWorldHandle(); + private final ItemHandle itemHandle = new ForgeItemHandle(); + private final WorldHandle worldHandle = new ForgeWorldHandle(); private final Lazy dataFolder = Lazy.lazy(() -> new File("./config/Terra")); public PlatformImpl() { diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/FabricItemHandle.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/ForgeItemHandle.java similarity index 97% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/handle/FabricItemHandle.java rename to platforms/forge/src/main/java/com/dfsek/terra/forge/handle/ForgeItemHandle.java index cc7b0d1a6..b68ad4478 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/FabricItemHandle.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/ForgeItemHandle.java @@ -34,7 +34,7 @@ import com.dfsek.terra.api.inventory.Item; import com.dfsek.terra.api.inventory.item.Enchantment; -public class FabricItemHandle implements ItemHandle { +public class ForgeItemHandle implements ItemHandle { @Override public Item createItem(String data) { diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/FabricWorldHandle.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/ForgeWorldHandle.java similarity index 97% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/handle/FabricWorldHandle.java rename to platforms/forge/src/main/java/com/dfsek/terra/forge/handle/ForgeWorldHandle.java index dd47858b8..b139af0e8 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/FabricWorldHandle.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/ForgeWorldHandle.java @@ -30,7 +30,7 @@ import com.dfsek.terra.api.entity.EntityType; import com.dfsek.terra.api.handle.WorldHandle; -public class FabricWorldHandle implements WorldHandle { +public class ForgeWorldHandle implements WorldHandle { private static final BlockState AIR = (BlockState) Blocks.AIR.getDefaultState(); From 752f57bbeaf9797064c56fc7d8ee1eb2d66738ab Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 21 Jun 2022 10:26:20 -0700 Subject: [PATCH 23/38] fix addon ID --- .../forge/src/main/java/com/dfsek/terra/forge/ForgeAddon.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeAddon.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeAddon.java index 320c03fe2..499ae6533 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeAddon.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeAddon.java @@ -75,6 +75,6 @@ public final class ForgeAddon implements BaseAddon { @Override public String getID() { - return "terra-fabric"; + return "terra-forge"; } } From 32b2f15f3b3cab36b324bf2a2a166f0a9da6a8ca Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 21 Jun 2022 10:26:58 -0700 Subject: [PATCH 24/38] fix chunk generator codec name --- .../src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java | 4 +--- .../src/main/java/com/dfsek/terra/forge/data/Codecs.java | 2 +- .../terra/forge/generation/ForgeChunkGeneratorWrapper.java | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java index 2c7da3437..e8f701fd0 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java @@ -37,8 +37,6 @@ import org.slf4j.LoggerFactory; import com.dfsek.terra.forge.data.Codecs; import com.dfsek.terra.forge.util.LifecycleUtil; -import java.util.concurrent.atomic.AtomicReference; - @Mod("terra") @EventBusSubscriber(bus = Bus.MOD) @@ -72,7 +70,7 @@ public class ForgeEntryPoint { event.register(Registry.WORLD_PRESET_KEY, helper -> sanityCheck.progress(RegistryStep.WORLD_TYPE, () -> LifecycleUtil.registerWorldTypes(helper))); - event.register(Registry.CHUNK_GENERATOR_KEY, helper -> helper.register(new Identifier("terra:terra"), Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER)); + event.register(Registry.CHUNK_GENERATOR_KEY, helper -> helper.register(new Identifier("terra:terra"), Codecs.FORGE_CHUNK_GENERATOR_WRAPPER)); event.register(Registry.BIOME_SOURCE_KEY, helper -> helper.register(new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE)); } } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/data/Codecs.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/data/Codecs.java index d93e176e7..f30006e12 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/data/Codecs.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/data/Codecs.java @@ -44,7 +44,7 @@ public final class Codecs { .forGetter(TerraBiomeSource::getPack)) .apply(instance, instance.stable(TerraBiomeSource::new))); - public static final Codec FABRIC_CHUNK_GENERATOR_WRAPPER = RecordCodecBuilder + public static final Codec FORGE_CHUNK_GENERATOR_WRAPPER = RecordCodecBuilder .create( instance -> instance.group( RegistryOps.createRegistryCodec(Registry.STRUCTURE_SET_KEY) diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/ForgeChunkGeneratorWrapper.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/ForgeChunkGeneratorWrapper.java index c38547524..ce649eba0 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/ForgeChunkGeneratorWrapper.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/ForgeChunkGeneratorWrapper.java @@ -94,7 +94,7 @@ public class ForgeChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.Ch @Override protected Codec getCodec() { - return Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER; + return Codecs.FORGE_CHUNK_GENERATOR_WRAPPER; } @Override From 37c358e3d1fba86321675be72191e78e2fdfb388 Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 21 Jun 2022 11:12:35 -0700 Subject: [PATCH 25/38] rename all platform references --- .../src/main/java/com/dfsek/terra/forge/PlatformImpl.java | 2 +- .../terra/forge/config/PreLoadCompatibilityOptions.java | 8 ++++---- .../terra/forge/mixin/fix/NetherFossilOptimization.java | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java index 53f42ee5a..6426c5685 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java @@ -122,7 +122,7 @@ public class PlatformImpl extends AbstractPlatform { @Override public @NotNull String platformName() { - return "Fabric"; + return "Forge"; } @Override diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/config/PreLoadCompatibilityOptions.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/config/PreLoadCompatibilityOptions.java index bf7c3b7bc..1b8acf3ae 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/config/PreLoadCompatibilityOptions.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/config/PreLoadCompatibilityOptions.java @@ -26,19 +26,19 @@ import com.dfsek.terra.api.properties.Properties; @SuppressWarnings("FieldMayBeFinal") public class PreLoadCompatibilityOptions implements ConfigTemplate, Properties { - @Value("fabric.use-vanilla-biomes") + @Value("forge.use-vanilla-biomes") @Default private boolean vanillaBiomes = false; - @Value("fabric.beard.enable") + @Value("forge.beard.enable") @Default private boolean beard = true; - @Value("fabric.beard.threshold") + @Value("forge.beard.threshold") @Default private double beardThreshold = 0.5; - @Value("fabric.beard.air-threshold") + @Value("forge.beard.air-threshold") @Default private double airThreshold = -0.5; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/NetherFossilOptimization.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/NetherFossilOptimization.java index 297d1acfc..d72e59761 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/NetherFossilOptimization.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/NetherFossilOptimization.java @@ -16,7 +16,7 @@ import java.util.Optional; /** * Disable fossil generation in Terra worlds, as they are very expensive due to consistently triggering cache misses. * - * Currently, on Fabric, Terra cannot be specified as a Nether generator. TODO: logic to turn fossils back on if chunk generator is in nether. + * Currently, on Forge, Terra cannot be specified as a Nether generator. TODO: logic to turn fossils back on if chunk generator is in nether. */ @Mixin(NetherFossilStructure.class) public class NetherFossilOptimization { From e1cbb29ae43d9e5e3b595b0c0aa8902c6bb43bcd Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 21 Jun 2022 14:46:50 -0700 Subject: [PATCH 26/38] begin splitting mixins into common --- buildSrc/src/main/kotlin/Versions.kt | 9 +++++++++ platforms/fabric/build.gradle.kts | 15 +++++++++++++-- .../FabricChunkGeneratorWrapper.java | 3 ++- .../mixin/access/ChunkRegionAccessor.java | 15 --------------- .../entity/MobSpawnerBlockEntityMixin.java | 3 ++- .../terra/block/state/BlockStateMixin.java | 3 ++- .../main/resources/terra.fabric.mixins.json | 6 +----- platforms/forge/build.gradle.kts | 2 +- .../main/resources/terra.forge.mixins.json | 2 +- platforms/mod-common/README.md | 4 ++++ platforms/mod-common/build.gradle.kts | 18 ++++++++++++++++++ .../mixin/access/MobSpawnerLogicAccessor.java | 2 +- .../mod}/mixin/access/StateAccessor.java | 2 +- .../access/StructureAccessorAccessor.java | 2 +- .../src/main/resources/fabric.mod.json | 8 ++++++++ .../main/resources/terra.common.mixins.json | 19 +++++++++++++++++++ 16 files changed, 83 insertions(+), 30 deletions(-) delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/ChunkRegionAccessor.java create mode 100644 platforms/mod-common/README.md create mode 100644 platforms/mod-common/build.gradle.kts rename platforms/{fabric/src/main/java/com/dfsek/terra/fabric => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/access/MobSpawnerLogicAccessor.java (95%) rename platforms/{fabric/src/main/java/com/dfsek/terra/fabric => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/access/StateAccessor.java (96%) rename platforms/{fabric/src/main/java/com/dfsek/terra/fabric => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/access/StructureAccessorAccessor.java (95%) create mode 100644 platforms/mod-common/src/main/resources/fabric.mod.json create mode 100644 platforms/mod-common/src/main/resources/terra.common.mixins.json diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 42a262e15..f0b5efc0f 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -28,6 +28,15 @@ object Versions { const val minotaur = "1.1.0" } + object Mod { + const val minecraft = "1.19" + const val yarn = "$minecraft+build.1" + const val fabricLoader = "0.14.2" + + const val architecuryLoom = "0.12.0-SNAPSHOT" + const val architectutyPlugin = "3.4-SNAPSHOT" + } + object Forge { const val minecraft = "1.19" const val forge = "$minecraft-41.0.38" diff --git a/platforms/fabric/build.gradle.kts b/platforms/fabric/build.gradle.kts index 401cea107..b8a3b4562 100644 --- a/platforms/fabric/build.gradle.kts +++ b/platforms/fabric/build.gradle.kts @@ -1,8 +1,16 @@ plugins { - id("fabric-loom") version Versions.Fabric.loom + id("dev.architectury.loom") version Versions.Mod.architecuryLoom + id("architectury-plugin") version Versions.Mod.architectutyPlugin id("io.github.juuxel.loom-quiltflower") version Versions.Fabric.loomQuiltflower } +configurations { + val common by creating + create("shadowCommon") + compileClasspath.get().extendsFrom(common) + runtimeClasspath.get().extendsFrom(common) +} + dependencies { shadedApi(project(":common:implementation:base")) @@ -10,6 +18,9 @@ dependencies { "annotationProcessor"("net.fabricmc:sponge-mixin:${Versions.Fabric.mixin}") "annotationProcessor"("net.fabricmc:fabric-loom:${Versions.Fabric.loom}") + "common"(project(path = ":platforms:mod-common", configuration = "namedElements")) { isTransitive = false } + "shadowCommon"(project(path = ":platforms:mod-common", configuration = "transformProductionFabric")) { isTransitive = false } + minecraft("com.mojang:minecraft:${Versions.Fabric.minecraft}") mappings("net.fabricmc:yarn:${Versions.Fabric.yarn}:v2") @@ -28,7 +39,7 @@ dependencies { loom { accessWidenerPath.set(file("src/main/resources/terra.accesswidener")) mixin { - defaultRefmapName.set("terra-refmap.json") + defaultRefmapName.set("terra-fabric-refmap.json") } } 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 04e87e4bc..8ae3c3afe 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 @@ -17,6 +17,8 @@ package com.dfsek.terra.fabric.generation; +import com.dfsek.terra.mod.mixin.access.StructureAccessorAccessor; + import com.mojang.serialization.Codec; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; @@ -63,7 +65,6 @@ 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.mixin.access.StructureAccessorAccessor; import com.dfsek.terra.fabric.util.FabricAdapter; 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 deleted file mode 100644 index 2c471cf0e..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/ChunkRegionAccessor.java +++ /dev/null @@ -1,15 +0,0 @@ -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/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java index 07fdd9630..0bb1b6120 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java @@ -17,6 +17,8 @@ package com.dfsek.terra.fabric.mixin.implementations.terra.block.entity; +import com.dfsek.terra.mod.mixin.access.MobSpawnerLogicAccessor; + import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityType; @@ -35,7 +37,6 @@ import com.dfsek.terra.api.block.entity.MobSpawner; import com.dfsek.terra.api.block.entity.SerialState; import com.dfsek.terra.api.entity.EntityType; import com.dfsek.terra.fabric.FabricEntryPoint; -import com.dfsek.terra.fabric.mixin.access.MobSpawnerLogicAccessor; @Mixin(MobSpawnerBlockEntity.class) diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/state/BlockStateMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/state/BlockStateMixin.java index 361dd8ae4..86552bda4 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/state/BlockStateMixin.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/state/BlockStateMixin.java @@ -1,6 +1,8 @@ package com.dfsek.terra.fabric.mixin.implementations.terra.block.state; +import com.dfsek.terra.mod.mixin.access.StateAccessor; + import com.google.common.collect.ImmutableMap; import com.mojang.serialization.MapCodec; import net.minecraft.block.AbstractBlock.AbstractBlockState; @@ -18,7 +20,6 @@ import java.util.stream.Collectors; import com.dfsek.terra.api.block.BlockType; import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.block.state.properties.Property; -import com.dfsek.terra.fabric.mixin.access.StateAccessor; @Mixin(AbstractBlockState.class) diff --git a/platforms/fabric/src/main/resources/terra.fabric.mixins.json b/platforms/fabric/src/main/resources/terra.fabric.mixins.json index 4e8614ba3..f18482bf5 100644 --- a/platforms/fabric/src/main/resources/terra.fabric.mixins.json +++ b/platforms/fabric/src/main/resources/terra.fabric.mixins.json @@ -4,10 +4,6 @@ "package": "com.dfsek.terra.fabric.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ - "access.ChunkRegionAccessor", - "access.MobSpawnerLogicAccessor", - "access.StateAccessor", - "access.StructureAccessorAccessor", "fix.BeeMoveGoalsUnsynchronizedRandomAccessFix", "fix.NetherFossilOptimization", "implementations.compat.GenerationSettingsFloraFeaturesMixin", @@ -49,5 +45,5 @@ "injectors": { "defaultRequire": 1 }, - "refmap": "terra-refmap.json" + "refmap": "terra-fabric-refmap.json" } \ No newline at end of file diff --git a/platforms/forge/build.gradle.kts b/platforms/forge/build.gradle.kts index 63db47bf2..1f630bda5 100644 --- a/platforms/forge/build.gradle.kts +++ b/platforms/forge/build.gradle.kts @@ -13,7 +13,7 @@ dependencies { loom { mixin { - defaultRefmapName.set("terra-refmap.json") + defaultRefmapName.set("terra-forge-refmap.json") } forge { diff --git a/platforms/forge/src/main/resources/terra.forge.mixins.json b/platforms/forge/src/main/resources/terra.forge.mixins.json index e68b6351b..33af22478 100644 --- a/platforms/forge/src/main/resources/terra.forge.mixins.json +++ b/platforms/forge/src/main/resources/terra.forge.mixins.json @@ -44,5 +44,5 @@ "injectors": { "defaultRequire": 1 }, - "refmap": "terra-refmap.json" + "refmap": "terra-forge-refmap.json" } \ No newline at end of file diff --git a/platforms/mod-common/README.md b/platforms/mod-common/README.md new file mode 100644 index 000000000..f92b8b043 --- /dev/null +++ b/platforms/mod-common/README.md @@ -0,0 +1,4 @@ +# mixin-common + +This project contains mixins shared between Forge & Fabric, as +well as glue code. \ No newline at end of file diff --git a/platforms/mod-common/build.gradle.kts b/platforms/mod-common/build.gradle.kts new file mode 100644 index 000000000..bb7de895f --- /dev/null +++ b/platforms/mod-common/build.gradle.kts @@ -0,0 +1,18 @@ +plugins { + id("dev.architectury.loom") version Versions.Mod.architecuryLoom + id("architectury-plugin") version Versions.Mod.architectutyPlugin +} + +dependencies { + shadedApi(project(":common:implementation:base")) + + modImplementation("net.fabricmc:fabric-loader:${Versions.Mod.fabricLoader}") + + minecraft("com.mojang:minecraft:${Versions.Mod.minecraft}") + mappings("net.fabricmc:yarn:${Versions.Mod.yarn}:v2") +} + +architectury { + common("fabric", "forge") + minecraft = Versions.Mod.minecraft +} \ No newline at end of file diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/MobSpawnerLogicAccessor.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/access/MobSpawnerLogicAccessor.java similarity index 95% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/MobSpawnerLogicAccessor.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/access/MobSpawnerLogicAccessor.java index 28cda62be..5289cd427 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/MobSpawnerLogicAccessor.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/access/MobSpawnerLogicAccessor.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.access; +package com.dfsek.terra.mod.mixin.access; import net.minecraft.world.MobSpawnerEntry; import net.minecraft.world.MobSpawnerLogic; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/StateAccessor.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/access/StateAccessor.java similarity index 96% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/StateAccessor.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/access/StateAccessor.java index 1ec51c2dc..0cee6cbaf 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/StateAccessor.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/access/StateAccessor.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.access; +package com.dfsek.terra.mod.mixin.access; import net.minecraft.state.State; import net.minecraft.state.property.Property; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/StructureAccessorAccessor.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/access/StructureAccessorAccessor.java similarity index 95% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/StructureAccessorAccessor.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/access/StructureAccessorAccessor.java index da33618d2..b64b47faa 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/access/StructureAccessorAccessor.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/access/StructureAccessorAccessor.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.access; +package com.dfsek.terra.mod.mixin.access; import net.minecraft.world.WorldAccess; import net.minecraft.world.gen.StructureAccessor; diff --git a/platforms/mod-common/src/main/resources/fabric.mod.json b/platforms/mod-common/src/main/resources/fabric.mod.json new file mode 100644 index 000000000..2f4b9b0de --- /dev/null +++ b/platforms/mod-common/src/main/resources/fabric.mod.json @@ -0,0 +1,8 @@ +{ + "schemaVersion": 1, + "id": "terra-common", + "version": "1.0.0", + "mixins": [ + "terra.common.mixins.json" + ] +} \ No newline at end of file diff --git a/platforms/mod-common/src/main/resources/terra.common.mixins.json b/platforms/mod-common/src/main/resources/terra.common.mixins.json new file mode 100644 index 000000000..ee399c73e --- /dev/null +++ b/platforms/mod-common/src/main/resources/terra.common.mixins.json @@ -0,0 +1,19 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "com.dfsek.terra.mod.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "access.MobSpawnerLogicAccessor", + "access.StateAccessor", + "access.StructureAccessorAccessor" + ], + "client": [ + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + }, + "refmap": "terra-common-refmap.json" +} \ No newline at end of file From 1a1000bbef66bf0fb2c6cbb8525e0bc4fc556979 Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 21 Jun 2022 15:38:28 -0700 Subject: [PATCH 27/38] fix forge build --- platforms/fabric/build.gradle.kts | 8 ++++++-- platforms/forge/build.gradle.kts | 27 ++++++++++++++++++++++++++- platforms/mod-common/build.gradle.kts | 6 ++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/platforms/fabric/build.gradle.kts b/platforms/fabric/build.gradle.kts index b8a3b4562..2af355a9a 100644 --- a/platforms/fabric/build.gradle.kts +++ b/platforms/fabric/build.gradle.kts @@ -4,9 +4,13 @@ plugins { id("io.github.juuxel.loom-quiltflower") version Versions.Fabric.loomQuiltflower } +architectury { + fabric() +} + + configurations { val common by creating - create("shadowCommon") compileClasspath.get().extendsFrom(common) runtimeClasspath.get().extendsFrom(common) } @@ -19,7 +23,7 @@ dependencies { "annotationProcessor"("net.fabricmc:fabric-loom:${Versions.Fabric.loom}") "common"(project(path = ":platforms:mod-common", configuration = "namedElements")) { isTransitive = false } - "shadowCommon"(project(path = ":platforms:mod-common", configuration = "transformProductionFabric")) { isTransitive = false } + shaded(project(path = ":platforms:mod-common", configuration = "transformProductionFabric")) { isTransitive = false } minecraft("com.mojang:minecraft:${Versions.Fabric.minecraft}") mappings("net.fabricmc:yarn:${Versions.Fabric.yarn}:v2") diff --git a/platforms/forge/build.gradle.kts b/platforms/forge/build.gradle.kts index 1f630bda5..9fcf26433 100644 --- a/platforms/forge/build.gradle.kts +++ b/platforms/forge/build.gradle.kts @@ -1,10 +1,30 @@ plugins { id("dev.architectury.loom") version Versions.Forge.architecuryLoom + id("architectury-plugin") version Versions.Mod.architectutyPlugin + id("io.github.juuxel.loom-quiltflower") version Versions.Fabric.loomQuiltflower +} + +architectury { + platformSetupLoomIde() + forge() +} + +configurations { + val common by creating + compileClasspath.get().extendsFrom(common) + runtimeClasspath.get().extendsFrom(common) } dependencies { shadedApi(project(":common:implementation:base")) + "common"(project(path = ":platforms:mod-common", configuration = "namedElements")) { isTransitive = false } + shaded(project(path = ":platforms:mod-common", configuration = "transformProductionForge")) { isTransitive = false } + "developmentForge"(project(":platforms:mod-common", configuration = "namedElements")) { + isTransitive = false + } + + forge(group = "net.minecraftforge", name = "forge", version = Versions.Forge.forge) minecraft("com.mojang:minecraft:${Versions.Forge.minecraft}") @@ -17,7 +37,8 @@ loom { } forge { - mixinConfigs.set(listOf("terra.forge.mixins.json")) + mixinConfig("terra.common.mixins.json") + mixinConfig("terra.forge.mixins.json") } } @@ -34,6 +55,10 @@ tasks { ) } } + + shadowJar { + exclude("fabric.mod.json") + } remapJar { inputFile.set(shadowJar.get().archiveFile) diff --git a/platforms/mod-common/build.gradle.kts b/platforms/mod-common/build.gradle.kts index bb7de895f..33a503818 100644 --- a/platforms/mod-common/build.gradle.kts +++ b/platforms/mod-common/build.gradle.kts @@ -3,6 +3,12 @@ plugins { id("architectury-plugin") version Versions.Mod.architectutyPlugin } +loom { + mixin { + defaultRefmapName.set("terra-common-refmap.json") + } +} + dependencies { shadedApi(project(":common:implementation:base")) From 2a6d130d2074642280fd98c0e63b2d941cf24428 Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 21 Jun 2022 15:48:09 -0700 Subject: [PATCH 28/38] move world handle into common module --- .../com/dfsek/terra/fabric/PlatformImpl.java | 4 +- .../com/dfsek/terra/forge/PlatformImpl.java | 4 +- .../terra/forge/handle/ForgeWorldHandle.java | 59 ------------------- .../mod/handle/MinecraftWorldHandle.java} | 8 +-- 4 files changed, 6 insertions(+), 69 deletions(-) delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/handle/ForgeWorldHandle.java rename platforms/{fabric/src/main/java/com/dfsek/terra/fabric/handle/FabricWorldHandle.java => mod-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftWorldHandle.java} (89%) diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/PlatformImpl.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/PlatformImpl.java index fef99d2cd..2ba5701f0 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/PlatformImpl.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/PlatformImpl.java @@ -49,14 +49,14 @@ import com.dfsek.terra.api.util.generic.Lazy; import com.dfsek.terra.api.world.biome.PlatformBiome; import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper; import com.dfsek.terra.fabric.handle.FabricItemHandle; -import com.dfsek.terra.fabric.handle.FabricWorldHandle; +import com.dfsek.terra.mod.handle.MinecraftWorldHandle; import com.dfsek.terra.fabric.util.ProtoPlatformBiome; public class PlatformImpl extends AbstractPlatform { private static final Logger LOGGER = LoggerFactory.getLogger(PlatformImpl.class); private final ItemHandle itemHandle = new FabricItemHandle(); - private final WorldHandle worldHandle = new FabricWorldHandle(); + private final WorldHandle worldHandle = new MinecraftWorldHandle(); private final Lazy dataFolder = Lazy.lazy(() -> new File(FabricLoader.getInstance().getConfigDir().toFile(), "Terra")); private MinecraftServer server; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java index 6426c5685..2b414715a 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java @@ -49,14 +49,14 @@ import com.dfsek.terra.api.util.generic.Lazy; import com.dfsek.terra.api.world.biome.PlatformBiome; import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper; import com.dfsek.terra.forge.handle.ForgeItemHandle; -import com.dfsek.terra.forge.handle.ForgeWorldHandle; import com.dfsek.terra.forge.util.ProtoPlatformBiome; +import com.dfsek.terra.mod.handle.MinecraftWorldHandle; public class PlatformImpl extends AbstractPlatform { private static final Logger LOGGER = LoggerFactory.getLogger(PlatformImpl.class); private final ItemHandle itemHandle = new ForgeItemHandle(); - private final WorldHandle worldHandle = new ForgeWorldHandle(); + private final WorldHandle worldHandle = new MinecraftWorldHandle(); private final Lazy dataFolder = Lazy.lazy(() -> new File("./config/Terra")); public PlatformImpl() { diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/ForgeWorldHandle.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/ForgeWorldHandle.java deleted file mode 100644 index b139af0e8..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/ForgeWorldHandle.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.forge.handle; - -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.block.Blocks; -import net.minecraft.command.argument.BlockArgumentParser; -import net.minecraft.util.Identifier; -import net.minecraft.util.registry.Registry; -import net.minecraftforge.registries.ForgeRegistries; -import org.jetbrains.annotations.NotNull; - -import com.dfsek.terra.api.block.state.BlockState; -import com.dfsek.terra.api.entity.EntityType; -import com.dfsek.terra.api.handle.WorldHandle; - - -public class ForgeWorldHandle implements WorldHandle { - - private static final BlockState AIR = (BlockState) Blocks.AIR.getDefaultState(); - - @Override - public @NotNull BlockState createBlockState(@NotNull String data) { - try { - net.minecraft.block.BlockState state = BlockArgumentParser.block(Registry.BLOCK, data, true).blockState(); - if(state == null) throw new IllegalArgumentException("Invalid data: " + data); - return (BlockState) state; - } catch(CommandSyntaxException e) { - throw new IllegalArgumentException(e); - } - } - - @Override - public @NotNull BlockState air() { - return AIR; - } - - @Override - public @NotNull EntityType getEntity(@NotNull String id) { - Identifier identifier = Identifier.tryParse(id); - if(identifier == null) identifier = Identifier.tryParse(id); - return (EntityType) ForgeRegistries.ENTITIES.getHolder(identifier).orElseThrow().value(); - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/handle/FabricWorldHandle.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftWorldHandle.java similarity index 89% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/handle/FabricWorldHandle.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftWorldHandle.java index ac7a0e248..13eef4b2d 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/handle/FabricWorldHandle.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftWorldHandle.java @@ -15,16 +15,12 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.handle; +package com.dfsek.terra.mod.handle; -import com.dfsek.terra.fabric.FabricEntryPoint; - -import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.block.Blocks; import net.minecraft.command.argument.BlockArgumentParser; import net.minecraft.util.Identifier; -import net.minecraft.util.registry.BuiltinRegistries; import net.minecraft.util.registry.Registry; import org.jetbrains.annotations.NotNull; @@ -33,7 +29,7 @@ import com.dfsek.terra.api.entity.EntityType; import com.dfsek.terra.api.handle.WorldHandle; -public class FabricWorldHandle implements WorldHandle { +public class MinecraftWorldHandle implements WorldHandle { private static final BlockState AIR = (BlockState) Blocks.AIR.getDefaultState(); From 2a24fa56d7f2169e9f08b332c9096f868698b32e Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 21 Jun 2022 16:01:59 -0700 Subject: [PATCH 29/38] move seedhack into common --- .../fabric/generation/TerraBiomeSource.java | 5 +--- .../mixin/lifecycle/NoiseConfigMixin.java | 4 +-- .../com/dfsek/terra/fabric/util/SeedHack.java | 29 ------------------- .../mixin/lifecycle/NoiseConfigMixin.java | 10 ++----- .../com/dfsek/terra/mod}/util/SeedHack.java | 2 +- 5 files changed, 6 insertions(+), 44 deletions(-) delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/SeedHack.java rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/util/SeedHack.java (96%) diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java index 17aaa343f..dec7784ff 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java @@ -22,11 +22,9 @@ import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.fabric.data.Codecs; import com.dfsek.terra.fabric.util.ProtoPlatformBiome; -import com.dfsek.terra.fabric.util.SeedHack; +import com.dfsek.terra.mod.util.SeedHack; import com.mojang.serialization.Codec; -import it.unimi.dsi.fastutil.objects.Object2LongMap; -import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.RegistryEntry; import net.minecraft.world.biome.source.BiomeSource; @@ -34,7 +32,6 @@ import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Map; import java.util.stream.StreamSupport; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/NoiseConfigMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/NoiseConfigMixin.java index b1ddda34f..b24bfd489 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/NoiseConfigMixin.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/NoiseConfigMixin.java @@ -1,5 +1,7 @@ package com.dfsek.terra.fabric.mixin.lifecycle; +import com.dfsek.terra.mod.util.SeedHack; + import net.minecraft.util.math.noise.DoublePerlinNoiseSampler; import net.minecraft.util.registry.Registry; import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; @@ -12,8 +14,6 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.dfsek.terra.fabric.util.SeedHack; - /** * Hack to map noise sampler to seeds diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/SeedHack.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/SeedHack.java deleted file mode 100644 index f0c59fc00..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/SeedHack.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.dfsek.terra.fabric.util; - -import it.unimi.dsi.fastutil.objects.Object2LongMap; -import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; -import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - - -/** - * Holder for hacky biome source seed workaround - */ -public class SeedHack { - private static final Logger LOGGER = LoggerFactory.getLogger(SeedHack.class); - - private static final Object2LongMap seedMap = new Object2LongOpenHashMap<>(); - - public static long getSeed(MultiNoiseSampler sampler) { - if(!seedMap.containsKey(sampler)) { - throw new IllegalArgumentException("Sampler is not registered: " + sampler); - } - return seedMap.getLong(sampler); - } - - public static void register(MultiNoiseSampler sampler, long seed) { - LOGGER.info("Registered seed {} to sampler {}", seed, sampler.hashCode()); - seedMap.put(sampler, seed); - } -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java index 7360045af..41a113f9e 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/NoiseConfigMixin.java @@ -1,25 +1,19 @@ package com.dfsek.terra.forge.mixin.lifecycle; -import com.dfsek.terra.forge.util.SeedHack; - -import net.minecraft.util.math.noise.DoublePerlinNoiseSampler; -import net.minecraft.util.math.noise.DoublePerlinNoiseSampler.NoiseParameters; -import net.minecraft.util.math.random.RandomSplitter; -import net.minecraft.util.registry.Registry; import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; import net.minecraft.world.biome.source.util.MultiNoiseUtil.NoiseHypercube; -import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; import net.minecraft.world.gen.densityfunction.DensityFunction; import net.minecraft.world.gen.noise.NoiseConfig; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; 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.Redirect; import java.util.List; +import com.dfsek.terra.mod.util.SeedHack; + /** * Hack to map noise sampler to seeds diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/SeedHack.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/SeedHack.java similarity index 96% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/util/SeedHack.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/SeedHack.java index 5eaf38093..74f9173ab 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/SeedHack.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/SeedHack.java @@ -1,4 +1,4 @@ -package com.dfsek.terra.forge.util; +package com.dfsek.terra.mod.util; import it.unimi.dsi.fastutil.objects.Object2LongMap; import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; From 7c2908e5cafde28d81908c184eb79f0064aba7c6 Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 21 Jun 2022 17:53:46 -0700 Subject: [PATCH 30/38] move most mod code into mod common --- .../dfsek/terra/fabric/FabricEntryPoint.java | 5 +- .../com/dfsek/terra/fabric/PlatformImpl.java | 52 +--- .../config/PostLoadCompatibilityOptions.java | 28 -- .../fabric/config/VanillaBiomeProperties.java | 76 ------ .../terra/fabric/handle/FabricItemHandle.java | 57 ---- ...oveGoalsUnsynchronizedRandomAccessFix.java | 27 -- .../mixin/fix/NetherFossilOptimization.java | 42 --- .../GenerationSettingsFloraFeaturesMixin.java | 32 --- .../implementations/terra/BiomeMixin.java | 31 --- .../terra/HandleImplementationMixin.java | 61 ----- .../terra/block/BlockMixin.java | 44 ---- .../terra/block/entity/BlockEntityMixin.java | 54 ---- .../LootableContainerBlockEntityMixin.java | 35 --- .../block/entity/SignBlockEntityMixin.java | 65 ----- .../terra/block/state/PropertyMixin.java | 43 --- .../terra/chunk/ChunkRegionMixin.java | 58 ----- .../terra/chunk/WorldChunkMixin.java | 75 ------ .../terra/chunk/data/ProtoChunkMixin.java | 53 ---- .../terra/entity/EntityMixin.java | 55 ---- .../terra/entity/EntityTypeMixin.java | 29 --- .../terra/entity/PlayerEntityMixin.java | 31 --- .../entity/ServerCommandSourceMixin.java | 66 ----- .../LockableContainerBlockEntityMixin.java | 47 ---- .../terra/inventory/item/ItemMixin.java | 43 --- .../terra/inventory/item/ItemStackMixin.java | 76 ------ .../inventory/meta/EnchantmentMixin.java | 53 ---- .../meta/ItemStackDamageableMixin.java | 55 ---- .../inventory/meta/ItemStackMetaMixin.java | 65 ----- .../implementations/terra/package-info.java | 23 -- .../mixin_ifaces/FloraFeatureHolder.java | 10 - .../dfsek/terra/fabric/util/BiomeUtil.java | 17 +- .../terra/fabric/util/FabricAdapter.java | 185 ------------- .../dfsek/terra/fabric/util/FabricUtil.java | 61 ----- .../terra/fabric/util/LifecycleUtil.java | 6 +- .../com/dfsek/terra/fabric/util/TagUtil.java | 8 +- .../main/resources/terra.fabric.mixins.json | 27 -- .../com/dfsek/terra/forge/ForgeAddon.java | 80 ------ .../dfsek/terra/forge/ForgeEntryPoint.java | 9 +- .../com/dfsek/terra/forge/PlatformImpl.java | 52 +--- .../config/PreLoadCompatibilityOptions.java | 60 ----- .../com/dfsek/terra/forge/data/Codecs.java | 65 ----- .../ForgeChunkGeneratorWrapper.java | 246 ------------------ .../forge/generation/TerraBiomeSource.java | 86 ------ .../mixin/access/MobSpawnerLogicAccessor.java | 30 --- .../forge/mixin/access/StateAccessor.java | 35 --- .../access/StructureAccessorAccessor.java | 30 --- .../entity/MobSpawnerBlockEntityMixin.java | 131 ---------- .../terra/block/state/BlockStateMixin.java | 83 ------ .../terra/world/ChunkRegionMixin.java | 149 ----------- .../terra/world/ServerWorldMixin.java | 102 -------- .../com/dfsek/terra/forge/util/BiomeUtil.java | 24 +- .../dfsek/terra/forge/util/LifecycleUtil.java | 12 +- .../terra/forge/util/ProtoPlatformBiome.java | 61 ----- .../com/dfsek/terra/forge/util/TagUtil.java | 8 +- .../main/resources/terra.forge.mixins.json | 30 --- .../com/dfsek/terra/mod/CommonPlatform.java | 24 ++ .../com/dfsek/terra/mod/MinecraftAddon.java} | 50 ++-- .../java/com/dfsek/terra/mod/ModPlatform.java | 56 ++++ .../config/PostLoadCompatibilityOptions.java | 2 +- .../config/PreLoadCompatibilityOptions.java | 10 +- .../terra/mod/config}/ProtoPlatformBiome.java | 6 +- .../mod}/config/VanillaBiomeProperties.java | 2 +- .../com/dfsek/terra/mod}/data/Codecs.java | 33 +-- .../MinecraftChunkGeneratorWrapper.java} | 22 +- .../mod}/generation/TerraBiomeSource.java | 6 +- .../mod/handle/MinecraftItemHandle.java} | 9 +- ...oveGoalsUnsynchronizedRandomAccessFix.java | 8 +- .../mixin/fix/NetherFossilOptimization.java | 8 +- .../GenerationSettingsFloraFeaturesMixin.java | 4 +- .../implementations/terra/BiomeMixin.java | 2 +- .../terra/HandleImplementationMixin.java | 2 +- .../terra/block/BlockMixin.java | 2 +- .../terra/block/entity/BlockEntityMixin.java | 2 +- .../LootableContainerBlockEntityMixin.java | 2 +- .../entity/MobSpawnerBlockEntityMixin.java | 9 +- .../block/entity/SignBlockEntityMixin.java | 2 +- .../terra/block/state/BlockStateMixin.java | 2 +- .../terra/block/state/PropertyMixin.java | 2 +- .../terra/chunk/ChunkRegionMixin.java | 2 +- .../terra/chunk/WorldChunkMixin.java | 2 +- .../terra/chunk/data/ProtoChunkMixin.java | 2 +- .../terra/entity/EntityMixin.java | 6 +- .../terra/entity/EntityTypeMixin.java | 2 +- .../terra/entity/PlayerEntityMixin.java | 2 +- .../entity/ServerCommandSourceMixin.java | 2 +- .../LockableContainerBlockEntityMixin.java | 2 +- .../terra/inventory/item/ItemMixin.java | 2 +- .../terra/inventory/item/ItemStackMixin.java | 2 +- .../inventory/meta/EnchantmentMixin.java | 2 +- .../meta/ItemStackDamageableMixin.java | 2 +- .../inventory/meta/ItemStackMetaMixin.java | 2 +- .../implementations/terra/package-info.java | 2 +- .../terra/world/ChunkRegionMixin.java | 10 +- .../terra/world/ServerWorldMixin.java | 18 +- .../mod}/mixin_ifaces/FloraFeatureHolder.java | 2 +- .../terra/mod/util/MinecraftAdapter.java} | 4 +- .../dfsek/terra/mod/util/MinecraftUtil.java} | 43 +-- .../main/resources/terra.common.mixins.json | 29 ++- 98 files changed, 320 insertions(+), 3071 deletions(-) delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PostLoadCompatibilityOptions.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/VanillaBiomeProperties.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/handle/FabricItemHandle.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/fix/NetherFossilOptimization.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/BiomeMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/HandleImplementationMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/BlockMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/BlockEntityMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/state/PropertyMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/chunk/ChunkRegionMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/chunk/WorldChunkMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/entity/EntityMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/entity/EntityTypeMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/entity/PlayerEntityMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/entity/ServerCommandSourceMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/item/ItemMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/item/ItemStackMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/package-info.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin_ifaces/FloraFeatureHolder.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricAdapter.java delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricUtil.java delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeAddon.java delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/config/PreLoadCompatibilityOptions.java delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/data/Codecs.java delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/generation/ForgeChunkGeneratorWrapper.java delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/generation/TerraBiomeSource.java delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/MobSpawnerLogicAccessor.java delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/StateAccessor.java delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/StructureAccessorAccessor.java delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/state/BlockStateMixin.java delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ChunkRegionMixin.java delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ServerWorldMixin.java delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java create mode 100644 platforms/mod-common/src/main/java/com/dfsek/terra/mod/CommonPlatform.java rename platforms/{fabric/src/main/java/com/dfsek/terra/fabric/FabricAddon.java => mod-common/src/main/java/com/dfsek/terra/mod/MinecraftAddon.java} (55%) create mode 100644 platforms/mod-common/src/main/java/com/dfsek/terra/mod/ModPlatform.java rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/config/PostLoadCompatibilityOptions.java (95%) rename platforms/{fabric/src/main/java/com/dfsek/terra/fabric => mod-common/src/main/java/com/dfsek/terra/mod}/config/PreLoadCompatibilityOptions.java (88%) rename platforms/{fabric/src/main/java/com/dfsek/terra/fabric/util => mod-common/src/main/java/com/dfsek/terra/mod/config}/ProtoPlatformBiome.java (89%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/config/VanillaBiomeProperties.java (97%) rename platforms/{fabric/src/main/java/com/dfsek/terra/fabric => mod-common/src/main/java/com/dfsek/terra/mod}/data/Codecs.java (79%) rename platforms/{fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java => mod-common/src/main/java/com/dfsek/terra/mod/generation/MinecraftChunkGeneratorWrapper.java} (91%) rename platforms/{fabric/src/main/java/com/dfsek/terra/fabric => mod-common/src/main/java/com/dfsek/terra/mod}/generation/TerraBiomeSource.java (95%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge/handle/ForgeItemHandle.java => mod-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftItemHandle.java} (87%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java (79%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/fix/NetherFossilOptimization.java (73%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java (89%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/BiomeMixin.java (94%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/HandleImplementationMixin.java (96%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/block/BlockMixin.java (95%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/block/entity/BlockEntityMixin.java (96%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java (94%) rename platforms/{fabric/src/main/java/com/dfsek/terra/fabric => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java (94%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java (96%) rename platforms/{fabric/src/main/java/com/dfsek/terra/fabric => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/block/state/BlockStateMixin.java (97%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/block/state/PropertyMixin.java (93%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/chunk/ChunkRegionMixin.java (97%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/chunk/WorldChunkMixin.java (97%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java (96%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/entity/EntityMixin.java (90%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/entity/EntityTypeMixin.java (93%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/entity/PlayerEntityMixin.java (94%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/entity/ServerCommandSourceMixin.java (97%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java (96%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/inventory/item/ItemMixin.java (95%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/inventory/item/ItemStackMixin.java (96%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java (96%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java (95%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java (96%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/package-info.java (92%) rename platforms/{fabric/src/main/java/com/dfsek/terra/fabric => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/world/ChunkRegionMixin.java (93%) rename platforms/{fabric/src/main/java/com/dfsek/terra/fabric => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/implementations/terra/world/ServerWorldMixin.java (85%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/mixin_ifaces/FloraFeatureHolder.java (81%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge/util/ForgeAdapter.java => mod-common/src/main/java/com/dfsek/terra/mod/util/MinecraftAdapter.java} (95%) rename platforms/{forge/src/main/java/com/dfsek/terra/forge/util/ForgeUtil.java => mod-common/src/main/java/com/dfsek/terra/mod/util/MinecraftUtil.java} (64%) diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricEntryPoint.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricEntryPoint.java index 66348ed53..d85b330e0 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricEntryPoint.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricEntryPoint.java @@ -28,11 +28,10 @@ import net.fabricmc.api.ModInitializer; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.util.Identifier; import net.minecraft.util.registry.Registry; -import net.minecraft.world.gen.WorldPresets; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.dfsek.terra.fabric.data.Codecs; +import com.dfsek.terra.mod.data.Codecs; public class FabricEntryPoint implements ModInitializer { @@ -46,7 +45,7 @@ public class FabricEntryPoint implements ModInitializer { } public static void register() { // register the things - Registry.register(Registry.CHUNK_GENERATOR, new Identifier("terra:terra"), Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER); + Registry.register(Registry.CHUNK_GENERATOR, new Identifier("terra:terra"), Codecs.MINECRAFT_CHUNK_GENERATOR_WRAPPER); Registry.register(Registry.BIOME_SOURCE, new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE); } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/PlatformImpl.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/PlatformImpl.java index 2ba5701f0..efa3bfe17 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/PlatformImpl.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/PlatformImpl.java @@ -20,17 +20,14 @@ package com.dfsek.terra.fabric; import ca.solostudios.strata.Versions; import ca.solostudios.strata.parser.tokenizer.ParseException; import ca.solostudios.strata.version.Version; -import com.dfsek.tectonic.api.TypeRegistry; -import com.dfsek.tectonic.api.depth.DepthTracker; -import com.dfsek.tectonic.api.exception.LoadException; + import com.dfsek.terra.fabric.util.BiomeUtil; +import com.dfsek.terra.mod.CommonPlatform; +import com.dfsek.terra.mod.ModPlatform; + import net.fabricmc.loader.api.FabricLoader; import net.minecraft.MinecraftVersion; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.Identifier; -import net.minecraft.util.registry.BuiltinRegistries; -import net.minecraft.world.biome.Biome.Precipitation; -import net.minecraft.world.biome.BiomeEffects.GrassColorModifier; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,29 +35,26 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.util.ArrayList; import java.util.List; -import java.util.Locale; -import com.dfsek.terra.AbstractPlatform; import com.dfsek.terra.addon.EphemeralAddon; import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.api.handle.ItemHandle; import com.dfsek.terra.api.handle.WorldHandle; import com.dfsek.terra.api.util.generic.Lazy; -import com.dfsek.terra.api.world.biome.PlatformBiome; -import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper; -import com.dfsek.terra.fabric.handle.FabricItemHandle; +import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; +import com.dfsek.terra.mod.handle.MinecraftItemHandle; import com.dfsek.terra.mod.handle.MinecraftWorldHandle; -import com.dfsek.terra.fabric.util.ProtoPlatformBiome; -public class PlatformImpl extends AbstractPlatform { +public class PlatformImpl extends ModPlatform { private static final Logger LOGGER = LoggerFactory.getLogger(PlatformImpl.class); - private final ItemHandle itemHandle = new FabricItemHandle(); + private final ItemHandle itemHandle = new MinecraftItemHandle(); private final WorldHandle worldHandle = new MinecraftWorldHandle(); private final Lazy dataFolder = Lazy.lazy(() -> new File(FabricLoader.getInstance().getConfigDir().toFile(), "Terra")); private MinecraftServer server; public PlatformImpl() { + CommonPlatform.initialize(this); load(); } @@ -68,6 +62,7 @@ public class PlatformImpl extends AbstractPlatform { this.server = server; } + @Override public MinecraftServer getServer() { return server; } @@ -86,7 +81,7 @@ public class PlatformImpl extends AbstractPlatform { }).join(); BiomeUtil.registerBiomes(); server.getWorlds().forEach(world -> { - if(world.getChunkManager().getChunkGenerator() instanceof FabricChunkGeneratorWrapper chunkGeneratorWrapper) { + if(world.getChunkManager().getChunkGenerator() instanceof MinecraftChunkGeneratorWrapper chunkGeneratorWrapper) { getConfigRegistry().get(chunkGeneratorWrapper.getPack().getRegistryKey()).ifPresent(pack -> { chunkGeneratorWrapper.setPack(pack); LOGGER.info("Replaced pack in chunk generator for world {}", world); @@ -101,7 +96,7 @@ public class PlatformImpl extends AbstractPlatform { protected Iterable platformAddon() { List addons = new ArrayList<>(); - addons.add(new FabricAddon(this)); + super.platformAddon().forEach(addons::add); String mcVersion = MinecraftVersion.CURRENT.getReleaseTarget(); try { @@ -150,27 +145,4 @@ public class PlatformImpl extends AbstractPlatform { public @NotNull ItemHandle getItemHandle() { return itemHandle; } - - @Override - public void register(TypeRegistry registry) { - super.register(registry); - registry.registerLoader(PlatformBiome.class, (type, o, loader, depthTracker) -> parseBiome((String) o, depthTracker)) - .registerLoader(Identifier.class, (type, o, loader, depthTracker) -> { - Identifier identifier = Identifier.tryParse((String) o); - if(identifier == null) - throw new LoadException("Invalid identifier: " + o, depthTracker); - return identifier; - }) - .registerLoader(Precipitation.class, (type, o, loader, depthTracker) -> Precipitation.valueOf(((String) o).toUpperCase( - Locale.ROOT))) - .registerLoader(GrassColorModifier.class, (type, o, loader, depthTracker) -> GrassColorModifier.valueOf(((String) o).toUpperCase( - Locale.ROOT))); - } - - - private ProtoPlatformBiome parseBiome(String id, DepthTracker tracker) throws LoadException { - Identifier identifier = Identifier.tryParse(id); - if(BuiltinRegistries.BIOME.get(identifier) == null) throw new LoadException("Invalid Biome ID: " + identifier, tracker); // failure. - return new ProtoPlatformBiome(identifier); - } } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PostLoadCompatibilityOptions.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PostLoadCompatibilityOptions.java deleted file mode 100644 index 9a13e0029..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PostLoadCompatibilityOptions.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.config; - -import com.dfsek.tectonic.api.config.template.ConfigTemplate; - -import com.dfsek.terra.api.properties.Properties; - - -@SuppressWarnings("FieldMayBeFinal") -public class PostLoadCompatibilityOptions implements ConfigTemplate, Properties { - -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/VanillaBiomeProperties.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/VanillaBiomeProperties.java deleted file mode 100644 index 889c9148f..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/VanillaBiomeProperties.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.dfsek.terra.fabric.config; - -import com.dfsek.tectonic.api.config.template.ConfigTemplate; -import com.dfsek.tectonic.api.config.template.annotations.Default; -import com.dfsek.tectonic.api.config.template.annotations.Value; -import net.minecraft.world.biome.Biome.Precipitation; -import net.minecraft.world.biome.BiomeEffects.GrassColorModifier; - -import com.dfsek.terra.api.properties.Properties; - - -public class VanillaBiomeProperties implements ConfigTemplate, Properties { - @Value("colors.grass") - @Default - private Integer grassColor = null; - - @Value("colors.fog") - @Default - private Integer fogColor = null; - - @Value("colors.water") - @Default - private Integer waterColor = null; - - @Value("colors.water-fog") - @Default - private Integer waterFogColor = null; - - @Value("colors.foliage") - @Default - private Integer foliageColor = null; - - @Value("colors.sky") - @Default - private Integer skyColor = null; - - @Value("colors.modifier") - @Default - private GrassColorModifier modifier = null; - - @Value("climate.precipitation") - @Default - private Precipitation precipitation = null; - - public Integer getFogColor() { - return fogColor; - } - - public Integer getFoliageColor() { - return foliageColor; - } - - public Integer getGrassColor() { - return grassColor; - } - - public Integer getWaterColor() { - return waterColor; - } - - public Integer getWaterFogColor() { - return waterFogColor; - } - - public Integer getSkyColor() { - return skyColor; - } - - public Precipitation getPrecipitation() { - return precipitation; - } - - public GrassColorModifier getModifier() { - return modifier; - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/handle/FabricItemHandle.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/handle/FabricItemHandle.java deleted file mode 100644 index beb2ee7a2..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/handle/FabricItemHandle.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.handle; - -import com.dfsek.terra.fabric.FabricEntryPoint; - -import com.mojang.brigadier.StringReader; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.command.CommandRegistryAccess; -import net.minecraft.command.argument.ItemStackArgumentType; -import net.minecraft.util.Identifier; -import net.minecraft.util.registry.Registry; - -import java.util.Set; -import java.util.stream.Collectors; - -import com.dfsek.terra.api.handle.ItemHandle; -import com.dfsek.terra.api.inventory.Item; -import com.dfsek.terra.api.inventory.item.Enchantment; - - -public class FabricItemHandle implements ItemHandle { - - @Override - public Item createItem(String data) { - try { - return (Item) new ItemStackArgumentType(new CommandRegistryAccess(FabricEntryPoint.getPlatform().getServer().getRegistryManager())).parse(new StringReader(data)).getItem(); - } catch(CommandSyntaxException e) { - throw new IllegalArgumentException("Invalid item data \"" + data + "\"", e); - } - } - - @Override - public Enchantment getEnchantment(String id) { - return (Enchantment) (Registry.ENCHANTMENT.get(Identifier.tryParse(id))); - } - - @Override - public Set getEnchantments() { - return Registry.ENCHANTMENT.stream().map(enchantment -> (Enchantment) enchantment).collect(Collectors.toSet()); - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java deleted file mode 100644 index ced25c46b..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.dfsek.terra.fabric.mixin.fix; - -import net.minecraft.entity.passive.BeeEntity.MoveToFlowerGoal; -import net.minecraft.entity.passive.BeeEntity.MoveToHiveGoal; -import net.minecraft.util.math.random.CheckedRandom; -import net.minecraft.util.math.random.Random; -import net.minecraft.world.World; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -import com.dfsek.terra.fabric.FabricEntryPoint; - - -/** - * Bees spawning uses world.random without synchronization. This causes issues when spawning bees during world generation. - */ -@Mixin({ - MoveToHiveGoal.class, - MoveToFlowerGoal.class -}) -public class BeeMoveGoalsUnsynchronizedRandomAccessFix { - @Redirect(method = "", at = @At(value = "FIELD", target = "Lnet/minecraft/world/World;random:Lnet/minecraft/util/math/random/Random;")) - public Random redirectRandomAccess(World instance) { - return new CheckedRandom(FabricEntryPoint.getPlatform().getServer().getTicks()); // replace with new random seeded by tick time. - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/fix/NetherFossilOptimization.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/fix/NetherFossilOptimization.java deleted file mode 100644 index 770b042dd..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/fix/NetherFossilOptimization.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.dfsek.terra.fabric.mixin.fix; - -import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper; - -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.structure.NetherFossilGenerator; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.util.math.random.ChunkRandom; -import net.minecraft.world.EmptyBlockView; -import net.minecraft.world.gen.HeightContext; -import net.minecraft.world.gen.chunk.VerticalBlockSample; -import net.minecraft.world.gen.heightprovider.HeightProvider; -import net.minecraft.world.gen.structure.NetherFossilStructure; -import net.minecraft.world.gen.structure.Structure; -import net.minecraft.world.gen.structure.Structure.Context; -import net.minecraft.world.gen.structure.Structure.StructurePosition; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -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.CallbackInfoReturnable; - -import java.util.Optional; - - -/** - * Disable fossil generation in Terra worlds, as they are very expensive due to consistently triggering cache misses. - * - * Currently, on Fabric, Terra cannot be specified as a Nether generator. TODO: logic to turn fossils back on if chunk generator is in nether. - */ -@Mixin(NetherFossilStructure.class) -public class NetherFossilOptimization { - @Inject(method = "getStructurePosition", at = @At("HEAD"), cancellable = true) - public void injectFossilPositions(Context context, CallbackInfoReturnable> cir) { - if(context.chunkGenerator() instanceof FabricChunkGeneratorWrapper) { - cir.setReturnValue(Optional.empty()); - } - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java deleted file mode 100644 index 39236239f..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.dfsek.terra.fabric.mixin.implementations.compat; - -import com.dfsek.terra.fabric.mixin_ifaces.FloraFeatureHolder; - -import net.minecraft.world.biome.GenerationSettings; -import net.minecraft.world.gen.feature.ConfiguredFeature; -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.CallbackInfoReturnable; - -import java.util.List; - - -@Mixin(GenerationSettings.class) -@Implements(@Interface(iface = FloraFeatureHolder.class, prefix = "terra$")) -public class GenerationSettingsFloraFeaturesMixin { - private List> flora; - - public void terra$setFloraFeatures(List> features) { - this.flora = features; - } - - @Inject(method = "getFlowerFeatures", cancellable = true, at = @At("HEAD")) - public void inject(CallbackInfoReturnable>> cir) { - if(flora != null) { - cir.setReturnValue(flora); - } - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/BiomeMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/BiomeMixin.java deleted file mode 100644 index 7ad40e91f..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/BiomeMixin.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra; - -import net.minecraft.world.biome.Biome; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; - -import com.dfsek.terra.api.world.biome.PlatformBiome; - - -@Mixin(Biome.class) -@Implements(@Interface(iface = PlatformBiome.class, prefix = "terra$")) -public abstract class BiomeMixin { -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/HandleImplementationMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/HandleImplementationMixin.java deleted file mode 100644 index 09ddf21a7..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/HandleImplementationMixin.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.dfsek.terra.fabric.mixin.implementations.terra; - -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.LockableContainerBlockEntity; -import net.minecraft.block.entity.LootableContainerBlockEntity; -import net.minecraft.enchantment.Enchantment; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityType; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.world.ServerWorld; -import net.minecraft.world.ChunkRegion; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.chunk.ProtoChunk; -import net.minecraft.world.chunk.WorldChunk; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Intrinsic; -import org.spongepowered.asm.mixin.Mixin; - -import com.dfsek.terra.api.Handle; - - -/** - * A ton of Minecraft classes must implement Handle identically, we can just take care of it here - */ -@Mixin({ - ServerWorld.class, - ChunkRegion.class, - - Block.class, - BlockState.class, - - BlockEntity.class, - LootableContainerBlockEntity.class, - LockableContainerBlockEntity.class, - - ProtoChunk.class, - WorldChunk.class, - - Entity.class, - EntityType.class, - - ServerCommandSource.class, - - Item.class, - ItemStack.class, - Enchantment.class, - - Biome.class -}) -@Implements(@Interface(iface = Handle.class, prefix = "terra$")) -public class HandleImplementationMixin { - @Intrinsic - public Object terra$getHandle() { - return this; - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/BlockMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/BlockMixin.java deleted file mode 100644 index 271615c01..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/BlockMixin.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.block; - -import net.minecraft.block.Block; -import net.minecraft.block.Blocks; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; - -import com.dfsek.terra.api.block.BlockType; - - -@Mixin(Block.class) -@Implements(@Interface(iface = BlockType.class, prefix = "terra$")) -public abstract class BlockMixin { - public com.dfsek.terra.api.block.state.BlockState terra$getDefaultState() { - return (com.dfsek.terra.api.block.state.BlockState) ((Block) (Object) this).getDefaultState(); - } - - public boolean terra$isSolid() { - return ((Block) (Object) this).getDefaultState().isOpaque(); - } - - @SuppressWarnings("ConstantConditions") - public boolean terra$isWater() { - return ((Object) this) == Blocks.WATER; - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/BlockEntityMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/BlockEntityMixin.java deleted file mode 100644 index a8fc2a580..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/BlockEntityMixin.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.block.entity; - -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; - -import com.dfsek.terra.api.block.entity.BlockEntity; -import com.dfsek.terra.api.block.state.BlockState; - - -@Mixin(net.minecraft.block.entity.BlockEntity.class) -@Implements(@Interface(iface = BlockEntity.class, prefix = "terra$")) -public abstract class BlockEntityMixin { - public boolean terra$update(boolean applyPhysics) { - if(((net.minecraft.block.entity.BlockEntity) (Object) this).hasWorld()) //noinspection ConstantConditions - ((net.minecraft.block.entity.BlockEntity) (Object) this).getWorld().getChunk( - ((net.minecraft.block.entity.BlockEntity) (Object) this).getPos()).setBlockEntity( - (net.minecraft.block.entity.BlockEntity) (Object) this); - return true; - } - - public int terra$getX() { - return ((net.minecraft.block.entity.BlockEntity) (Object) this).getPos().getX(); - } - - public int terra$getY() { - return ((net.minecraft.block.entity.BlockEntity) (Object) this).getPos().getY(); - } - - public int terra$getZ() { - return ((net.minecraft.block.entity.BlockEntity) (Object) this).getPos().getZ(); - } - - public BlockState terra$getBlockState() { - return (BlockState) ((net.minecraft.block.entity.BlockEntity) (Object) this).getCachedState(); - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java deleted file mode 100644 index 40755991e..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.block.entity; - -import net.minecraft.block.entity.LootableContainerBlockEntity; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; - -import com.dfsek.terra.api.block.entity.Container; -import com.dfsek.terra.api.inventory.Inventory; - - -@Mixin(LootableContainerBlockEntity.class) -@Implements(@Interface(iface = Container.class, prefix = "terra$")) -public abstract class LootableContainerBlockEntityMixin extends BlockEntityMixin { - public Inventory terra$getInventory() { - return (Inventory) this; - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java deleted file mode 100644 index 2006246d8..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.block.entity; - -import net.minecraft.block.entity.SignBlockEntity; -import net.minecraft.text.Text; -import org.jetbrains.annotations.NotNull; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import com.dfsek.terra.api.block.entity.SerialState; -import com.dfsek.terra.api.block.entity.Sign; - - -@Mixin(SignBlockEntity.class) -@Implements(@Interface(iface = Sign.class, prefix = "terra$")) -public abstract class SignBlockEntityMixin { - @Shadow - @Final - private Text[] texts; - - @Shadow - public abstract void setTextOnRow(int row, Text text); - - public void terra$setLine(int index, @NotNull String line) throws IndexOutOfBoundsException { - setTextOnRow(index, Text.literal(line)); - } - - public @NotNull String[] terra$getLines() { - String[] lines = new String[texts.length]; - for(int i = 0; i < texts.length; i++) { - lines[i] = texts[i].getString(); - } - return lines; - } - - public @NotNull String terra$getLine(int index) throws IndexOutOfBoundsException { - return texts[index].getString(); - } - - public void terra$applyState(String state) { - SerialState.parse(state).forEach((k, v) -> { - if(!k.startsWith("text")) throw new IllegalArgumentException("Invalid property: " + k); - terra$setLine(Integer.parseInt(k.substring(4)), v); - }); - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/state/PropertyMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/state/PropertyMixin.java deleted file mode 100644 index 7665662be..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/state/PropertyMixin.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.dfsek.terra.fabric.mixin.implementations.terra.block.state; - -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Interface.Remap; -import org.spongepowered.asm.mixin.Intrinsic; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.Collection; - -import com.dfsek.terra.api.block.state.properties.Property; - - -@Mixin(net.minecraft.state.property.Property.class) -@Implements(@Interface(iface = Property.class, prefix = "terra$", remap = Remap.NONE)) -public abstract class PropertyMixin { - @Shadow - @Final - private Class type; - @Shadow - @Final - private String name; - - @Shadow - public abstract Collection getValues(); - - @Intrinsic - public Collection terra$values() { - return getValues(); - } - - @Intrinsic - public Class terra$getType() { - return type; - } - - @Intrinsic - public String terra$getID() { - return name; - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/chunk/ChunkRegionMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/chunk/ChunkRegionMixin.java deleted file mode 100644 index 4da5c28cf..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/chunk/ChunkRegionMixin.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.chunk; - -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.ChunkRegion; -import org.jetbrains.annotations.NotNull; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import com.dfsek.terra.api.block.state.BlockState; -import com.dfsek.terra.api.world.chunk.Chunk; - - -@Mixin(ChunkRegion.class) -@Implements(@Interface(iface = Chunk.class, prefix = "terraChunk$")) -public abstract class ChunkRegionMixin { - - @Shadow - @Final - private net.minecraft.world.chunk.Chunk centerPos; - - public void terraChunk$setBlock(int x, int y, int z, @NotNull BlockState blockState, boolean physics) { - ((ChunkRegion) (Object) this).setBlockState(new BlockPos(x + (centerPos.getPos().x << 4), y, z + (centerPos.getPos().z << 4)), - (net.minecraft.block.BlockState) blockState, 0); - } - - public @NotNull BlockState terraChunk$getBlock(int x, int y, int z) { - return (BlockState) ((ChunkRegion) (Object) this).getBlockState( - new BlockPos(x + (centerPos.getPos().x << 4), y, z + (centerPos.getPos().z << 4))); - } - - public int terraChunk$getX() { - return centerPos.getPos().x; - } - - public int terraChunk$getZ() { - return centerPos.getPos().z; - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/chunk/WorldChunkMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/chunk/WorldChunkMixin.java deleted file mode 100644 index 885d0aae2..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/chunk/WorldChunkMixin.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.chunk; - -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.chunk.WorldChunk; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Intrinsic; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import com.dfsek.terra.api.block.state.BlockState; -import com.dfsek.terra.api.world.ServerWorld; -import com.dfsek.terra.api.world.chunk.Chunk; - - -@Mixin(WorldChunk.class) -@Implements(@Interface(iface = Chunk.class, prefix = "terra$")) -public abstract class WorldChunkMixin { - @Final - @Shadow - net.minecraft.world.World world; - - @Shadow - public abstract net.minecraft.block.BlockState getBlockState(BlockPos pos); - - @Shadow - @Nullable - public abstract net.minecraft.block.BlockState setBlockState(BlockPos pos, net.minecraft.block.BlockState state, boolean moved); - - public void terra$setBlock(int x, int y, int z, BlockState data, boolean physics) { - setBlockState(new BlockPos(x, y, z), (net.minecraft.block.BlockState) data, false); - } - - public void terra$setBlock(int x, int y, int z, @NotNull BlockState blockState) { - ((net.minecraft.world.chunk.Chunk) (Object) this).setBlockState(new BlockPos(x, y, z), (net.minecraft.block.BlockState) blockState, - false); - } - - @Intrinsic - public @NotNull BlockState terra$getBlock(int x, int y, int z) { - return (BlockState) getBlockState(new BlockPos(x, y, z)); - } - - public int terra$getX() { - return ((net.minecraft.world.chunk.Chunk) (Object) this).getPos().x; - } - - public int terra$getZ() { - return ((net.minecraft.world.chunk.Chunk) (Object) this).getPos().z; - } - - public ServerWorld terra$getWorld() { - return (ServerWorld) world; - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java deleted file mode 100644 index afae72689..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.chunk.data; - -import com.dfsek.terra.api.block.state.BlockState; -import com.dfsek.terra.api.world.chunk.generation.ProtoChunk; - -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.HeightLimitView; -import org.jetbrains.annotations.NotNull; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - - -@Mixin(net.minecraft.world.chunk.ProtoChunk.class) -@Implements(@Interface(iface = ProtoChunk.class, prefix = "terra$")) -public abstract class ProtoChunkMixin { - @Shadow - public abstract net.minecraft.block.BlockState getBlockState(BlockPos pos); - - @Shadow - public abstract HeightLimitView getHeightLimitView(); - - public void terra$setBlock(int x, int y, int z, @NotNull BlockState blockState) { - ((net.minecraft.world.chunk.Chunk) (Object) this).setBlockState(new BlockPos(x, y, z), (net.minecraft.block.BlockState) blockState, - false); - } - - public @NotNull BlockState terra$getBlock(int x, int y, int z) { - return (BlockState) getBlockState(new BlockPos(x, y, z)); - } - - public int terra$getMaxHeight() { - return getHeightLimitView().getTopY(); - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/entity/EntityMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/entity/EntityMixin.java deleted file mode 100644 index beeaf0d57..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/entity/EntityMixin.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.entity; - -import net.minecraft.entity.Entity; -import net.minecraft.util.math.BlockPos; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import com.dfsek.terra.api.util.vector.Vector3; -import com.dfsek.terra.api.world.ServerWorld; -import com.dfsek.terra.fabric.util.FabricAdapter; - - -@Mixin(Entity.class) -@Implements(@Interface(iface = com.dfsek.terra.api.entity.Entity.class, prefix = "terra$")) -public abstract class EntityMixin { - @Shadow - public net.minecraft.world.World world; - - @Shadow - private BlockPos blockPos; - - @Shadow - public abstract void teleport(double destX, double destY, double destZ); - - public Vector3 terra$position() { - return FabricAdapter.adapt(blockPos); - } - - public void terra$position(Vector3 location) { - teleport(location.getX(), location.getY(), location.getZ()); - } - - public ServerWorld terra$world() { - return (ServerWorld) world; - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/entity/EntityTypeMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/entity/EntityTypeMixin.java deleted file mode 100644 index 27ea5a462..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/entity/EntityTypeMixin.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.entity; - -import net.minecraft.entity.EntityType; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; - - -@Mixin(EntityType.class) -@Implements(@Interface(iface = com.dfsek.terra.api.entity.EntityType.class, prefix = "terra$")) -public abstract class EntityTypeMixin { -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/entity/PlayerEntityMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/entity/PlayerEntityMixin.java deleted file mode 100644 index 8298cb4e7..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/entity/PlayerEntityMixin.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.entity; - -import net.minecraft.entity.player.PlayerEntity; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; - -import com.dfsek.terra.api.entity.Player; - - -@Mixin(PlayerEntity.class) -@Implements(@Interface(iface = Player.class, prefix = "terra$")) -public abstract class PlayerEntityMixin extends EntityMixin { -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/entity/ServerCommandSourceMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/entity/ServerCommandSourceMixin.java deleted file mode 100644 index a8fdb8958..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/entity/ServerCommandSourceMixin.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.entity; - -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.server.command.ServerCommandSource; -import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.text.Text; -import org.jetbrains.annotations.Nullable; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.Optional; - -import com.dfsek.terra.api.command.CommandSender; -import com.dfsek.terra.api.entity.Entity; -import com.dfsek.terra.api.entity.Player; - - -@Mixin(ServerCommandSource.class) -@Implements(@Interface(iface = CommandSender.class, prefix = "terra$")) -public abstract class ServerCommandSourceMixin { - @Shadow - public abstract void sendFeedback(Text message, boolean broadcastToOps); - - @Shadow - public abstract ServerPlayerEntity getPlayer() throws CommandSyntaxException; - - @Shadow - @Nullable - public abstract net.minecraft.entity.@Nullable Entity getEntity(); - - public void terra$sendMessage(String message) { - sendFeedback(Text.literal(message), true); - } - - @Nullable - public Optional terra$getEntity() { - return Optional.ofNullable((Entity) getEntity()); - } - - public Optional terra$getPlayer() { - try { - return Optional.ofNullable((Player) getPlayer()); - } catch(CommandSyntaxException e) { - return Optional.empty(); - } - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java deleted file mode 100644 index e888e511a..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.inventory; - -import net.minecraft.block.entity.LockableContainerBlockEntity; -import net.minecraft.item.Items; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; - -import com.dfsek.terra.api.inventory.Inventory; -import com.dfsek.terra.api.inventory.ItemStack; - - -@Mixin(LockableContainerBlockEntity.class) -@Implements(@Interface(iface = Inventory.class, prefix = "terra$")) -public class LockableContainerBlockEntityMixin { - @SuppressWarnings("ConstantConditions") - public void terra$setItem(int slot, ItemStack newStack) { - ((LockableContainerBlockEntity) (Object) this).setStack(slot, (net.minecraft.item.ItemStack) (Object) newStack); - } - - public int terra$getSize() { - return ((LockableContainerBlockEntity) (Object) this).size(); - } - - @SuppressWarnings("ConstantConditions") - public ItemStack terra$getItem(int slot) { - net.minecraft.item.ItemStack itemStack = ((LockableContainerBlockEntity) (Object) this).getStack(slot); - return itemStack.getItem() == Items.AIR ? null : (ItemStack) (Object) itemStack; - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/item/ItemMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/item/ItemMixin.java deleted file mode 100644 index 111aa95fa..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/item/ItemMixin.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.inventory.item; - -import net.minecraft.item.Item; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import com.dfsek.terra.api.inventory.ItemStack; - - -@Mixin(Item.class) -@Implements(@Interface(iface = com.dfsek.terra.api.inventory.Item.class, prefix = "terra$")) -public abstract class ItemMixin { - @Shadow - public abstract int getMaxDamage(); - - @SuppressWarnings("ConstantConditions") - public ItemStack terra$newItemStack(int amount) { - return (ItemStack) (Object) new net.minecraft.item.ItemStack((Item) (Object) this, amount); - } - - public double terra$getMaxDurability() { - return getMaxDamage(); - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/item/ItemStackMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/item/ItemStackMixin.java deleted file mode 100644 index 3dafd81be..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/item/ItemStackMixin.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.inventory.item; - -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import org.jetbrains.annotations.Nullable; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Intrinsic; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import com.dfsek.terra.api.inventory.Item; -import com.dfsek.terra.api.inventory.item.ItemMeta; - - -@Mixin(ItemStack.class) -@Implements(@Interface(iface = com.dfsek.terra.api.inventory.ItemStack.class, prefix = "terra$")) -public abstract class ItemStackMixin { - @Shadow - public abstract int getCount(); - - @Shadow - public abstract void setCount(int count); - - @Shadow - public abstract net.minecraft.item.Item getItem(); - - @Shadow - public abstract boolean isDamageable(); - - @Shadow - public abstract void setNbt(@Nullable NbtCompound tag); - - public int terra$getAmount() { - return getCount(); - } - - public void terra$setAmount(int i) { - setCount(i); - } - - public Item terra$getType() { - return (Item) getItem(); - } - - public ItemMeta terra$getItemMeta() { - return (ItemMeta) this; - } - - @SuppressWarnings("ConstantConditions") - public void terra$setItemMeta(ItemMeta meta) { - setNbt(((ItemStack) (Object) meta).getNbt()); - } - - @Intrinsic - public boolean terra$isDamageable() { - return isDamageable(); - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java deleted file mode 100644 index ddc2e6936..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.inventory.meta; - -import net.minecraft.enchantment.Enchantment; -import net.minecraft.util.registry.Registry; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.Objects; - -import com.dfsek.terra.api.inventory.ItemStack; - - -@Mixin(Enchantment.class) -@Implements(@Interface(iface = com.dfsek.terra.api.inventory.item.Enchantment.class, prefix = "terra$")) -public abstract class EnchantmentMixin { - @Shadow - public abstract boolean isAcceptableItem(net.minecraft.item.ItemStack stack); - - @Shadow - public abstract boolean canCombine(Enchantment other); - - @SuppressWarnings("ConstantConditions") - public boolean terra$canEnchantItem(ItemStack itemStack) { - return isAcceptableItem((net.minecraft.item.ItemStack) (Object) itemStack); - } - - public boolean terra$conflictsWith(com.dfsek.terra.api.inventory.item.Enchantment other) { - return !canCombine((Enchantment) other); - } - - public String terra$getID() { - return Objects.requireNonNull(Registry.ENCHANTMENT.getId((Enchantment) (Object) this)).toString(); - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java deleted file mode 100644 index 4749b8b4d..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.inventory.meta; - -import net.minecraft.item.ItemStack; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Intrinsic; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import com.dfsek.terra.api.inventory.item.Damageable; - - -@Mixin(ItemStack.class) -@Implements(@Interface(iface = Damageable.class, prefix = "terra$")) -public abstract class ItemStackDamageableMixin { - @Shadow - public abstract boolean isDamaged(); - - @Shadow - public abstract int getDamage(); - - @Shadow - public abstract void setDamage(int damage); - - @Intrinsic - public int terra$getDamage() { - return getDamage(); - } - - @Intrinsic - public void terra$setDamage(int damage) { - setDamage(damage); - } - - public boolean terra$hasDamage() { - return isDamaged(); - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java deleted file mode 100644 index 0fe8f7686..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra.inventory.meta; - -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtList; -import net.minecraft.util.registry.Registry; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Intrinsic; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -import com.dfsek.terra.api.inventory.item.Enchantment; -import com.dfsek.terra.api.inventory.item.ItemMeta; - - -@Mixin(ItemStack.class) -@Implements(@Interface(iface = ItemMeta.class, prefix = "terra$")) -public abstract class ItemStackMetaMixin { - @Shadow - public abstract boolean hasEnchantments(); - - @Shadow - public abstract NbtList getEnchantments(); - - @Shadow - public abstract void addEnchantment(net.minecraft.enchantment.Enchantment enchantment, int level); - - public void terra$addEnchantment(Enchantment enchantment, int level) { - addEnchantment((net.minecraft.enchantment.Enchantment) enchantment, level); - } - - @Intrinsic(displace = true) - public Map terra$getEnchantments() { - if(!hasEnchantments()) return Collections.emptyMap(); - Map map = new HashMap<>(); - - getEnchantments().forEach(enchantment -> { - NbtCompound eTag = (NbtCompound) enchantment; - map.put((Enchantment) Registry.ENCHANTMENT.get(eTag.getInt("id")), eTag.getInt("lvl")); - }); - return map; - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/package-info.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/package-info.java deleted file mode 100644 index 64552f11a..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/package-info.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -/** - * Mixins in this package implement Terra - * interfaces in Minecraft classes. - */ - -package com.dfsek.terra.fabric.mixin.implementations.terra; \ No newline at end of file diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin_ifaces/FloraFeatureHolder.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin_ifaces/FloraFeatureHolder.java deleted file mode 100644 index 5f4697d99..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin_ifaces/FloraFeatureHolder.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.dfsek.terra.fabric.mixin_ifaces; - -import net.minecraft.world.gen.feature.ConfiguredFeature; - -import java.util.List; - - -public interface FloraFeatureHolder { - void setFloraFeatures(List> features); -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/BiomeUtil.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/BiomeUtil.java index 421b321f4..678d7777a 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/BiomeUtil.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/BiomeUtil.java @@ -3,10 +3,13 @@ package com.dfsek.terra.fabric.util; import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.fabric.FabricEntryPoint; -import com.dfsek.terra.fabric.config.PreLoadCompatibilityOptions; -import com.dfsek.terra.fabric.config.VanillaBiomeProperties; +import com.dfsek.terra.mod.config.PreLoadCompatibilityOptions; +import com.dfsek.terra.mod.config.VanillaBiomeProperties; + +import com.dfsek.terra.mod.mixin_ifaces.FloraFeatureHolder; +import com.dfsek.terra.mod.config.ProtoPlatformBiome; +import com.dfsek.terra.mod.util.MinecraftUtil; -import com.dfsek.terra.fabric.mixin_ifaces.FloraFeatureHolder; import net.minecraft.util.Identifier; import net.minecraft.util.registry.BuiltinRegistries; import net.minecraft.util.registry.Registry; @@ -66,10 +69,10 @@ public final class BiomeUtil { Identifier identifier = new Identifier("terra", createBiomeID(pack, id)); if(registry.containsId(identifier)) { - ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(FabricUtil.getEntry(registry, identifier) - .orElseThrow() - .getKey() - .orElseThrow()); + ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(MinecraftUtil.getEntry(registry, identifier) + .orElseThrow() + .getKey() + .orElseThrow()); } else { ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(BuiltinRegistries.add(registry, registerKey(identifier).getValue(), diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricAdapter.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricAdapter.java deleted file mode 100644 index da6c3f6f8..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricAdapter.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.util; - -import net.minecraft.block.enums.BlockHalf; -import net.minecraft.block.enums.WallShape; -import net.minecraft.block.enums.WireConnection; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Direction; -import net.minecraft.world.HeightLimitView; - -import com.dfsek.terra.api.block.state.properties.enums.Axis; -import com.dfsek.terra.api.block.state.properties.enums.Half; -import com.dfsek.terra.api.block.state.properties.enums.RailShape; -import com.dfsek.terra.api.block.state.properties.enums.RedstoneConnection; -import com.dfsek.terra.api.block.state.properties.enums.WallHeight; -import com.dfsek.terra.api.util.vector.Vector3; -import com.dfsek.terra.api.world.info.WorldProperties; - - -public final class FabricAdapter { - public static BlockPos adapt(Vector3 v) { - return new BlockPos(v.getBlockX(), v.getBlockY(), v.getBlockZ()); - } - - public static Vector3 adapt(BlockPos pos) { - return Vector3.of(pos.getX(), pos.getY(), pos.getZ()); - } - - public static Direction adapt(com.dfsek.terra.api.block.state.properties.enums.Direction direction) { - return switch(direction) { - case SOUTH -> Direction.SOUTH; - case NORTH -> Direction.NORTH; - case WEST -> Direction.WEST; - case EAST -> Direction.EAST; - case UP -> Direction.UP; - case DOWN -> Direction.DOWN; - }; - } - - public static WorldProperties adapt(HeightLimitView height, long seed) { - return new WorldProperties() { - @Override - public long getSeed() { - return seed; - } - - @Override - public int getMaxHeight() { - return height.getTopY(); - } - - @Override - public int getMinHeight() { - return height.getBottomY(); - } - - @Override - public Object getHandle() { - return height; - } - }; - } - - public static com.dfsek.terra.api.block.state.properties.enums.Direction adapt(Direction direction) { - return switch(direction) { - case SOUTH -> com.dfsek.terra.api.block.state.properties.enums.Direction.SOUTH; - case NORTH -> com.dfsek.terra.api.block.state.properties.enums.Direction.NORTH; - case WEST -> com.dfsek.terra.api.block.state.properties.enums.Direction.WEST; - case EAST -> com.dfsek.terra.api.block.state.properties.enums.Direction.EAST; - case UP -> com.dfsek.terra.api.block.state.properties.enums.Direction.UP; - case DOWN -> com.dfsek.terra.api.block.state.properties.enums.Direction.DOWN; - }; - } - - public static WallHeight adapt(WallShape shape) { - return switch(shape) { - case LOW -> WallHeight.LOW; - case NONE -> WallHeight.NONE; - case TALL -> WallHeight.TALL; - }; - } - - public static WallShape adapt(WallHeight shape) { - return switch(shape) { - case LOW -> WallShape.LOW; - case NONE -> WallShape.NONE; - case TALL -> WallShape.TALL; - }; - } - - public static RedstoneConnection adapt(WireConnection connection) { - return switch(connection) { - case NONE -> RedstoneConnection.NONE; - case UP -> RedstoneConnection.UP; - case SIDE -> RedstoneConnection.SIDE; - }; - } - - public static WireConnection adapt(RedstoneConnection connection) { - return switch(connection) { - case NONE -> WireConnection.NONE; - case UP -> WireConnection.UP; - case SIDE -> WireConnection.SIDE; - }; - } - - - public static Half adapt(BlockHalf half) { - return switch(half) { - case BOTTOM -> Half.BOTTOM; - case TOP -> Half.TOP; - }; - } - - public static BlockHalf adapt(Half half) { - return switch(half) { - case TOP -> BlockHalf.TOP; - case BOTTOM -> BlockHalf.BOTTOM; - default -> throw new IllegalStateException(); - }; - } - - public static RailShape adapt(net.minecraft.block.enums.RailShape railShape) { - return switch(railShape) { - case EAST_WEST -> RailShape.EAST_WEST; - case NORTH_EAST -> RailShape.NORTH_EAST; - case NORTH_WEST -> RailShape.NORTH_WEST; - case SOUTH_EAST -> RailShape.SOUTH_EAST; - case SOUTH_WEST -> RailShape.SOUTH_WEST; - case NORTH_SOUTH -> RailShape.NORTH_SOUTH; - case ASCENDING_EAST -> RailShape.ASCENDING_EAST; - case ASCENDING_NORTH -> RailShape.ASCENDING_NORTH; - case ASCENDING_SOUTH -> RailShape.ASCENDING_SOUTH; - case ASCENDING_WEST -> RailShape.ASCENDING_WEST; - }; - } - - public static net.minecraft.block.enums.RailShape adapt(RailShape railShape) { - return switch(railShape) { - case EAST_WEST -> net.minecraft.block.enums.RailShape.EAST_WEST; - case NORTH_EAST -> net.minecraft.block.enums.RailShape.NORTH_EAST; - case NORTH_WEST -> net.minecraft.block.enums.RailShape.NORTH_WEST; - case SOUTH_EAST -> net.minecraft.block.enums.RailShape.SOUTH_EAST; - case SOUTH_WEST -> net.minecraft.block.enums.RailShape.SOUTH_WEST; - case NORTH_SOUTH -> net.minecraft.block.enums.RailShape.NORTH_SOUTH; - case ASCENDING_EAST -> net.minecraft.block.enums.RailShape.ASCENDING_EAST; - case ASCENDING_NORTH -> net.minecraft.block.enums.RailShape.ASCENDING_NORTH; - case ASCENDING_SOUTH -> net.minecraft.block.enums.RailShape.ASCENDING_SOUTH; - case ASCENDING_WEST -> net.minecraft.block.enums.RailShape.ASCENDING_WEST; - }; - } - - - public static Axis adapt(Direction.Axis axis) { - return switch(axis) { - case X -> Axis.X; - case Y -> Axis.Y; - case Z -> Axis.Z; - }; - } - - public static Direction.Axis adapt(Axis axis) { - return switch(axis) { - case Z -> Direction.Axis.Z; - case Y -> Direction.Axis.Y; - case X -> Direction.Axis.X; - }; - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricUtil.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricUtil.java deleted file mode 100644 index 7e00aa900..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/FabricUtil.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.fabric.util; - -import net.minecraft.block.entity.LootableContainerBlockEntity; -import net.minecraft.block.entity.MobSpawnerBlockEntity; -import net.minecraft.block.entity.SignBlockEntity; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.registry.Registry; -import net.minecraft.util.registry.RegistryEntry; -import net.minecraft.world.WorldAccess; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Optional; - -import com.dfsek.terra.api.block.entity.BlockEntity; -import com.dfsek.terra.api.block.entity.Container; -import com.dfsek.terra.api.block.entity.MobSpawner; -import com.dfsek.terra.api.block.entity.Sign; - - -public final class FabricUtil { - private FabricUtil() { - - } - - public static BlockEntity createState(WorldAccess worldAccess, BlockPos pos) { - net.minecraft.block.entity.BlockEntity entity = worldAccess.getBlockEntity(pos); - if(entity instanceof SignBlockEntity) { - return (Sign) entity; - } else if(entity instanceof MobSpawnerBlockEntity) { - return (MobSpawner) entity; - } else if(entity instanceof LootableContainerBlockEntity) { - return (Container) entity; - } - return null; - } - - public static Optional> getEntry(Registry registry, Identifier identifier) { - return registry.getOrEmpty(identifier) - .flatMap(registry::getKey) - .map(registry::getOrCreateEntry); - } -} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/LifecycleUtil.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/LifecycleUtil.java index 2e935d889..d91d4e263 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/LifecycleUtil.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/LifecycleUtil.java @@ -2,8 +2,8 @@ package com.dfsek.terra.fabric.util; import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; import com.dfsek.terra.fabric.FabricEntryPoint; -import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper; -import com.dfsek.terra.fabric.generation.TerraBiomeSource; +import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; +import com.dfsek.terra.mod.generation.TerraBiomeSource; import net.minecraft.structure.StructureSet; import net.minecraft.util.Identifier; @@ -78,7 +78,7 @@ public class LifecycleUtil { PRESETS.add(generatorID); TerraBiomeSource biomeSource = new TerraBiomeSource(biomeRegistry, pack); - ChunkGenerator generator = new FabricChunkGeneratorWrapper(structureSetRegistry, biomeSource, pack, overworld); + ChunkGenerator generator = new MinecraftChunkGeneratorWrapper(structureSetRegistry, biomeSource, pack, overworld); DimensionOptions dimensionOptions = new DimensionOptions(overworldDimensionType, generator); WorldPreset preset = new WorldPreset( diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java index 7a52ff376..78759c4f4 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java @@ -1,5 +1,7 @@ package com.dfsek.terra.fabric.util; +import com.dfsek.terra.mod.util.MinecraftUtil; + import com.google.common.collect.ImmutableMap; import net.minecraft.tag.TagKey; import net.minecraft.tag.WorldPresetTags; @@ -38,7 +40,7 @@ public final class TagUtil { LifecycleUtil .getPresets() - .forEach(id -> FabricUtil + .forEach(id -> MinecraftUtil .getEntry(registry, id) .ifPresentOrElse( preset -> collect @@ -57,11 +59,11 @@ public final class TagUtil { BiomeUtil .getTerraBiomeMap() .forEach((vb, terraBiomes) -> - FabricUtil + MinecraftUtil .getEntry(registry, vb) .ifPresentOrElse( vanilla -> terraBiomes - .forEach(tb -> FabricUtil + .forEach(tb -> MinecraftUtil .getEntry(registry, tb) .ifPresentOrElse( terra -> { diff --git a/platforms/fabric/src/main/resources/terra.fabric.mixins.json b/platforms/fabric/src/main/resources/terra.fabric.mixins.json index f18482bf5..d28c0541c 100644 --- a/platforms/fabric/src/main/resources/terra.fabric.mixins.json +++ b/platforms/fabric/src/main/resources/terra.fabric.mixins.json @@ -4,33 +4,6 @@ "package": "com.dfsek.terra.fabric.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ - "fix.BeeMoveGoalsUnsynchronizedRandomAccessFix", - "fix.NetherFossilOptimization", - "implementations.compat.GenerationSettingsFloraFeaturesMixin", - "implementations.terra.BiomeMixin", - "implementations.terra.HandleImplementationMixin", - "implementations.terra.block.BlockMixin", - "implementations.terra.block.entity.BlockEntityMixin", - "implementations.terra.block.entity.LootableContainerBlockEntityMixin", - "implementations.terra.block.entity.MobSpawnerBlockEntityMixin", - "implementations.terra.block.entity.SignBlockEntityMixin", - "implementations.terra.block.state.BlockStateMixin", - "implementations.terra.block.state.PropertyMixin", - "implementations.terra.chunk.ChunkRegionMixin", - "implementations.terra.chunk.WorldChunkMixin", - "implementations.terra.chunk.data.ProtoChunkMixin", - "implementations.terra.entity.EntityMixin", - "implementations.terra.entity.EntityTypeMixin", - "implementations.terra.entity.PlayerEntityMixin", - "implementations.terra.entity.ServerCommandSourceMixin", - "implementations.terra.inventory.LockableContainerBlockEntityMixin", - "implementations.terra.inventory.item.ItemMixin", - "implementations.terra.inventory.item.ItemStackMixin", - "implementations.terra.inventory.meta.EnchantmentMixin", - "implementations.terra.inventory.meta.ItemStackDamageableMixin", - "implementations.terra.inventory.meta.ItemStackMetaMixin", - "implementations.terra.world.ChunkRegionMixin", - "implementations.terra.world.ServerWorldMixin", "lifecycle.DataPackContentsMixin", "lifecycle.MinecraftServerMixin", "lifecycle.NoiseConfigMixin", diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeAddon.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeAddon.java deleted file mode 100644 index 499ae6533..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeAddon.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.forge; - -import ca.solostudios.strata.Versions; -import ca.solostudios.strata.version.Version; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.dfsek.terra.api.addon.BaseAddon; -import com.dfsek.terra.api.event.events.config.ConfigurationLoadEvent; -import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent; -import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; -import com.dfsek.terra.api.event.functional.FunctionalEventHandler; -import com.dfsek.terra.api.world.biome.Biome; -import com.dfsek.terra.forge.config.PostLoadCompatibilityOptions; -import com.dfsek.terra.forge.config.PreLoadCompatibilityOptions; -import com.dfsek.terra.forge.config.VanillaBiomeProperties; - - -public final class ForgeAddon implements BaseAddon { - private static final Version VERSION = Versions.getVersion(1, 0, 0); - private static final Logger logger = LoggerFactory.getLogger(ForgeAddon.class); - private final PlatformImpl terraForgePlugin; - - public ForgeAddon(PlatformImpl terraForgePlugin) { - this.terraForgePlugin = terraForgePlugin; - } - - @Override - public void initialize() { - terraForgePlugin.getEventManager() - .getHandler(FunctionalEventHandler.class) - .register(this, ConfigPackPreLoadEvent.class) - .then(event -> event.getPack().getContext().put(event.loadTemplate(new PreLoadCompatibilityOptions()))) - .global(); - - terraForgePlugin.getEventManager() - .getHandler(FunctionalEventHandler.class) - .register(this, ConfigPackPostLoadEvent.class) - .then(event -> event.getPack().getContext().put(event.loadTemplate(new PostLoadCompatibilityOptions()))) - .priority(100) - .global(); - - terraForgePlugin.getEventManager() - .getHandler(FunctionalEventHandler.class) - .register(this, ConfigurationLoadEvent.class) - .then(event -> { - if(event.is(Biome.class)) { - event.getLoadedObject(Biome.class).getContext().put(event.load(new VanillaBiomeProperties())); - } - }) - .global(); - } - - @Override - public Version getVersion() { - return VERSION; - } - - @Override - public String getID() { - return "terra-forge"; - } -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java index e8f701fd0..5208f01ec 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java @@ -17,9 +17,6 @@ package com.dfsek.terra.forge; -import com.dfsek.terra.forge.AwfulForgeHacks.RegistrySanityCheck; -import com.dfsek.terra.forge.AwfulForgeHacks.RegistryStep; - import net.minecraft.util.Identifier; import net.minecraft.util.registry.Registry; import net.minecraftforge.eventbus.api.EventPriority; @@ -34,8 +31,10 @@ import net.minecraftforge.registries.RegisterEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.dfsek.terra.forge.data.Codecs; +import com.dfsek.terra.forge.AwfulForgeHacks.RegistrySanityCheck; +import com.dfsek.terra.forge.AwfulForgeHacks.RegistryStep; import com.dfsek.terra.forge.util.LifecycleUtil; +import com.dfsek.terra.mod.data.Codecs; @Mod("terra") @@ -70,7 +69,7 @@ public class ForgeEntryPoint { event.register(Registry.WORLD_PRESET_KEY, helper -> sanityCheck.progress(RegistryStep.WORLD_TYPE, () -> LifecycleUtil.registerWorldTypes(helper))); - event.register(Registry.CHUNK_GENERATOR_KEY, helper -> helper.register(new Identifier("terra:terra"), Codecs.FORGE_CHUNK_GENERATOR_WRAPPER)); + event.register(Registry.CHUNK_GENERATOR_KEY, helper -> helper.register(new Identifier("terra:terra"), Codecs.MINECRAFT_CHUNK_GENERATOR_WRAPPER)); event.register(Registry.BIOME_SOURCE_KEY, helper -> helper.register(new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE)); } } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java index 2b414715a..294fa01d9 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java @@ -20,15 +20,8 @@ package com.dfsek.terra.forge; import ca.solostudios.strata.Versions; import ca.solostudios.strata.parser.tokenizer.ParseException; import ca.solostudios.strata.version.Version; -import com.dfsek.tectonic.api.TypeRegistry; -import com.dfsek.tectonic.api.depth.DepthTracker; -import com.dfsek.tectonic.api.exception.LoadException; import net.minecraft.MinecraftVersion; import net.minecraft.server.MinecraftServer; -import net.minecraft.util.Identifier; -import net.minecraft.util.registry.BuiltinRegistries; -import net.minecraft.world.biome.Biome.Precipitation; -import net.minecraft.world.biome.BiomeEffects.GrassColorModifier; import net.minecraftforge.fml.loading.FMLLoader; import net.minecraftforge.server.ServerLifecycleHooks; import org.jetbrains.annotations.NotNull; @@ -38,31 +31,31 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.util.ArrayList; import java.util.List; -import java.util.Locale; -import com.dfsek.terra.AbstractPlatform; import com.dfsek.terra.addon.EphemeralAddon; import com.dfsek.terra.api.addon.BaseAddon; import com.dfsek.terra.api.handle.ItemHandle; import com.dfsek.terra.api.handle.WorldHandle; import com.dfsek.terra.api.util.generic.Lazy; -import com.dfsek.terra.api.world.biome.PlatformBiome; -import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper; -import com.dfsek.terra.forge.handle.ForgeItemHandle; -import com.dfsek.terra.forge.util.ProtoPlatformBiome; +import com.dfsek.terra.mod.CommonPlatform; +import com.dfsek.terra.mod.ModPlatform; +import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; +import com.dfsek.terra.mod.handle.MinecraftItemHandle; import com.dfsek.terra.mod.handle.MinecraftWorldHandle; -public class PlatformImpl extends AbstractPlatform { +public class PlatformImpl extends ModPlatform { private static final Logger LOGGER = LoggerFactory.getLogger(PlatformImpl.class); - private final ItemHandle itemHandle = new ForgeItemHandle(); + private final ItemHandle itemHandle = new MinecraftItemHandle(); private final WorldHandle worldHandle = new MinecraftWorldHandle(); private final Lazy dataFolder = Lazy.lazy(() -> new File("./config/Terra")); public PlatformImpl() { + CommonPlatform.initialize(this); load(); } + @Override public MinecraftServer getServer() { return ServerLifecycleHooks.getCurrentServer(); } @@ -82,7 +75,7 @@ public class PlatformImpl extends AbstractPlatform { }).join(); //BiomeUtil.registerBiomes(); server.getWorlds().forEach(world -> { - if(world.getChunkManager().getChunkGenerator() instanceof ForgeChunkGeneratorWrapper chunkGeneratorWrapper) { + if(world.getChunkManager().getChunkGenerator() instanceof MinecraftChunkGeneratorWrapper chunkGeneratorWrapper) { getConfigRegistry().get(chunkGeneratorWrapper.getPack().getRegistryKey()).ifPresent(pack -> { chunkGeneratorWrapper.setPack(pack); LOGGER.info("Replaced pack in chunk generator for world {}", world); @@ -96,8 +89,8 @@ public class PlatformImpl extends AbstractPlatform { @Override protected Iterable platformAddon() { List addons = new ArrayList<>(); - - addons.add(new ForgeAddon(this)); + + super.platformAddon().forEach(addons::add); String mcVersion = MinecraftVersion.CURRENT.getReleaseTarget(); try { @@ -139,27 +132,4 @@ public class PlatformImpl extends AbstractPlatform { public @NotNull ItemHandle getItemHandle() { return itemHandle; } - - @Override - public void register(TypeRegistry registry) { - super.register(registry); - registry.registerLoader(PlatformBiome.class, (type, o, loader, depthTracker) -> parseBiome((String) o, depthTracker)) - .registerLoader(Identifier.class, (type, o, loader, depthTracker) -> { - Identifier identifier = Identifier.tryParse((String) o); - if(identifier == null) - throw new LoadException("Invalid identifier: " + o, depthTracker); - return identifier; - }) - .registerLoader(Precipitation.class, (type, o, loader, depthTracker) -> Precipitation.valueOf(((String) o).toUpperCase( - Locale.ROOT))) - .registerLoader(GrassColorModifier.class, (type, o, loader, depthTracker) -> GrassColorModifier.valueOf(((String) o).toUpperCase( - Locale.ROOT))); - } - - - private ProtoPlatformBiome parseBiome(String id, DepthTracker tracker) throws LoadException { - Identifier identifier = Identifier.tryParse(id); - if(BuiltinRegistries.BIOME.get(identifier) == null) throw new LoadException("Invalid Biome ID: " + identifier, tracker); // failure. - return new ProtoPlatformBiome(identifier); - } } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/config/PreLoadCompatibilityOptions.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/config/PreLoadCompatibilityOptions.java deleted file mode 100644 index 1b8acf3ae..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/config/PreLoadCompatibilityOptions.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.forge.config; - -import com.dfsek.tectonic.api.config.template.ConfigTemplate; -import com.dfsek.tectonic.api.config.template.annotations.Default; -import com.dfsek.tectonic.api.config.template.annotations.Value; - -import com.dfsek.terra.api.properties.Properties; - - -@SuppressWarnings("FieldMayBeFinal") -public class PreLoadCompatibilityOptions implements ConfigTemplate, Properties { - @Value("forge.use-vanilla-biomes") - @Default - private boolean vanillaBiomes = false; - - @Value("forge.beard.enable") - @Default - private boolean beard = true; - - @Value("forge.beard.threshold") - @Default - private double beardThreshold = 0.5; - - @Value("forge.beard.air-threshold") - @Default - private double airThreshold = -0.5; - - public boolean useVanillaBiomes() { - return vanillaBiomes; - } - - public boolean isBeard() { - return beard; - } - - public double getBeardThreshold() { - return beardThreshold; - } - - public double getAirThreshold() { - return airThreshold; - } -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/data/Codecs.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/data/Codecs.java deleted file mode 100644 index f30006e12..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/data/Codecs.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.dfsek.terra.forge.data; - -import com.dfsek.terra.api.config.ConfigPack; -import com.dfsek.terra.api.registry.key.RegistryKey; -import com.dfsek.terra.forge.ForgeEntryPoint; -import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper; -import com.dfsek.terra.forge.generation.TerraBiomeSource; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.minecraft.util.dynamic.RegistryOps; -import net.minecraft.util.registry.Registry; -import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; - - -public final class Codecs { - public static final Codec TERRA_REGISTRY_KEY = RecordCodecBuilder - .create(registryKey -> registryKey.group(Codec.STRING.fieldOf("namespace") - .stable() - .forGetter(RegistryKey::getNamespace), - Codec.STRING.fieldOf("id") - .stable() - .forGetter(RegistryKey::getID)) - .apply(registryKey, registryKey.stable(RegistryKey::of))); - - public static final Codec CONFIG_PACK = RecordCodecBuilder - .create(config -> config.group(TERRA_REGISTRY_KEY.fieldOf("pack") - .stable() - .forGetter(ConfigPack::getRegistryKey)) - .apply(config, config.stable(id -> ForgeEntryPoint.getPlatform() - .getConfigRegistry() - .get(id) - .orElseThrow(() -> new IllegalArgumentException( - "No such config pack " + - id))))); - - public static final Codec TERRA_BIOME_SOURCE = RecordCodecBuilder - .create(instance -> instance.group(RegistryOps.createRegistryCodec(Registry.BIOME_KEY) - .fieldOf("biome_registry") - .stable() - .forGetter(TerraBiomeSource::getBiomeRegistry), - CONFIG_PACK.fieldOf("pack") - .stable() - .forGetter(TerraBiomeSource::getPack)) - .apply(instance, instance.stable(TerraBiomeSource::new))); - - public static final Codec FORGE_CHUNK_GENERATOR_WRAPPER = RecordCodecBuilder - .create( - instance -> instance.group( - RegistryOps.createRegistryCodec(Registry.STRUCTURE_SET_KEY) - .fieldOf("structure_registry") - .stable() - .forGetter(ForgeChunkGeneratorWrapper::getNoiseRegistry), - TERRA_BIOME_SOURCE.fieldOf("biome_source") - .stable() - .forGetter(ForgeChunkGeneratorWrapper::getBiomeSource), - CONFIG_PACK.fieldOf("pack") - .stable() - .forGetter(ForgeChunkGeneratorWrapper::getPack), - ChunkGeneratorSettings.REGISTRY_CODEC.fieldOf("settings") - .stable() - .forGetter(ForgeChunkGeneratorWrapper::getSettings) - ).apply(instance, instance.stable(ForgeChunkGeneratorWrapper::new)) - ); -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/ForgeChunkGeneratorWrapper.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/ForgeChunkGeneratorWrapper.java deleted file mode 100644 index ce649eba0..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/ForgeChunkGeneratorWrapper.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.forge.generation; - -import com.mojang.serialization.Codec; -import net.minecraft.block.BlockState; -import net.minecraft.block.Blocks; -import net.minecraft.structure.StructureSet; -import net.minecraft.util.Util; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.util.math.random.CheckedRandom; -import net.minecraft.util.math.random.ChunkRandom; -import net.minecraft.util.math.random.RandomSeed; -import net.minecraft.util.registry.Registry; -import net.minecraft.util.registry.RegistryEntry; -import net.minecraft.world.ChunkRegion; -import net.minecraft.world.HeightLimitView; -import net.minecraft.world.Heightmap.Type; -import net.minecraft.world.SpawnHelper; -import net.minecraft.world.StructureWorldAccess; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.biome.source.BiomeAccess; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.gen.GenerationStep.Carver; -import net.minecraft.world.gen.StructureAccessor; -import net.minecraft.world.gen.StructureWeightSampler; -import net.minecraft.world.gen.chunk.Blender; -import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; -import net.minecraft.world.gen.chunk.VerticalBlockSample; -import net.minecraft.world.gen.densityfunction.DensityFunction.UnblendedNoisePos; -import net.minecraft.world.gen.noise.NoiseConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; - -import com.dfsek.terra.api.config.ConfigPack; -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.ProtoChunk; -import com.dfsek.terra.api.world.chunk.generation.ProtoWorld; -import com.dfsek.terra.api.world.chunk.generation.stage.Chunkified; -import com.dfsek.terra.api.world.chunk.generation.util.GeneratorWrapper; -import com.dfsek.terra.api.world.info.WorldProperties; -import com.dfsek.terra.forge.config.PreLoadCompatibilityOptions; -import com.dfsek.terra.forge.data.Codecs; -import com.dfsek.terra.forge.mixin.access.StructureAccessorAccessor; -import com.dfsek.terra.forge.util.ForgeAdapter; - - -public class ForgeChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.ChunkGenerator implements GeneratorWrapper { - private static final Logger logger = LoggerFactory.getLogger(ForgeChunkGeneratorWrapper.class); - - private final TerraBiomeSource biomeSource; - private final Registry noiseRegistry; - private final RegistryEntry settings; - private ChunkGenerator delegate; - private ConfigPack pack; - - public ForgeChunkGeneratorWrapper(Registry noiseRegistry, TerraBiomeSource biomeSource, ConfigPack configPack, - RegistryEntry settingsSupplier) { - super(noiseRegistry, Optional.empty(), biomeSource); - this.noiseRegistry = noiseRegistry; - this.pack = configPack; - this.settings = settingsSupplier; - - this.delegate = pack.getGeneratorProvider().newInstance(pack); - logger.info("Loading world with config pack {}", pack.getID()); - this.biomeSource = biomeSource; - } - - public Registry getNoiseRegistry() { - return noiseRegistry; - } - - @Override - protected Codec getCodec() { - return Codecs.FORGE_CHUNK_GENERATOR_WRAPPER; - } - - @Override - public void buildSurface(ChunkRegion region, StructureAccessor structures, NoiseConfig noiseConfig, Chunk chunk) { - // no op - } - - @Override - public void populateEntities(ChunkRegion region) { - if(!this.settings.value().mobGenerationDisabled()) { - ChunkPos chunkPos = region.getCenterPos(); - RegistryEntry registryEntry = region.getBiome(chunkPos.getStartPos().withY(region.getTopY() - 1)); - ChunkRandom chunkRandom = new ChunkRandom(new CheckedRandom(RandomSeed.getSeed())); - chunkRandom.setPopulationSeed(region.getSeed(), chunkPos.getStartX(), chunkPos.getStartZ()); - SpawnHelper.populateEntities(region, registryEntry, chunkPos, chunkRandom); - } - } - - @Override - public int getWorldHeight() { - return settings.value().generationShapeConfig().height(); - } - - - @Override - public CompletableFuture populateNoise(Executor executor, Blender blender, NoiseConfig noiseConfig, - StructureAccessor structureAccessor, Chunk chunk) { - return CompletableFuture.supplyAsync(() -> { - ProtoWorld world = (ProtoWorld) ((StructureAccessorAccessor) structureAccessor).getWorld(); - BiomeProvider biomeProvider = pack.getBiomeProvider(); - delegate.generateChunkData((ProtoChunk) chunk, world, biomeProvider, chunk.getPos().x, chunk.getPos().z); - - PreLoadCompatibilityOptions compatibilityOptions = pack.getContext().get(PreLoadCompatibilityOptions.class); - if(compatibilityOptions.isBeard()) { - beard(structureAccessor, chunk, world, biomeProvider, compatibilityOptions); - } - return chunk; - }, Util.getMainWorkerExecutor()); - } - - private void beard(StructureAccessor structureAccessor, Chunk chunk, WorldProperties world, BiomeProvider biomeProvider, - PreLoadCompatibilityOptions compatibilityOptions) { - StructureWeightSampler structureWeightSampler = StructureWeightSampler.method_42695(structureAccessor, chunk.getPos()); - double threshold = compatibilityOptions.getBeardThreshold(); - double airThreshold = compatibilityOptions.getAirThreshold(); - int xi = chunk.getPos().x << 4; - int zi = chunk.getPos().z << 4; - for(int x = 0; x < 16; x++) { - for(int z = 0; z < 16; z++) { - int depth = 0; - for(int y = world.getMaxHeight(); y >= world.getMinHeight(); y--) { - double noise = structureWeightSampler.sample(new UnblendedNoisePos(x + xi, y, z + zi)); - if(noise > threshold) { - chunk.setBlockState(new BlockPos(x, y, z), (BlockState) delegate - .getPalette(x + xi, y, z + zi, world, biomeProvider) - .get(depth, x + xi, y, z + zi, world.getSeed()), false); - depth++; - } else if(noise < airThreshold) { - chunk.setBlockState(new BlockPos(x, y, z), Blocks.AIR.getDefaultState(), false); - } else { - depth = 0; - } - } - } - } - } - - @Override - public void generateFeatures(StructureWorldAccess world, Chunk chunk, StructureAccessor structureAccessor) { - super.generateFeatures(world, chunk, structureAccessor); - pack.getStages().forEach(populator -> { - if(!(populator instanceof Chunkified)) { - populator.populate((ProtoWorld) world); - } - }); - } - - @Override - public int getSeaLevel() { - return settings.value().seaLevel(); - } - - @Override - public int getMinimumY() { - return settings.value().generationShapeConfig().minimumY(); - } - - - @Override - public int getHeight(int x, int z, Type heightmap, HeightLimitView height, NoiseConfig noiseConfig) { - WorldProperties properties = ForgeAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); - BiomeProvider biomeProvider = pack.getBiomeProvider(); - int min = height.getBottomY(); - for(int y = height.getTopY() - 1; y >= min; y--) { - if(heightmap - .getBlockPredicate() - .test((BlockState) delegate.getBlock(properties, x, y, z, biomeProvider))) return y + 1; - } - return min; - } - - @Override - public VerticalBlockSample getColumnSample(int x, int z, HeightLimitView height, NoiseConfig noiseConfig) { - BlockState[] array = new BlockState[height.getHeight()]; - WorldProperties properties = ForgeAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); - BiomeProvider biomeProvider = pack.getBiomeProvider(); - for(int y = height.getTopY() - 1; y >= height.getBottomY(); y--) { - array[y - height.getBottomY()] = (BlockState) delegate.getBlock(properties, x, y, z, biomeProvider); - } - return new VerticalBlockSample(height.getBottomY(), array); - } - - @Override - public void getDebugHudText(List text, NoiseConfig noiseConfig, BlockPos pos) { - - } - - public ConfigPack getPack() { - return pack; - } - - public void setPack(ConfigPack pack) { - this.pack = pack; - this.delegate = pack.getGeneratorProvider().newInstance(pack); - biomeSource.setPack(pack); - - logger.debug("Loading world with config pack {}", pack.getID()); - } - - @Override - public void carve(ChunkRegion chunkRegion, long seed, NoiseConfig noiseConfig, BiomeAccess world, StructureAccessor structureAccessor, - Chunk chunk, Carver carverStep) { - // no op - } - - @Override - public ChunkGenerator getHandle() { - return delegate; - } - - public RegistryEntry getSettings() { - return settings; - } - - @Override - public TerraBiomeSource getBiomeSource() { - return biomeSource; - } -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/TerraBiomeSource.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/TerraBiomeSource.java deleted file mode 100644 index b43b38ce8..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/generation/TerraBiomeSource.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.forge.generation; - -import com.dfsek.terra.api.config.ConfigPack; -import com.dfsek.terra.api.world.biome.generation.BiomeProvider; -import com.dfsek.terra.forge.data.Codecs; -import com.dfsek.terra.forge.util.ProtoPlatformBiome; - -import com.dfsek.terra.forge.util.SeedHack; - -import com.mojang.serialization.Codec; -import net.minecraft.util.registry.Registry; -import net.minecraft.util.registry.RegistryEntry; -import net.minecraft.world.biome.source.BiomeSource; -import net.minecraft.world.biome.source.util.MultiNoiseUtil.MultiNoiseSampler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.stream.StreamSupport; - - -public class TerraBiomeSource extends BiomeSource { - - private static final Logger LOGGER = LoggerFactory.getLogger(TerraBiomeSource.class); - private final Registry biomeRegistry; - private ConfigPack pack; - - public TerraBiomeSource(Registry biomes, ConfigPack pack) { - super(StreamSupport - .stream(pack.getBiomeProvider() - .getBiomes() - .spliterator(), false) - .map(b -> biomes.getOrCreateEntry(((ProtoPlatformBiome) b.getPlatformBiome()).getDelegate()))); - this.biomeRegistry = biomes; - this.pack = pack; - - LOGGER.debug("Biomes: " + getBiomes()); - } - - @Override - protected Codec getCodec() { - return Codecs.TERRA_BIOME_SOURCE; - } - - @Override - public RegistryEntry getBiome(int biomeX, int biomeY, int biomeZ, MultiNoiseSampler noiseSampler) { - return biomeRegistry - .entryOf(((ProtoPlatformBiome) pack - .getBiomeProvider() - .getBiome(biomeX << 2, biomeY << 2, biomeZ << 2, SeedHack.getSeed(noiseSampler)) - .getPlatformBiome()).getDelegate() - ); - } - - public BiomeProvider getProvider() { - return pack.getBiomeProvider(); - } - - public Registry getBiomeRegistry() { - return biomeRegistry; - } - - public ConfigPack getPack() { - return pack; - } - - public void setPack(ConfigPack pack) { - this.pack = pack; - } -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/MobSpawnerLogicAccessor.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/MobSpawnerLogicAccessor.java deleted file mode 100644 index 20a900005..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/MobSpawnerLogicAccessor.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.forge.mixin.access; - -import net.minecraft.world.MobSpawnerEntry; -import net.minecraft.world.MobSpawnerLogic; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - - -@Mixin(MobSpawnerLogic.class) -public interface MobSpawnerLogicAccessor { - @Accessor("spawnEntry") - MobSpawnerEntry getSpawnEntry(); -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/StateAccessor.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/StateAccessor.java deleted file mode 100644 index 947118da9..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/StateAccessor.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.forge.mixin.access; - -import net.minecraft.state.State; -import net.minecraft.state.property.Property; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -import java.util.Map; -import java.util.function.Function; - - -@Mixin(State.class) -public interface StateAccessor { - @Accessor("PROPERTY_MAP_PRINTER") - static Function, Comparable>, String> getPropertyMapPrinter() { - throw new UnsupportedOperationException(); - } -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/StructureAccessorAccessor.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/StructureAccessorAccessor.java deleted file mode 100644 index 12ca75c9d..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/access/StructureAccessorAccessor.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.forge.mixin.access; - -import net.minecraft.world.WorldAccess; -import net.minecraft.world.gen.StructureAccessor; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - - -@Mixin(StructureAccessor.class) -public interface StructureAccessorAccessor { - @Accessor - WorldAccess getWorld(); -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java deleted file mode 100644 index 60bafaefb..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.forge.mixin.implementations.terra.block.entity; - -import com.dfsek.terra.forge.ForgeEntryPoint; -import com.dfsek.terra.forge.mixin.access.MobSpawnerLogicAccessor; -import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; -import net.minecraft.block.entity.BlockEntityType; -import net.minecraft.block.entity.MobSpawnerBlockEntity; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.registry.Registry; -import net.minecraft.world.MobSpawnerLogic; -import org.jetbrains.annotations.NotNull; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import com.dfsek.terra.api.block.entity.MobSpawner; -import com.dfsek.terra.api.block.entity.SerialState; -import com.dfsek.terra.api.entity.EntityType; - - -@Mixin(MobSpawnerBlockEntity.class) -@Implements(@Interface(iface = MobSpawner.class, prefix = "terra$")) -public abstract class MobSpawnerBlockEntityMixin extends BlockEntity { - private MobSpawnerBlockEntityMixin(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - @Shadow - public abstract MobSpawnerLogic getLogic(); - - public EntityType terra$getSpawnedType() { - return (EntityType) Registry.ENTITY_TYPE.get( - Identifier.tryParse(((MobSpawnerLogicAccessor) getLogic()).getSpawnEntry().getNbt().getString("id"))); - } - - public void terra$setSpawnedType(@NotNull EntityType creatureType) { - getLogic().setEntityId((net.minecraft.entity.EntityType) creatureType); - } - - public int terra$getDelay() { - return 0; - } - - public void terra$setDelay(int delay) { - - } - - public int terra$getMinSpawnDelay() { - return 0; - } - - public void terra$setMinSpawnDelay(int delay) { - - } - - public int terra$getMaxSpawnDelay() { - return 0; - } - - public void terra$setMaxSpawnDelay(int delay) { - - } - - public int terra$getSpawnCount() { - return 0; - } - - public void terra$setSpawnCount(int spawnCount) { - - } - - public int terra$getMaxNearbyEntities() { - return 0; - } - - public void terra$setMaxNearbyEntities(int maxNearbyEntities) { - - } - - public int terra$getRequiredPlayerRange() { - return 0; - } - - public void terra$setRequiredPlayerRange(int requiredPlayerRange) { - - } - - public int terra$getSpawnRange() { - return 0; - } - - public void terra$setSpawnRange(int spawnRange) { - - } - - public void terra$applyState(String state) { - SerialState.parse(state).forEach((k, v) -> { - switch(k) { - case "type" -> terra$setSpawnedType(ForgeEntryPoint.getPlatform().getWorldHandle().getEntity(v)); - case "delay" -> terra$setDelay(Integer.parseInt(v)); - case "min_delay" -> terra$setMinSpawnDelay(Integer.parseInt(v)); - case "max_delay" -> terra$setMaxSpawnDelay(Integer.parseInt(v)); - case "spawn_count" -> terra$setSpawnCount(Integer.parseInt(v)); - case "spawn_range" -> terra$setSpawnRange(Integer.parseInt(v)); - case "max_nearby" -> terra$setMaxNearbyEntities(Integer.parseInt(v)); - case "required_player_range" -> terra$setRequiredPlayerRange(Integer.parseInt(v)); - default -> throw new IllegalArgumentException("Invalid property: " + k); - } - }); - } -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/state/BlockStateMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/state/BlockStateMixin.java deleted file mode 100644 index c0076820c..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/state/BlockStateMixin.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.dfsek.terra.forge.mixin.implementations.terra.block.state; - - -import com.dfsek.terra.forge.mixin.access.StateAccessor; -import com.google.common.collect.ImmutableMap; -import com.mojang.serialization.MapCodec; -import net.minecraft.block.AbstractBlock.AbstractBlockState; -import net.minecraft.block.Block; -import net.minecraft.state.State; -import net.minecraft.util.registry.Registry; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Intrinsic; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import java.util.stream.Collectors; - -import com.dfsek.terra.api.block.BlockType; -import com.dfsek.terra.api.block.state.BlockState; -import com.dfsek.terra.api.block.state.properties.Property; - - -@Mixin(AbstractBlockState.class) -@Implements(@Interface(iface = BlockState.class, prefix = "terra$")) -public abstract class BlockStateMixin extends State { - private BlockStateMixin(Block owner, ImmutableMap, Comparable> entries, - MapCodec codec) { - super(owner, entries, codec); - } - - @Shadow - public abstract Block getBlock(); - - @Shadow - public abstract boolean isAir(); - - public boolean terra$matches(BlockState other) { - return getBlock() == ((net.minecraft.block.BlockState) other).getBlock(); - } - - @Intrinsic - public > boolean terra$has(Property property) { - if(property instanceof net.minecraft.state.property.Property minecraftProperty) { - return contains(minecraftProperty); - } - return false; - } - - @SuppressWarnings("unchecked") - @Intrinsic - public > T terra$get(Property property) { - return get((net.minecraft.state.property.Property) property); - } - - @SuppressWarnings("unchecked") - @Intrinsic - public > BlockState terra$set(Property property, T value) { - return (BlockState) with((net.minecraft.state.property.Property) property, value); - } - - @Intrinsic - public BlockType terra$getBlockType() { - return (BlockType) getBlock(); - } - - @Intrinsic - public String terra$getAsString(boolean properties) { - StringBuilder data = new StringBuilder(Registry.BLOCK.getId(getBlock()).toString()); - if(properties && !getEntries().isEmpty()) { - data.append('['); - data.append( - getEntries().entrySet().stream().map(StateAccessor.getPropertyMapPrinter()).collect(Collectors.joining(","))); - data.append(']'); - } - return data.toString(); - } - - @Intrinsic - public boolean terra$isAir() { - return isAir(); - } -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ChunkRegionMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ChunkRegionMixin.java deleted file mode 100644 index 22f3733a0..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ChunkRegionMixin.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.forge.mixin.implementations.terra.world; - -import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper; -import net.minecraft.block.FluidBlock; -import net.minecraft.fluid.Fluid; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.ChunkRegion; -import net.minecraft.world.WorldAccess; -import net.minecraft.world.chunk.Chunk; -import net.minecraft.world.chunk.ChunkStatus; -import net.minecraft.world.tick.MultiTickScheduler; -import net.minecraft.world.tick.OrderedTick; -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Intrinsic; -import org.spongepowered.asm.mixin.Mixin; -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 java.util.List; - -import com.dfsek.terra.api.block.entity.BlockEntity; -import com.dfsek.terra.api.block.state.BlockState; -import com.dfsek.terra.api.config.ConfigPack; -import com.dfsek.terra.api.entity.Entity; -import com.dfsek.terra.api.entity.EntityType; -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.forge.util.ForgeUtil; - - -@Mixin(ChunkRegion.class) -@Implements(@Interface(iface = ProtoWorld.class, prefix = "terraWorld$")) -public abstract class ChunkRegionMixin { - private ConfigPack terra$config; - - - @Shadow - @Final - private net.minecraft.server.world.ServerWorld world; - - @Shadow - @Final - private long seed; - @Shadow - @Final - private Chunk centerPos; - - @Shadow - @Final - private MultiTickScheduler fluidTickScheduler; - - - @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.terra$config = ((ServerWorld) world).getPack(); - } - - - @Intrinsic(displace = true) - public void terraWorld$setBlockState(int x, int y, int z, BlockState data, boolean physics) { - BlockPos pos = new BlockPos(x, y, z); - ((ChunkRegion) (Object) this).setBlockState(pos, (net.minecraft.block.BlockState) data, physics ? 3 : 1042); - if(physics && ((net.minecraft.block.BlockState) data).getBlock() instanceof FluidBlock) { - fluidTickScheduler.scheduleTick( - OrderedTick.create(((FluidBlock) ((net.minecraft.block.BlockState) data).getBlock()).getFluidState( - (net.minecraft.block.BlockState) data).getFluid(), pos)); - } - } - - @Intrinsic - public long terraWorld$getSeed() { - return seed; - } - - public int terraWorld$getMaxHeight() { - return world.getTopY(); - } - - @Intrinsic(displace = true) - public BlockState terraWorld$getBlockState(int x, int y, int z) { - BlockPos pos = new BlockPos(x, y, z); - return (BlockState) ((ChunkRegion) (Object) this).getBlockState(pos); - } - - public BlockEntity terraWorld$getBlockEntity(int x, int y, int z) { - return ForgeUtil.createState((WorldAccess) this, new BlockPos(x, y, z)); - } - - public int terraWorld$getMinHeight() { - return world.getBottomY(); - } - - public ChunkGenerator terraWorld$getGenerator() { - return ((ForgeChunkGeneratorWrapper) world.getChunkManager().getChunkGenerator()).getHandle(); - } - - public BiomeProvider terraWorld$getBiomeProvider() { - return terra$config.getBiomeProvider(); - } - - public Entity terraWorld$spawnEntity(double x, double y, double z, EntityType entityType) { - net.minecraft.entity.Entity entity = ((net.minecraft.entity.EntityType) entityType).create(world); - entity.setPos(x, y, z); - ((ChunkRegion) (Object) this).spawnEntity(entity); - return (Entity) entity; - } - - public int terraWorld$centerChunkX() { - return centerPos.getPos().x; - } - - public int terraWorld$centerChunkZ() { - return centerPos.getPos().z; - } - - public ServerWorld terraWorld$getWorld() { - return (ServerWorld) world; - } - - public ConfigPack terraWorld$getPack() { - return terra$config; - } -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ServerWorldMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ServerWorldMixin.java deleted file mode 100644 index 698d49bfe..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/world/ServerWorldMixin.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.forge.mixin.implementations.terra.world; - -import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper; -import com.dfsek.terra.forge.generation.TerraBiomeSource; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.WorldAccess; -import org.spongepowered.asm.mixin.Implements; -import org.spongepowered.asm.mixin.Interface; -import org.spongepowered.asm.mixin.Intrinsic; -import org.spongepowered.asm.mixin.Mixin; - -import com.dfsek.terra.api.block.entity.BlockEntity; -import com.dfsek.terra.api.block.state.BlockState; -import com.dfsek.terra.api.config.ConfigPack; -import com.dfsek.terra.api.entity.Entity; -import com.dfsek.terra.api.entity.EntityType; -import com.dfsek.terra.api.world.ServerWorld; -import com.dfsek.terra.api.world.biome.generation.BiomeProvider; -import com.dfsek.terra.api.world.chunk.Chunk; -import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator; -import com.dfsek.terra.forge.util.ForgeUtil; - - -@Mixin(net.minecraft.server.world.ServerWorld.class) -@Implements(@Interface(iface = ServerWorld.class, prefix = "terra$")) -public abstract class ServerWorldMixin { - public Entity terra$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); - ((net.minecraft.server.world.ServerWorld) (Object) this).spawnEntity(entity); - return (Entity) entity; - } - - public void terra$setBlockState(int x, int y, int z, BlockState data, boolean physics) { - BlockPos pos = new BlockPos(x, y, z); - ((net.minecraft.server.world.ServerWorld) (Object) this).setBlockState(pos, (net.minecraft.block.BlockState) data, - physics ? 3 : 1042); - } - - @Intrinsic - public long terra$getSeed() { - return ((net.minecraft.server.world.ServerWorld) (Object) this).getSeed(); - } - - public int terra$getMaxHeight() { - return (((net.minecraft.server.world.ServerWorld) (Object) this).getBottomY()) + - ((net.minecraft.server.world.ServerWorld) (Object) this).getHeight(); - } - - public Chunk terra$getChunkAt(int x, int z) { - return (Chunk) ((net.minecraft.server.world.ServerWorld) (Object) this).getChunk(x, z); - } - - public BlockState terra$getBlockState(int x, int y, int z) { - return (BlockState) ((net.minecraft.server.world.ServerWorld) (Object) this).getBlockState(new BlockPos(x, y, z)); - } - - public BlockEntity terra$getBlockEntity(int x, int y, int z) { - return ForgeUtil.createState((WorldAccess) this, new BlockPos(x, y, z)); - } - - public int terra$getMinHeight() { - return ((net.minecraft.server.world.ServerWorld) (Object) this).getBottomY(); - } - - public ChunkGenerator terra$getGenerator() { - return ((ForgeChunkGeneratorWrapper) ((net.minecraft.server.world.ServerWorld) (Object) this).getChunkManager() - .getChunkGenerator()).getHandle(); - } - - public BiomeProvider terra$getBiomeProvider() { - return ((TerraBiomeSource) ((net.minecraft.server.world.ServerWorld) (Object) this).getChunkManager() - .getChunkGenerator() - .getBiomeSource()).getProvider(); - } - - public ConfigPack terra$getPack() { - net.minecraft.world.gen.chunk.ChunkGenerator generator = - (((net.minecraft.server.world.ServerWorld) (Object) this).getChunkManager()).getChunkGenerator(); - if(generator instanceof ForgeChunkGeneratorWrapper forgeChunkGeneratorWrapper) { - return forgeChunkGeneratorWrapper.getPack(); - } - return null; - } -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java index 5612372b4..c42db1143 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java @@ -1,12 +1,6 @@ package com.dfsek.terra.forge.util; -import com.dfsek.terra.api.config.ConfigPack; -import com.dfsek.terra.api.world.biome.Biome; -import com.dfsek.terra.forge.ForgeEntryPoint; -import com.dfsek.terra.forge.config.PreLoadCompatibilityOptions; -import com.dfsek.terra.forge.config.VanillaBiomeProperties; - -import com.dfsek.terra.forge.mixin_ifaces.FloraFeatureHolder; +import com.dfsek.terra.mod.config.ProtoPlatformBiome; import net.minecraft.util.Identifier; import net.minecraft.util.registry.BuiltinRegistries; @@ -21,7 +15,19 @@ import net.minecraftforge.registries.RegisterEvent.RegisterHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.world.biome.Biome; +import com.dfsek.terra.forge.ForgeEntryPoint; +import com.dfsek.terra.mod.config.PreLoadCompatibilityOptions; +import com.dfsek.terra.mod.config.VanillaBiomeProperties; +import com.dfsek.terra.mod.mixin_ifaces.FloraFeatureHolder; public final class BiomeUtil { @@ -57,7 +63,7 @@ public final class BiomeUtil { */ private static void registerBiome(Biome biome, ConfigPack pack, com.dfsek.terra.api.registry.key.RegistryKey id, RegisterHelper helper) { - RegistryKey vanilla = ((ProtoPlatformBiome) biome.getPlatformBiome()).get(ForgeRegistries.BIOMES); + RegistryKey vanilla = ((ProtoPlatformBiome) biome.getPlatformBiome()).get(BuiltinRegistries.BIOME); if(pack.getContext().get(PreLoadCompatibilityOptions.class).useVanillaBiomes()) { diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java index ac0efc605..abaabaa0e 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java @@ -1,10 +1,5 @@ package com.dfsek.terra.forge.util; -import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; -import com.dfsek.terra.forge.ForgeEntryPoint; -import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper; -import com.dfsek.terra.forge.generation.TerraBiomeSource; - import net.minecraft.structure.StructureSet; import net.minecraft.util.Identifier; import net.minecraft.util.math.noise.DoublePerlinNoiseSampler.NoiseParameters; @@ -30,6 +25,11 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; +import com.dfsek.terra.forge.ForgeEntryPoint; +import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; +import com.dfsek.terra.mod.generation.TerraBiomeSource; + public class LifecycleUtil { private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleUtil.class); @@ -80,7 +80,7 @@ public class LifecycleUtil { PRESETS.add(generatorID); TerraBiomeSource biomeSource = new TerraBiomeSource(biomeRegistry, pack); - ChunkGenerator generator = new ForgeChunkGeneratorWrapper(structureSetRegistry, biomeSource, pack, overworld); + ChunkGenerator generator = new MinecraftChunkGeneratorWrapper(structureSetRegistry, biomeSource, pack, overworld); DimensionOptions dimensionOptions = new DimensionOptions(overworldDimensionType, generator); WorldPreset preset = new WorldPreset( diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java deleted file mode 100644 index e06ebf0f8..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ProtoPlatformBiome.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ - -package com.dfsek.terra.forge.util; - -import net.minecraft.util.Identifier; -import net.minecraft.util.registry.Registry; -import net.minecraft.util.registry.RegistryKey; -import net.minecraft.world.biome.Biome; - -import java.util.Objects; - -import com.dfsek.terra.api.world.biome.PlatformBiome; - -import net.minecraftforge.registries.IForgeRegistry; - - -public class ProtoPlatformBiome implements PlatformBiome { - private final Identifier identifier; - - private RegistryKey delegate; - - public ProtoPlatformBiome(Identifier identifier) { - this.identifier = identifier; - } - - public RegistryKey get(Registry registry) { - return ForgeUtil.getEntry(registry, identifier).orElseThrow().getKey().orElseThrow(); - } - - public RegistryKey get(IForgeRegistry registry) { - return registry.getHolder(identifier).orElseThrow().getKey().orElseThrow(); - } - - @Override - public Object getHandle() { - return identifier; - } - - public RegistryKey getDelegate() { - return delegate; - } - - public void setDelegate(RegistryKey delegate) { - this.delegate = Objects.requireNonNull(delegate); - } -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java index 4486aad0b..42f001e8e 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java @@ -1,5 +1,7 @@ package com.dfsek.terra.forge.util; +import com.dfsek.terra.mod.util.MinecraftUtil; + import com.google.common.collect.ImmutableMap; import net.minecraft.tag.TagKey; import net.minecraft.tag.WorldPresetTags; @@ -38,7 +40,7 @@ public final class TagUtil { LifecycleUtil .getPresets() - .forEach(id -> ForgeUtil + .forEach(id -> MinecraftUtil .getEntry(registry, id) .ifPresentOrElse( preset -> collect @@ -57,11 +59,11 @@ public final class TagUtil { BiomeUtil .getTerraBiomeMap() .forEach((vb, terraBiomes) -> - ForgeUtil + MinecraftUtil .getEntry(registry, vb) .ifPresentOrElse( vanilla -> terraBiomes - .forEach(tb -> ForgeUtil + .forEach(tb -> MinecraftUtil .getEntry(registry, tb) .ifPresentOrElse( terra -> { diff --git a/platforms/forge/src/main/resources/terra.forge.mixins.json b/platforms/forge/src/main/resources/terra.forge.mixins.json index 33af22478..a1316f288 100644 --- a/platforms/forge/src/main/resources/terra.forge.mixins.json +++ b/platforms/forge/src/main/resources/terra.forge.mixins.json @@ -4,36 +4,6 @@ "package": "com.dfsek.terra.forge.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ - "access.MobSpawnerLogicAccessor", - "access.StateAccessor", - "access.StructureAccessorAccessor", - "fix.BeeMoveGoalsUnsynchronizedRandomAccessFix", - "fix.NetherFossilOptimization", - "implementations.compat.GenerationSettingsFloraFeaturesMixin", - "implementations.terra.BiomeMixin", - "implementations.terra.HandleImplementationMixin", - "implementations.terra.block.BlockMixin", - "implementations.terra.block.entity.BlockEntityMixin", - "implementations.terra.block.entity.LootableContainerBlockEntityMixin", - "implementations.terra.block.entity.MobSpawnerBlockEntityMixin", - "implementations.terra.block.entity.SignBlockEntityMixin", - "implementations.terra.block.state.BlockStateMixin", - "implementations.terra.block.state.PropertyMixin", - "implementations.terra.chunk.ChunkRegionMixin", - "implementations.terra.chunk.WorldChunkMixin", - "implementations.terra.chunk.data.ProtoChunkMixin", - "implementations.terra.entity.EntityMixin", - "implementations.terra.entity.EntityTypeMixin", - "implementations.terra.entity.PlayerEntityMixin", - "implementations.terra.entity.ServerCommandSourceMixin", - "implementations.terra.inventory.LockableContainerBlockEntityMixin", - "implementations.terra.inventory.item.ItemMixin", - "implementations.terra.inventory.item.ItemStackMixin", - "implementations.terra.inventory.meta.EnchantmentMixin", - "implementations.terra.inventory.meta.ItemStackDamageableMixin", - "implementations.terra.inventory.meta.ItemStackMetaMixin", - "implementations.terra.world.ChunkRegionMixin", - "implementations.terra.world.ServerWorldMixin", "lifecycle.DataPackContentsMixin", "lifecycle.NoiseConfigMixin" ], diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/CommonPlatform.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/CommonPlatform.java new file mode 100644 index 000000000..97534c8b1 --- /dev/null +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/CommonPlatform.java @@ -0,0 +1,24 @@ +package com.dfsek.terra.mod; + +import java.util.concurrent.atomic.AtomicReference; + + +public final class CommonPlatform { + private static final AtomicReference platform = new AtomicReference<>(); + + public static ModPlatform get() { + ModPlatform modPlatform = platform.get(); + + if(modPlatform == null) { + throw new IllegalStateException("Platform is not yet initialised!"); + } + + return modPlatform; + } + + public static void initialize(ModPlatform modPlatform) { + if(!platform.compareAndSet(null, modPlatform)) { + throw new IllegalStateException("Platform has already been initialized to " + platform.get()); + } + } +} diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricAddon.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/MinecraftAddon.java similarity index 55% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricAddon.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/MinecraftAddon.java index 347244a54..76b13b137 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricAddon.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/MinecraftAddon.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric; +package com.dfsek.terra.mod; import ca.solostudios.strata.Versions; import ca.solostudios.strata.version.Version; @@ -28,44 +28,44 @@ import com.dfsek.terra.api.event.events.config.pack.ConfigPackPostLoadEvent; import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent; import com.dfsek.terra.api.event.functional.FunctionalEventHandler; import com.dfsek.terra.api.world.biome.Biome; -import com.dfsek.terra.fabric.config.PostLoadCompatibilityOptions; -import com.dfsek.terra.fabric.config.PreLoadCompatibilityOptions; -import com.dfsek.terra.fabric.config.VanillaBiomeProperties; +import com.dfsek.terra.mod.config.PostLoadCompatibilityOptions; +import com.dfsek.terra.mod.config.PreLoadCompatibilityOptions; +import com.dfsek.terra.mod.config.VanillaBiomeProperties; -public final class FabricAddon implements BaseAddon { +public final class MinecraftAddon implements BaseAddon { private static final Version VERSION = Versions.getVersion(1, 0, 0); - private static final Logger logger = LoggerFactory.getLogger(FabricAddon.class); - private final PlatformImpl terraFabricPlugin; + private static final Logger logger = LoggerFactory.getLogger(MinecraftAddon.class); + private final ModPlatform modPlatform; - public FabricAddon(PlatformImpl terraFabricPlugin) { - this.terraFabricPlugin = terraFabricPlugin; + public MinecraftAddon(ModPlatform modPlatform) { + this.modPlatform = modPlatform; } @Override public void initialize() { - terraFabricPlugin.getEventManager() - .getHandler(FunctionalEventHandler.class) - .register(this, ConfigPackPreLoadEvent.class) - .then(event -> event.getPack().getContext().put(event.loadTemplate(new PreLoadCompatibilityOptions()))) - .global(); + modPlatform.getEventManager() + .getHandler(FunctionalEventHandler.class) + .register(this, ConfigPackPreLoadEvent.class) + .then(event -> event.getPack().getContext().put(event.loadTemplate(new PreLoadCompatibilityOptions()))) + .global(); - terraFabricPlugin.getEventManager() - .getHandler(FunctionalEventHandler.class) - .register(this, ConfigPackPostLoadEvent.class) - .then(event -> event.getPack().getContext().put(event.loadTemplate(new PostLoadCompatibilityOptions()))) - .priority(100) - .global(); + modPlatform.getEventManager() + .getHandler(FunctionalEventHandler.class) + .register(this, ConfigPackPostLoadEvent.class) + .then(event -> event.getPack().getContext().put(event.loadTemplate(new PostLoadCompatibilityOptions()))) + .priority(100) + .global(); - terraFabricPlugin.getEventManager() - .getHandler(FunctionalEventHandler.class) - .register(this, ConfigurationLoadEvent.class) - .then(event -> { + modPlatform.getEventManager() + .getHandler(FunctionalEventHandler.class) + .register(this, ConfigurationLoadEvent.class) + .then(event -> { if(event.is(Biome.class)) { event.getLoadedObject(Biome.class).getContext().put(event.load(new VanillaBiomeProperties())); } }) - .global(); + .global(); } @Override diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/ModPlatform.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/ModPlatform.java new file mode 100644 index 000000000..48fa219c2 --- /dev/null +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/ModPlatform.java @@ -0,0 +1,56 @@ +package com.dfsek.terra.mod; + +import com.dfsek.tectonic.api.TypeRegistry; + +import com.dfsek.tectonic.api.depth.DepthTracker; +import com.dfsek.tectonic.api.exception.LoadException; + +import com.dfsek.terra.AbstractPlatform; + +import com.dfsek.terra.api.addon.BaseAddon; +import com.dfsek.terra.api.world.biome.PlatformBiome; + +import com.dfsek.terra.mod.config.ProtoPlatformBiome; + +import net.minecraft.command.CommandSource; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.BuiltinRegistries; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.Biome.Precipitation; +import net.minecraft.world.biome.BiomeEffects.GrassColorModifier; + +import java.util.List; +import java.util.Locale; + + +public abstract class ModPlatform extends AbstractPlatform { + public abstract MinecraftServer getServer(); + + @Override + public void register(TypeRegistry registry) { + super.register(registry); + registry.registerLoader(PlatformBiome.class, (type, o, loader, depthTracker) -> parseBiome((String) o, depthTracker)) + .registerLoader(Identifier.class, (type, o, loader, depthTracker) -> { + Identifier identifier = Identifier.tryParse((String) o); + if(identifier == null) + throw new LoadException("Invalid identifier: " + o, depthTracker); + return identifier; + }) + .registerLoader(Precipitation.class, (type, o, loader, depthTracker) -> Precipitation.valueOf(((String) o).toUpperCase( + Locale.ROOT))) + .registerLoader(GrassColorModifier.class, (type, o, loader, depthTracker) -> GrassColorModifier.valueOf(((String) o).toUpperCase( + Locale.ROOT))); + } + + private ProtoPlatformBiome parseBiome(String id, DepthTracker tracker) throws LoadException { + Identifier identifier = Identifier.tryParse(id); + if(BuiltinRegistries.BIOME.get(identifier) == null) throw new LoadException("Invalid Biome ID: " + identifier, tracker); // failure. + return new ProtoPlatformBiome(identifier); + } + + @Override + protected Iterable platformAddon() { + return List.of(new MinecraftAddon(this)); + } +} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/config/PostLoadCompatibilityOptions.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/PostLoadCompatibilityOptions.java similarity index 95% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/config/PostLoadCompatibilityOptions.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/PostLoadCompatibilityOptions.java index 1a8ad12ba..a8b457bf5 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/config/PostLoadCompatibilityOptions.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/PostLoadCompatibilityOptions.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.config; +package com.dfsek.terra.mod.config; import com.dfsek.tectonic.api.config.template.ConfigTemplate; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PreLoadCompatibilityOptions.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/PreLoadCompatibilityOptions.java similarity index 88% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PreLoadCompatibilityOptions.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/PreLoadCompatibilityOptions.java index 8533ef1a0..00825bc5f 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/config/PreLoadCompatibilityOptions.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/PreLoadCompatibilityOptions.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.config; +package com.dfsek.terra.mod.config; import com.dfsek.tectonic.api.config.template.ConfigTemplate; import com.dfsek.tectonic.api.config.template.annotations.Default; @@ -26,19 +26,19 @@ import com.dfsek.terra.api.properties.Properties; @SuppressWarnings("FieldMayBeFinal") public class PreLoadCompatibilityOptions implements ConfigTemplate, Properties { - @Value("fabric.use-vanilla-biomes") + @Value("minecraft.use-vanilla-biomes") @Default private boolean vanillaBiomes = false; - @Value("fabric.beard.enable") + @Value("minecraft.beard.enable") @Default private boolean beard = true; - @Value("fabric.beard.threshold") + @Value("minecraft.beard.threshold") @Default private double beardThreshold = 0.5; - @Value("fabric.beard.air-threshold") + @Value("minecraft.beard.air-threshold") @Default private double airThreshold = -0.5; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/ProtoPlatformBiome.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/ProtoPlatformBiome.java similarity index 89% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/ProtoPlatformBiome.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/ProtoPlatformBiome.java index b8262893a..78542fabe 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/ProtoPlatformBiome.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/ProtoPlatformBiome.java @@ -15,7 +15,9 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.util; +package com.dfsek.terra.mod.config; + +import com.dfsek.terra.mod.util.MinecraftUtil; import net.minecraft.util.Identifier; import net.minecraft.util.registry.Registry; @@ -37,7 +39,7 @@ public class ProtoPlatformBiome implements PlatformBiome { } public RegistryKey get(Registry registry) { - return FabricUtil.getEntry(registry, identifier).orElseThrow().getKey().orElseThrow(); + return MinecraftUtil.getEntry(registry, identifier).orElseThrow().getKey().orElseThrow(); } @Override diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/config/VanillaBiomeProperties.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/VanillaBiomeProperties.java similarity index 97% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/config/VanillaBiomeProperties.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/VanillaBiomeProperties.java index b4baa1882..b37266230 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/config/VanillaBiomeProperties.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/VanillaBiomeProperties.java @@ -1,4 +1,4 @@ -package com.dfsek.terra.forge.config; +package com.dfsek.terra.mod.config; import com.dfsek.tectonic.api.config.template.ConfigTemplate; import com.dfsek.tectonic.api.config.template.annotations.Default; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/data/Codecs.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/data/Codecs.java similarity index 79% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/data/Codecs.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/data/Codecs.java index a2d2222c7..643ced594 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/data/Codecs.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/data/Codecs.java @@ -1,10 +1,7 @@ -package com.dfsek.terra.fabric.data; +package com.dfsek.terra.mod.data; -import com.dfsek.terra.api.config.ConfigPack; -import com.dfsek.terra.api.registry.key.RegistryKey; -import com.dfsek.terra.fabric.FabricEntryPoint; -import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper; -import com.dfsek.terra.fabric.generation.TerraBiomeSource; +import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; +import com.dfsek.terra.mod.generation.TerraBiomeSource; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; @@ -12,6 +9,10 @@ import net.minecraft.util.dynamic.RegistryOps; import net.minecraft.util.registry.Registry; import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.api.registry.key.RegistryKey; +import com.dfsek.terra.mod.CommonPlatform; + public final class Codecs { public static final Codec TERRA_REGISTRY_KEY = RecordCodecBuilder @@ -27,10 +28,10 @@ public final class Codecs { .create(config -> config.group(TERRA_REGISTRY_KEY.fieldOf("pack") .stable() .forGetter(ConfigPack::getRegistryKey)) - .apply(config, config.stable(id -> FabricEntryPoint.getPlatform() - .getConfigRegistry() - .get(id) - .orElseThrow(() -> new IllegalArgumentException( + .apply(config, config.stable(id -> CommonPlatform.get() + .getConfigRegistry() + .get(id) + .orElseThrow(() -> new IllegalArgumentException( "No such config pack " + id))))); @@ -44,22 +45,22 @@ public final class Codecs { .forGetter(TerraBiomeSource::getPack)) .apply(instance, instance.stable(TerraBiomeSource::new))); - public static final Codec FABRIC_CHUNK_GENERATOR_WRAPPER = RecordCodecBuilder + public static final Codec MINECRAFT_CHUNK_GENERATOR_WRAPPER = RecordCodecBuilder .create( instance -> instance.group( RegistryOps.createRegistryCodec(Registry.STRUCTURE_SET_KEY) .fieldOf("structure_registry") .stable() - .forGetter(FabricChunkGeneratorWrapper::getNoiseRegistry), + .forGetter(MinecraftChunkGeneratorWrapper::getNoiseRegistry), TERRA_BIOME_SOURCE.fieldOf("biome_source") .stable() - .forGetter(FabricChunkGeneratorWrapper::getBiomeSource), + .forGetter(MinecraftChunkGeneratorWrapper::getBiomeSource), CONFIG_PACK.fieldOf("pack") .stable() - .forGetter(FabricChunkGeneratorWrapper::getPack), + .forGetter(MinecraftChunkGeneratorWrapper::getPack), ChunkGeneratorSettings.REGISTRY_CODEC.fieldOf("settings") .stable() - .forGetter(FabricChunkGeneratorWrapper::getSettings) - ).apply(instance, instance.stable(FabricChunkGeneratorWrapper::new)) + .forGetter(MinecraftChunkGeneratorWrapper::getSettings) + ).apply(instance, instance.stable(MinecraftChunkGeneratorWrapper::new)) ); } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/generation/MinecraftChunkGeneratorWrapper.java similarity index 91% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/generation/MinecraftChunkGeneratorWrapper.java index 8ae3c3afe..1b8af7852 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/FabricChunkGeneratorWrapper.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/generation/MinecraftChunkGeneratorWrapper.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.generation; +package com.dfsek.terra.mod.generation; import com.dfsek.terra.mod.mixin.access.StructureAccessorAccessor; @@ -63,13 +63,13 @@ import com.dfsek.terra.api.world.chunk.generation.ProtoWorld; import com.dfsek.terra.api.world.chunk.generation.stage.Chunkified; 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.util.FabricAdapter; +import com.dfsek.terra.mod.config.PreLoadCompatibilityOptions; +import com.dfsek.terra.mod.data.Codecs; +import com.dfsek.terra.mod.util.MinecraftAdapter; -public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.ChunkGenerator implements GeneratorWrapper { - private static final Logger logger = LoggerFactory.getLogger(FabricChunkGeneratorWrapper.class); +public class MinecraftChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.ChunkGenerator implements GeneratorWrapper { + private static final Logger logger = LoggerFactory.getLogger(MinecraftChunkGeneratorWrapper.class); private final TerraBiomeSource biomeSource; private final Registry noiseRegistry; @@ -77,8 +77,8 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C private ChunkGenerator delegate; private ConfigPack pack; - public FabricChunkGeneratorWrapper(Registry noiseRegistry, TerraBiomeSource biomeSource, ConfigPack configPack, - RegistryEntry settingsSupplier) { + public MinecraftChunkGeneratorWrapper(Registry noiseRegistry, TerraBiomeSource biomeSource, ConfigPack configPack, + RegistryEntry settingsSupplier) { super(noiseRegistry, Optional.empty(), biomeSource); this.noiseRegistry = noiseRegistry; this.pack = configPack; @@ -95,7 +95,7 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C @Override protected Codec getCodec() { - return Codecs.FABRIC_CHUNK_GENERATOR_WRAPPER; + return Codecs.MINECRAFT_CHUNK_GENERATOR_WRAPPER; } @Override @@ -186,7 +186,7 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C @Override public int getHeight(int x, int z, Type heightmap, HeightLimitView height, NoiseConfig noiseConfig) { - WorldProperties properties = FabricAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); + WorldProperties properties = MinecraftAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); BiomeProvider biomeProvider = pack.getBiomeProvider(); int min = height.getBottomY(); for(int y = height.getTopY() - 1; y >= min; y--) { @@ -200,7 +200,7 @@ public class FabricChunkGeneratorWrapper extends net.minecraft.world.gen.chunk.C @Override public VerticalBlockSample getColumnSample(int x, int z, HeightLimitView height, NoiseConfig noiseConfig) { BlockState[] array = new BlockState[height.getHeight()]; - WorldProperties properties = FabricAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); + WorldProperties properties = MinecraftAdapter.adapt(height, noiseConfig.getLegacyWorldSeed()); BiomeProvider biomeProvider = pack.getBiomeProvider(); for(int y = height.getTopY() - 1; y >= height.getBottomY(); y--) { array[y - height.getBottomY()] = (BlockState) delegate.getBlock(properties, x, y, z, biomeProvider); diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/generation/TerraBiomeSource.java similarity index 95% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/generation/TerraBiomeSource.java index dec7784ff..7f1f1d6dd 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/generation/TerraBiomeSource.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/generation/TerraBiomeSource.java @@ -15,12 +15,12 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.generation; +package com.dfsek.terra.mod.generation; import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.world.biome.generation.BiomeProvider; -import com.dfsek.terra.fabric.data.Codecs; -import com.dfsek.terra.fabric.util.ProtoPlatformBiome; +import com.dfsek.terra.mod.data.Codecs; +import com.dfsek.terra.mod.config.ProtoPlatformBiome; import com.dfsek.terra.mod.util.SeedHack; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/ForgeItemHandle.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftItemHandle.java similarity index 87% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/handle/ForgeItemHandle.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftItemHandle.java index b68ad4478..5d26b6c43 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/handle/ForgeItemHandle.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftItemHandle.java @@ -15,9 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.handle; - -import com.dfsek.terra.forge.ForgeEntryPoint; +package com.dfsek.terra.mod.handle; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -32,15 +30,16 @@ import java.util.stream.Collectors; import com.dfsek.terra.api.handle.ItemHandle; import com.dfsek.terra.api.inventory.Item; import com.dfsek.terra.api.inventory.item.Enchantment; +import com.dfsek.terra.mod.CommonPlatform; -public class ForgeItemHandle implements ItemHandle { +public class MinecraftItemHandle implements ItemHandle { @Override public Item createItem(String data) { try { return (Item) new ItemStackArgumentType(new CommandRegistryAccess( - ForgeEntryPoint.getPlatform().getServer().getRegistryManager())).parse(new StringReader(data)).getItem(); + CommonPlatform.get().getServer().getRegistryManager())).parse(new StringReader(data)).getItem(); } catch(CommandSyntaxException e) { throw new IllegalArgumentException("Invalid item data \"" + data + "\"", e); } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java similarity index 79% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java index 53b2ac21d..ba73ff960 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java @@ -1,6 +1,4 @@ -package com.dfsek.terra.forge.mixin.fix; - -import com.dfsek.terra.forge.ForgeEntryPoint; +package com.dfsek.terra.mod.mixin.fix; import net.minecraft.entity.passive.BeeEntity.MoveToFlowerGoal; import net.minecraft.entity.passive.BeeEntity.MoveToHiveGoal; @@ -11,6 +9,8 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; +import com.dfsek.terra.mod.CommonPlatform; + /** * Bees spawning uses world.random without synchronization. This causes issues when spawning bees during world generation. @@ -22,6 +22,6 @@ import org.spongepowered.asm.mixin.injection.Redirect; public class BeeMoveGoalsUnsynchronizedRandomAccessFix { @Redirect(method = "", at = @At(value = "FIELD", target = "Lnet/minecraft/world/World;random:Lnet/minecraft/util/math/random/Random;")) public Random redirectRandomAccess(World instance) { - return new CheckedRandom(ForgeEntryPoint.getPlatform().getServer().getTicks()); // replace with new random seeded by tick time. + return new CheckedRandom(CommonPlatform.get().getServer().getTicks()); // replace with new random seeded by tick time. } } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/NetherFossilOptimization.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/fix/NetherFossilOptimization.java similarity index 73% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/NetherFossilOptimization.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/fix/NetherFossilOptimization.java index d72e59761..f0eb245b8 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/fix/NetherFossilOptimization.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/fix/NetherFossilOptimization.java @@ -1,6 +1,6 @@ -package com.dfsek.terra.forge.mixin.fix; +package com.dfsek.terra.mod.mixin.fix; -import com.dfsek.terra.forge.generation.ForgeChunkGeneratorWrapper; +import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; import net.minecraft.world.gen.structure.NetherFossilStructure; import net.minecraft.world.gen.structure.Structure.Context; @@ -16,13 +16,13 @@ import java.util.Optional; /** * Disable fossil generation in Terra worlds, as they are very expensive due to consistently triggering cache misses. * - * Currently, on Forge, Terra cannot be specified as a Nether generator. TODO: logic to turn fossils back on if chunk generator is in nether. + * Currently, on Fabric, Terra cannot be specified as a Nether generator. TODO: logic to turn fossils back on if chunk generator is in nether. */ @Mixin(NetherFossilStructure.class) public class NetherFossilOptimization { @Inject(method = "getStructurePosition", at = @At("HEAD"), cancellable = true) public void injectFossilPositions(Context context, CallbackInfoReturnable> cir) { - if(context.chunkGenerator() instanceof ForgeChunkGeneratorWrapper) { + if(context.chunkGenerator() instanceof MinecraftChunkGeneratorWrapper) { cir.setReturnValue(Optional.empty()); } } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java similarity index 89% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java index 19639e48a..df71e733f 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java @@ -1,6 +1,6 @@ -package com.dfsek.terra.forge.mixin.implementations.compat; +package com.dfsek.terra.mod.mixin.implementations.compat; -import com.dfsek.terra.forge.mixin_ifaces.FloraFeatureHolder; +import com.dfsek.terra.mod.mixin_ifaces.FloraFeatureHolder; import net.minecraft.world.biome.GenerationSettings; import net.minecraft.world.gen.feature.ConfiguredFeature; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/BiomeMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/BiomeMixin.java similarity index 94% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/BiomeMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/BiomeMixin.java index 3bf07cffc..893921e8e 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/BiomeMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/BiomeMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra; +package com.dfsek.terra.mod.mixin.implementations.terra; import net.minecraft.world.biome.Biome; import org.spongepowered.asm.mixin.Implements; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/HandleImplementationMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/HandleImplementationMixin.java similarity index 96% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/HandleImplementationMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/HandleImplementationMixin.java index 936af09b3..0257421ca 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/HandleImplementationMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/HandleImplementationMixin.java @@ -1,4 +1,4 @@ -package com.dfsek.terra.forge.mixin.implementations.terra; +package com.dfsek.terra.mod.mixin.implementations.terra; import net.minecraft.block.Block; import net.minecraft.block.BlockState; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/BlockMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/BlockMixin.java similarity index 95% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/BlockMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/BlockMixin.java index 8df67e40a..480e4a86d 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/BlockMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/BlockMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.block; +package com.dfsek.terra.mod.mixin.implementations.terra.block; import net.minecraft.block.Block; import net.minecraft.block.Blocks; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/BlockEntityMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/BlockEntityMixin.java similarity index 96% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/BlockEntityMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/BlockEntityMixin.java index 272c18812..cfb7b795b 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/BlockEntityMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/BlockEntityMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.block.entity; +package com.dfsek.terra.mod.mixin.implementations.terra.block.entity; import org.spongepowered.asm.mixin.Implements; import org.spongepowered.asm.mixin.Interface; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java similarity index 94% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java index 123541696..ad237b3b8 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.block.entity; +package com.dfsek.terra.mod.mixin.implementations.terra.block.entity; import net.minecraft.block.entity.LootableContainerBlockEntity; import org.spongepowered.asm.mixin.Implements; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java similarity index 94% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java index 0bb1b6120..f28c27a62 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java @@ -15,9 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.terra.block.entity; - -import com.dfsek.terra.mod.mixin.access.MobSpawnerLogicAccessor; +package com.dfsek.terra.mod.mixin.implementations.terra.block.entity; import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; @@ -36,7 +34,8 @@ import org.spongepowered.asm.mixin.Shadow; import com.dfsek.terra.api.block.entity.MobSpawner; import com.dfsek.terra.api.block.entity.SerialState; import com.dfsek.terra.api.entity.EntityType; -import com.dfsek.terra.fabric.FabricEntryPoint; +import com.dfsek.terra.mod.CommonPlatform; +import com.dfsek.terra.mod.mixin.access.MobSpawnerLogicAccessor; @Mixin(MobSpawnerBlockEntity.class) @@ -117,7 +116,7 @@ public abstract class MobSpawnerBlockEntityMixin extends BlockEntity { public void terra$applyState(String state) { SerialState.parse(state).forEach((k, v) -> { switch(k) { - case "type" -> terra$setSpawnedType(FabricEntryPoint.getPlatform().getWorldHandle().getEntity(v)); + case "type" -> terra$setSpawnedType(CommonPlatform.get().getWorldHandle().getEntity(v)); case "delay" -> terra$setDelay(Integer.parseInt(v)); case "min_delay" -> terra$setMinSpawnDelay(Integer.parseInt(v)); case "max_delay" -> terra$setMaxSpawnDelay(Integer.parseInt(v)); diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java similarity index 96% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java index 400a176ca..e32d7e053 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.block.entity; +package com.dfsek.terra.mod.mixin.implementations.terra.block.entity; import net.minecraft.block.entity.SignBlockEntity; import net.minecraft.text.Text; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/state/BlockStateMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/BlockStateMixin.java similarity index 97% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/state/BlockStateMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/BlockStateMixin.java index 86552bda4..86272efd9 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/block/state/BlockStateMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/BlockStateMixin.java @@ -1,4 +1,4 @@ -package com.dfsek.terra.fabric.mixin.implementations.terra.block.state; +package com.dfsek.terra.mod.mixin.implementations.terra.block.state; import com.dfsek.terra.mod.mixin.access.StateAccessor; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/state/PropertyMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/PropertyMixin.java similarity index 93% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/state/PropertyMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/PropertyMixin.java index ce7d41e20..2dd6100d6 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/block/state/PropertyMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/PropertyMixin.java @@ -1,4 +1,4 @@ -package com.dfsek.terra.forge.mixin.implementations.terra.block.state; +package com.dfsek.terra.mod.mixin.implementations.terra.block.state; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Implements; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/ChunkRegionMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/ChunkRegionMixin.java similarity index 97% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/ChunkRegionMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/ChunkRegionMixin.java index 96bbe0715..7224f25d1 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/ChunkRegionMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/ChunkRegionMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.chunk; +package com.dfsek.terra.mod.mixin.implementations.terra.chunk; import net.minecraft.util.math.BlockPos; import net.minecraft.world.ChunkRegion; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/WorldChunkMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/WorldChunkMixin.java similarity index 97% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/WorldChunkMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/WorldChunkMixin.java index b6aecff61..3fb01104d 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/WorldChunkMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/WorldChunkMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.chunk; +package com.dfsek.terra.mod.mixin.implementations.terra.chunk; import net.minecraft.util.math.BlockPos; import net.minecraft.world.chunk.WorldChunk; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java similarity index 96% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java index 918df4f42..f90e5a3b3 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.chunk.data; +package com.dfsek.terra.mod.mixin.implementations.terra.chunk.data; import com.dfsek.terra.api.block.state.BlockState; import com.dfsek.terra.api.world.chunk.generation.ProtoChunk; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityMixin.java similarity index 90% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityMixin.java index a300693b7..dce95cf19 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityMixin.java @@ -15,9 +15,8 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.entity; +package com.dfsek.terra.mod.mixin.implementations.terra.entity; -import com.dfsek.terra.forge.util.ForgeAdapter; import net.minecraft.entity.Entity; import net.minecraft.util.math.BlockPos; import org.spongepowered.asm.mixin.Implements; @@ -27,6 +26,7 @@ import org.spongepowered.asm.mixin.Shadow; import com.dfsek.terra.api.util.vector.Vector3; import com.dfsek.terra.api.world.ServerWorld; +import com.dfsek.terra.mod.util.MinecraftAdapter; @Mixin(Entity.class) @@ -42,7 +42,7 @@ public abstract class EntityMixin { public abstract void teleport(double destX, double destY, double destZ); public Vector3 terra$position() { - return ForgeAdapter.adapt(blockPos); + return MinecraftAdapter.adapt(blockPos); } public void terra$position(Vector3 location) { diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityTypeMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityTypeMixin.java similarity index 93% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityTypeMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityTypeMixin.java index 1c73c1efb..a79d4fb0d 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/EntityTypeMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityTypeMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.entity; +package com.dfsek.terra.mod.mixin.implementations.terra.entity; import net.minecraft.entity.EntityType; import org.spongepowered.asm.mixin.Implements; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/PlayerEntityMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/PlayerEntityMixin.java similarity index 94% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/PlayerEntityMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/PlayerEntityMixin.java index f08df6293..ec60c9f69 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/PlayerEntityMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/PlayerEntityMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.entity; +package com.dfsek.terra.mod.mixin.implementations.terra.entity; import net.minecraft.entity.player.PlayerEntity; import org.spongepowered.asm.mixin.Implements; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/ServerCommandSourceMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/ServerCommandSourceMixin.java similarity index 97% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/ServerCommandSourceMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/ServerCommandSourceMixin.java index ce91be261..f11ee5f73 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/entity/ServerCommandSourceMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/ServerCommandSourceMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.entity; +package com.dfsek.terra.mod.mixin.implementations.terra.entity; import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.server.command.ServerCommandSource; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java similarity index 96% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java index 40f6111db..90c0275dc 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.inventory; +package com.dfsek.terra.mod.mixin.implementations.terra.inventory; import net.minecraft.block.entity.LockableContainerBlockEntity; import net.minecraft.item.Items; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/item/ItemMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemMixin.java similarity index 95% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/item/ItemMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemMixin.java index e48b5341c..51687c45a 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/item/ItemMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.inventory.item; +package com.dfsek.terra.mod.mixin.implementations.terra.inventory.item; import net.minecraft.item.Item; import org.spongepowered.asm.mixin.Implements; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/item/ItemStackMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemStackMixin.java similarity index 96% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/item/ItemStackMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemStackMixin.java index 7bb42595a..f41bce58d 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/item/ItemStackMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemStackMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.inventory.item; +package com.dfsek.terra.mod.mixin.implementations.terra.inventory.item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java similarity index 96% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java index 358cd7a95..d5394870c 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.inventory.meta; +package com.dfsek.terra.mod.mixin.implementations.terra.inventory.meta; import net.minecraft.enchantment.Enchantment; import net.minecraft.util.registry.Registry; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java similarity index 95% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java index d70b1732d..599dd232d 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.inventory.meta; +package com.dfsek.terra.mod.mixin.implementations.terra.inventory.meta; import net.minecraft.item.ItemStack; import org.spongepowered.asm.mixin.Implements; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java similarity index 96% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java index 17bf068a1..39974ed26 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.mixin.implementations.terra.inventory.meta; +package com.dfsek.terra.mod.mixin.implementations.terra.inventory.meta; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NbtCompound; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/package-info.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/package-info.java similarity index 92% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/package-info.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/package-info.java index 0899793d3..0d7e843de 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/implementations/terra/package-info.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/package-info.java @@ -20,4 +20,4 @@ * interfaces in Minecraft classes. */ -package com.dfsek.terra.forge.mixin.implementations.terra; \ No newline at end of file +package com.dfsek.terra.mod.mixin.implementations.terra; \ No newline at end of file diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/world/ChunkRegionMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ChunkRegionMixin.java similarity index 93% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/world/ChunkRegionMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ChunkRegionMixin.java index 7a5ebf822..c17a8c1ee 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/world/ChunkRegionMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ChunkRegionMixin.java @@ -15,8 +15,9 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.terra.world; +package com.dfsek.terra.mod.mixin.implementations.terra.world; +import com.dfsek.terra.mod.util.MinecraftUtil; import net.minecraft.block.FluidBlock; import net.minecraft.fluid.Fluid; import net.minecraft.util.math.BlockPos; @@ -47,8 +48,7 @@ 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.generation.FabricChunkGeneratorWrapper; -import com.dfsek.terra.fabric.util.FabricUtil; +import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; @Mixin(ChunkRegion.class) @@ -109,7 +109,7 @@ public abstract class ChunkRegionMixin { } public BlockEntity terraWorld$getBlockEntity(int x, int y, int z) { - return FabricUtil.createState((WorldAccess) this, new BlockPos(x, y, z)); + return MinecraftUtil.createState((WorldAccess) this, new BlockPos(x, y, z)); } public int terraWorld$getMinHeight() { @@ -117,7 +117,7 @@ public abstract class ChunkRegionMixin { } public ChunkGenerator terraWorld$getGenerator() { - return ((FabricChunkGeneratorWrapper) world.getChunkManager().getChunkGenerator()).getHandle(); + return ((MinecraftChunkGeneratorWrapper) world.getChunkManager().getChunkGenerator()).getHandle(); } public BiomeProvider terraWorld$getBiomeProvider() { diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/world/ServerWorldMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ServerWorldMixin.java similarity index 85% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/world/ServerWorldMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ServerWorldMixin.java index 048b38d8e..f219db0a1 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/implementations/terra/world/ServerWorldMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ServerWorldMixin.java @@ -15,8 +15,9 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.fabric.mixin.implementations.terra.world; +package com.dfsek.terra.mod.mixin.implementations.terra.world; +import com.dfsek.terra.mod.util.MinecraftUtil; import net.minecraft.util.math.BlockPos; import net.minecraft.world.WorldAccess; import org.spongepowered.asm.mixin.Implements; @@ -33,9 +34,8 @@ import com.dfsek.terra.api.world.ServerWorld; import com.dfsek.terra.api.world.biome.generation.BiomeProvider; import com.dfsek.terra.api.world.chunk.Chunk; import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator; -import com.dfsek.terra.fabric.generation.FabricChunkGeneratorWrapper; -import com.dfsek.terra.fabric.generation.TerraBiomeSource; -import com.dfsek.terra.fabric.util.FabricUtil; +import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; +import com.dfsek.terra.mod.generation.TerraBiomeSource; @Mixin(net.minecraft.server.world.ServerWorld.class) @@ -73,7 +73,7 @@ public abstract class ServerWorldMixin { } public BlockEntity terra$getBlockEntity(int x, int y, int z) { - return FabricUtil.createState((WorldAccess) this, new BlockPos(x, y, z)); + return MinecraftUtil.createState((WorldAccess) this, new BlockPos(x, y, z)); } public int terra$getMinHeight() { @@ -81,8 +81,8 @@ public abstract class ServerWorldMixin { } public ChunkGenerator terra$getGenerator() { - return ((FabricChunkGeneratorWrapper) ((net.minecraft.server.world.ServerWorld) (Object) this).getChunkManager() - .getChunkGenerator()).getHandle(); + return ((MinecraftChunkGeneratorWrapper) ((net.minecraft.server.world.ServerWorld) (Object) this).getChunkManager() + .getChunkGenerator()).getHandle(); } public BiomeProvider terra$getBiomeProvider() { @@ -94,8 +94,8 @@ public abstract class ServerWorldMixin { public ConfigPack terra$getPack() { net.minecraft.world.gen.chunk.ChunkGenerator generator = (((net.minecraft.server.world.ServerWorld) (Object) this).getChunkManager()).getChunkGenerator(); - if(generator instanceof FabricChunkGeneratorWrapper fabricChunkGeneratorWrapper) { - return fabricChunkGeneratorWrapper.getPack(); + if(generator instanceof MinecraftChunkGeneratorWrapper minecraftChunkGeneratorWrapper) { + return minecraftChunkGeneratorWrapper.getPack(); } return null; } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin_ifaces/FloraFeatureHolder.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin_ifaces/FloraFeatureHolder.java similarity index 81% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/mixin_ifaces/FloraFeatureHolder.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin_ifaces/FloraFeatureHolder.java index 2797691f4..4e7c38dec 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin_ifaces/FloraFeatureHolder.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin_ifaces/FloraFeatureHolder.java @@ -1,4 +1,4 @@ -package com.dfsek.terra.forge.mixin_ifaces; +package com.dfsek.terra.mod.mixin_ifaces; import net.minecraft.world.gen.feature.ConfiguredFeature; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ForgeAdapter.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/MinecraftAdapter.java similarity index 95% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/util/ForgeAdapter.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/MinecraftAdapter.java index 469b80349..2f43913e2 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ForgeAdapter.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/MinecraftAdapter.java @@ -15,7 +15,7 @@ * along with Terra. If not, see . */ -package com.dfsek.terra.forge.util; +package com.dfsek.terra.mod.util; import net.minecraft.util.math.BlockPos; import net.minecraft.world.HeightLimitView; @@ -24,7 +24,7 @@ import com.dfsek.terra.api.util.vector.Vector3; import com.dfsek.terra.api.world.info.WorldProperties; -public final class ForgeAdapter { +public final class MinecraftAdapter { public static Vector3 adapt(BlockPos pos) { return Vector3.of(pos.getX(), pos.getY(), pos.getZ()); diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ForgeUtil.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/MinecraftUtil.java similarity index 64% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/util/ForgeUtil.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/MinecraftUtil.java index cb577de6f..9f7a36712 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/ForgeUtil.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/MinecraftUtil.java @@ -1,21 +1,9 @@ -/* - * This file is part of Terra. - * - * Terra 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 - * (at your option) any later version. - * - * Terra 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 Terra. If not, see . - */ +package com.dfsek.terra.mod.util; -package com.dfsek.terra.forge.util; +import com.dfsek.terra.api.block.entity.BlockEntity; +import com.dfsek.terra.api.block.entity.Container; +import com.dfsek.terra.api.block.entity.MobSpawner; +import com.dfsek.terra.api.block.entity.Sign; import net.minecraft.block.entity.LootableContainerBlockEntity; import net.minecraft.block.entity.MobSpawnerBlockEntity; @@ -28,17 +16,18 @@ import net.minecraft.world.WorldAccess; import java.util.Optional; -import com.dfsek.terra.api.block.entity.BlockEntity; -import com.dfsek.terra.api.block.entity.Container; -import com.dfsek.terra.api.block.entity.MobSpawner; -import com.dfsek.terra.api.block.entity.Sign; - -public final class ForgeUtil { - private ForgeUtil() { +public final class MinecraftUtil { + private MinecraftUtil() { } + public static Optional> getEntry(Registry registry, Identifier identifier) { + return registry.getOrEmpty(identifier) + .flatMap(registry::getKey) + .map(registry::getOrCreateEntry); + } + public static BlockEntity createState(WorldAccess worldAccess, BlockPos pos) { net.minecraft.block.entity.BlockEntity entity = worldAccess.getBlockEntity(pos); if(entity instanceof SignBlockEntity) { @@ -50,10 +39,4 @@ public final class ForgeUtil { } return null; } - - public static Optional> getEntry(Registry registry, Identifier identifier) { - return registry.getOrEmpty(identifier) - .flatMap(registry::getKey) - .map(registry::getOrCreateEntry); - } } diff --git a/platforms/mod-common/src/main/resources/terra.common.mixins.json b/platforms/mod-common/src/main/resources/terra.common.mixins.json index ee399c73e..c8142c28a 100644 --- a/platforms/mod-common/src/main/resources/terra.common.mixins.json +++ b/platforms/mod-common/src/main/resources/terra.common.mixins.json @@ -6,7 +6,34 @@ "mixins": [ "access.MobSpawnerLogicAccessor", "access.StateAccessor", - "access.StructureAccessorAccessor" + "access.StructureAccessorAccessor", + "fix.BeeMoveGoalsUnsynchronizedRandomAccessFix", + "fix.NetherFossilOptimization", + "implementations.compat.GenerationSettingsFloraFeaturesMixin", + "implementations.terra.BiomeMixin", + "implementations.terra.HandleImplementationMixin", + "implementations.terra.block.BlockMixin", + "implementations.terra.block.entity.BlockEntityMixin", + "implementations.terra.block.entity.LootableContainerBlockEntityMixin", + "implementations.terra.block.entity.MobSpawnerBlockEntityMixin", + "implementations.terra.block.entity.SignBlockEntityMixin", + "implementations.terra.block.state.BlockStateMixin", + "implementations.terra.block.state.PropertyMixin", + "implementations.terra.chunk.ChunkRegionMixin", + "implementations.terra.chunk.WorldChunkMixin", + "implementations.terra.chunk.data.ProtoChunkMixin", + "implementations.terra.entity.EntityMixin", + "implementations.terra.entity.EntityTypeMixin", + "implementations.terra.entity.PlayerEntityMixin", + "implementations.terra.entity.ServerCommandSourceMixin", + "implementations.terra.inventory.LockableContainerBlockEntityMixin", + "implementations.terra.inventory.item.ItemMixin", + "implementations.terra.inventory.item.ItemStackMixin", + "implementations.terra.inventory.meta.EnchantmentMixin", + "implementations.terra.inventory.meta.ItemStackDamageableMixin", + "implementations.terra.inventory.meta.ItemStackMetaMixin", + "implementations.terra.world.ChunkRegionMixin", + "implementations.terra.world.ServerWorldMixin" ], "client": [ ], From 6ba4a48e29371e311ae6cd74fe370058032a36da Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 21 Jun 2022 18:00:48 -0700 Subject: [PATCH 31/38] move biomeutil stuff into common --- .../lifecycle/DataPackContentsMixin.java | 5 +- .../dfsek/terra/fabric/util/BiomeUtil.java | 109 +--------------- .../com/dfsek/terra/fabric/util/TagUtil.java | 2 +- .../lifecycle/DataPackContentsMixin.java | 4 +- .../com/dfsek/terra/forge/util/BiomeUtil.java | 120 ++---------------- .../com/dfsek/terra/forge/util/TagUtil.java | 2 +- .../dfsek/terra/mod/util/MinecraftUtil.java | 112 ++++++++++++++++ 7 files changed, 133 insertions(+), 221 deletions(-) diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/DataPackContentsMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/DataPackContentsMixin.java index f2e38a11d..e355e4f2d 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/DataPackContentsMixin.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/DataPackContentsMixin.java @@ -1,7 +1,8 @@ package com.dfsek.terra.fabric.mixin.lifecycle; -import com.dfsek.terra.fabric.util.BiomeUtil; import com.dfsek.terra.fabric.util.TagUtil; +import com.dfsek.terra.mod.util.MinecraftUtil; + import net.minecraft.server.DataPackContents; import net.minecraft.util.registry.DynamicRegistryManager; import net.minecraft.util.registry.Registry; @@ -23,6 +24,6 @@ public class DataPackContentsMixin { Registry biomeRegistry = dynamicRegistryManager.get(Registry.BIOME_KEY); TagUtil.registerBiomeTags(biomeRegistry); - BiomeUtil.registerFlora(biomeRegistry); + MinecraftUtil.registerFlora(biomeRegistry); } } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/BiomeUtil.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/BiomeUtil.java index 678d7777a..769c9e65b 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/BiomeUtil.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/BiomeUtil.java @@ -4,9 +4,7 @@ import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.fabric.FabricEntryPoint; import com.dfsek.terra.mod.config.PreLoadCompatibilityOptions; -import com.dfsek.terra.mod.config.VanillaBiomeProperties; -import com.dfsek.terra.mod.mixin_ifaces.FloraFeatureHolder; import com.dfsek.terra.mod.config.ProtoPlatformBiome; import com.dfsek.terra.mod.util.MinecraftUtil; @@ -14,10 +12,6 @@ import net.minecraft.util.Identifier; import net.minecraft.util.registry.BuiltinRegistries; import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.RegistryKey; -import net.minecraft.world.biome.Biome.Builder; -import net.minecraft.world.biome.BiomeEffects; -import net.minecraft.world.biome.GenerationSettings; -import net.minecraft.world.gen.feature.ConfiguredFeature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -27,25 +21,17 @@ import java.util.*; public final class BiomeUtil { private static final Logger logger = LoggerFactory.getLogger(BiomeUtil.class); - private static final Map> - TERRA_BIOME_MAP = new HashMap<>(); - private BiomeUtil() { } - public static String createBiomeID(ConfigPack pack, com.dfsek.terra.api.registry.key.RegistryKey biomeID) { - return pack.getID() - .toLowerCase() + "/" + biomeID.getNamespace().toLowerCase(Locale.ROOT) + "/" + biomeID.getID().toLowerCase(Locale.ROOT); - } - public static void registerBiomes() { logger.info("Registering biomes..."); FabricEntryPoint.getPlatform().getConfigRegistry().forEach(pack -> { // Register all Terra biomes. pack.getCheckedRegistry(Biome.class) .forEach((id, biome) -> registerBiome(biome, pack, id)); }); - registerFlora(BuiltinRegistries.BIOME); + MinecraftUtil.registerFlora(BuiltinRegistries.BIOME); logger.info("Terra biomes registered."); } @@ -64,9 +50,9 @@ public final class BiomeUtil { if(pack.getContext().get(PreLoadCompatibilityOptions.class).useVanillaBiomes()) { ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(vanilla); } else { - net.minecraft.world.biome.Biome minecraftBiome = createBiome(biome, registry.get(vanilla)); + net.minecraft.world.biome.Biome minecraftBiome = MinecraftUtil.createBiome(biome, registry.get(vanilla)); - Identifier identifier = new Identifier("terra", createBiomeID(pack, id)); + Identifier identifier = new Identifier("terra", MinecraftUtil.createBiomeID(pack, id)); if(registry.containsId(identifier)) { ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(MinecraftUtil.getEntry(registry, identifier) @@ -75,97 +61,12 @@ public final class BiomeUtil { .orElseThrow()); } else { ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(BuiltinRegistries.add(registry, - registerKey(identifier).getValue(), + MinecraftUtil.registerKey(identifier).getValue(), minecraftBiome).getKey().orElseThrow()); } - TERRA_BIOME_MAP.computeIfAbsent(vanilla.getValue(), i -> new ArrayList<>()).add(identifier); + MinecraftUtil.TERRA_BIOME_MAP.computeIfAbsent(vanilla.getValue(), i -> new ArrayList<>()).add(identifier); } } - public static void registerFlora(Registry biomes) { - logger.info("Injecting flora into Terra biomes..."); - TERRA_BIOME_MAP - .forEach((vb, terraBiomes) -> - biomes.getOrEmpty(vb) - .ifPresentOrElse(vanilla -> terraBiomes - .forEach(tb -> biomes.getOrEmpty(tb) - .ifPresentOrElse( - terra -> { - List> flowerFeatures = List.copyOf(vanilla.getGenerationSettings().getFlowerFeatures()); - logger.debug("Injecting flora into biome {} : {}", tb, flowerFeatures); - ((FloraFeatureHolder) terra.getGenerationSettings()).setFloraFeatures(flowerFeatures); - }, - () -> logger.error( - "No such biome: {}", - tb))), - () -> logger.error("No vanilla biome: {}", vb))); - - } - - public static Map> getTerraBiomeMap() { - return Map.copyOf(TERRA_BIOME_MAP); - } - - private static RegistryKey registerKey(Identifier identifier) { - return RegistryKey.of(Registry.BIOME_KEY, identifier); - } - - public static net.minecraft.world.biome.Biome createBiome(Biome biome, net.minecraft.world.biome.Biome vanilla) { - GenerationSettings.Builder generationSettings = new GenerationSettings.Builder(); - - BiomeEffects.Builder effects = new BiomeEffects.Builder(); - - net.minecraft.world.biome.Biome.Builder builder = new Builder(); - - if(biome.getContext().has(VanillaBiomeProperties.class)) { - VanillaBiomeProperties vanillaBiomeProperties = biome.getContext().get(VanillaBiomeProperties.class); - - effects.waterColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterColor(), vanilla.getWaterColor())) - .waterFogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterFogColor(), vanilla.getWaterFogColor())) - .fogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getFogColor(), vanilla.getFogColor())) - .skyColor(Objects.requireNonNullElse(vanillaBiomeProperties.getSkyColor(), vanilla.getSkyColor())) - .grassColorModifier( - Objects.requireNonNullElse(vanillaBiomeProperties.getModifier(), vanilla.getEffects().getGrassColorModifier())); - - - if(vanillaBiomeProperties.getGrassColor() == null) { - vanilla.getEffects().getGrassColor().ifPresent(effects::grassColor); - } else { - effects.grassColor(vanillaBiomeProperties.getGrassColor()); - } - - if(vanillaBiomeProperties.getFoliageColor() == null) { - vanilla.getEffects().getFoliageColor().ifPresent(effects::foliageColor); - } else { - effects.foliageColor(vanillaBiomeProperties.getFoliageColor()); - } - - builder.precipitation(Objects.requireNonNullElse(vanillaBiomeProperties.getPrecipitation(), vanilla.getPrecipitation())); - - } else { - effects.waterColor(vanilla.getWaterColor()) - .waterFogColor(vanilla.getWaterFogColor()) - .fogColor(vanilla.getFogColor()) - .skyColor(vanilla.getSkyColor()); - vanilla.getEffects().getFoliageColor().ifPresent(effects::foliageColor); - vanilla.getEffects().getGrassColor().ifPresent(effects::grassColor); - - builder.precipitation(vanilla.getPrecipitation()); - } - - vanilla.getLoopSound().ifPresent(effects::loopSound); - vanilla.getAdditionsSound().ifPresent(effects::additionsSound); - vanilla.getMoodSound().ifPresent(effects::moodSound); - vanilla.getMusic().ifPresent(effects::music); - vanilla.getParticleConfig().ifPresent(effects::particleConfig); - - return builder - .temperature(vanilla.getTemperature()) - .downfall(vanilla.getDownfall()) - .effects(effects.build()) - .spawnSettings(vanilla.getSpawnSettings()) - .generationSettings(generationSettings.build()) - .build(); - } } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java index 78759c4f4..78c180283 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java @@ -56,7 +56,7 @@ public final class TagUtil { logger.info("Doing biome tag garbage...."); Map, List>> collect = tagsToMutableMap(registry); - BiomeUtil + MinecraftUtil .getTerraBiomeMap() .forEach((vb, terraBiomes) -> MinecraftUtil diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/DataPackContentsMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/DataPackContentsMixin.java index fefb67df4..b7db9106a 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/DataPackContentsMixin.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/DataPackContentsMixin.java @@ -2,6 +2,8 @@ package com.dfsek.terra.forge.mixin.lifecycle; import com.dfsek.terra.forge.util.BiomeUtil; import com.dfsek.terra.forge.util.TagUtil; +import com.dfsek.terra.mod.util.MinecraftUtil; + import net.minecraft.server.DataPackContents; import net.minecraft.util.registry.DynamicRegistryManager; import net.minecraft.util.registry.Registry; @@ -23,6 +25,6 @@ public class DataPackContentsMixin { Registry biomeRegistry = dynamicRegistryManager.get(Registry.BIOME_KEY); TagUtil.registerBiomeTags(biomeRegistry); - BiomeUtil.registerFlora(biomeRegistry); + MinecraftUtil.registerFlora(biomeRegistry); } } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java index c42db1143..28fe88ec2 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/BiomeUtil.java @@ -1,49 +1,31 @@ package com.dfsek.terra.forge.util; -import com.dfsek.terra.mod.config.ProtoPlatformBiome; - import net.minecraft.util.Identifier; import net.minecraft.util.registry.BuiltinRegistries; -import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.RegistryKey; -import net.minecraft.world.biome.Biome.Builder; -import net.minecraft.world.biome.BiomeEffects; -import net.minecraft.world.biome.GenerationSettings; -import net.minecraft.world.gen.feature.ConfiguredFeature; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegisterEvent.RegisterHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; import com.dfsek.terra.api.config.ConfigPack; import com.dfsek.terra.api.world.biome.Biome; import com.dfsek.terra.forge.ForgeEntryPoint; import com.dfsek.terra.mod.config.PreLoadCompatibilityOptions; -import com.dfsek.terra.mod.config.VanillaBiomeProperties; -import com.dfsek.terra.mod.mixin_ifaces.FloraFeatureHolder; +import com.dfsek.terra.mod.config.ProtoPlatformBiome; +import com.dfsek.terra.mod.util.MinecraftUtil; public final class BiomeUtil { private static final Logger logger = LoggerFactory.getLogger(BiomeUtil.class); - private static final Map> - TERRA_BIOME_MAP = new HashMap<>(); private BiomeUtil() { } - - public static String createBiomeID(ConfigPack pack, com.dfsek.terra.api.registry.key.RegistryKey biomeID) { - return pack.getID() - .toLowerCase() + "/" + biomeID.getNamespace().toLowerCase(Locale.ROOT) + "/" + biomeID.getID().toLowerCase(Locale.ROOT); - } + public static void registerBiomes(RegisterHelper helper) { logger.info("Registering biomes..."); @@ -51,7 +33,7 @@ public final class BiomeUtil { pack.getCheckedRegistry(Biome.class) .forEach((id, biome) -> registerBiome(biome, pack, id, helper)); }); - registerFlora(BuiltinRegistries.BIOME); + MinecraftUtil.registerFlora(BuiltinRegistries.BIOME); logger.info("Terra biomes registered."); } @@ -69,104 +51,18 @@ public final class BiomeUtil { if(pack.getContext().get(PreLoadCompatibilityOptions.class).useVanillaBiomes()) { ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(vanilla); } else { - net.minecraft.world.biome.Biome minecraftBiome = createBiome(biome, ForgeRegistries.BIOMES.getDelegateOrThrow(vanilla).value()); + net.minecraft.world.biome.Biome minecraftBiome = MinecraftUtil.createBiome(biome, ForgeRegistries.BIOMES.getDelegateOrThrow(vanilla).value()); - Identifier identifier = new Identifier("terra", createBiomeID(pack, id)); + Identifier identifier = new Identifier("terra", MinecraftUtil.createBiomeID(pack, id)); if(ForgeRegistries.BIOMES.containsKey(identifier)) { ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(ForgeRegistries.BIOMES.getHolder(identifier).orElseThrow().getKey().orElseThrow()); } else { - helper.register(registerKey(identifier).getValue(), minecraftBiome); + helper.register(MinecraftUtil.registerKey(identifier).getValue(), minecraftBiome); ((ProtoPlatformBiome) biome.getPlatformBiome()).setDelegate(ForgeRegistries.BIOMES.getHolder(identifier).orElseThrow().getKey().orElseThrow()); } - TERRA_BIOME_MAP.computeIfAbsent(vanilla.getValue(), i -> new ArrayList<>()).add(identifier); + MinecraftUtil.TERRA_BIOME_MAP.computeIfAbsent(vanilla.getValue(), i -> new ArrayList<>()).add(identifier); } } - - public static void registerFlora(Registry biomes) { - logger.info("Injecting flora into Terra biomes..."); - TERRA_BIOME_MAP - .forEach((vb, terraBiomes) -> - biomes.getOrEmpty(vb) - .ifPresentOrElse(vanilla -> terraBiomes - .forEach(tb -> biomes.getOrEmpty(tb) - .ifPresentOrElse( - terra -> { - List> flowerFeatures = List.copyOf(vanilla.getGenerationSettings().getFlowerFeatures()); - logger.debug("Injecting flora into biome {} : {}", tb, flowerFeatures); - ((FloraFeatureHolder) terra.getGenerationSettings()).setFloraFeatures(flowerFeatures); - }, - () -> logger.error( - "No such biome: {}", - tb))), - () -> logger.error("No vanilla biome: {}", vb))); - - } - - public static Map> getTerraBiomeMap() { - return Map.copyOf(TERRA_BIOME_MAP); - } - - private static RegistryKey registerKey(Identifier identifier) { - return RegistryKey.of(Registry.BIOME_KEY, identifier); - } - - public static net.minecraft.world.biome.Biome createBiome(Biome biome, net.minecraft.world.biome.Biome vanilla) { - GenerationSettings.Builder generationSettings = new GenerationSettings.Builder(); - - BiomeEffects.Builder effects = new BiomeEffects.Builder(); - - net.minecraft.world.biome.Biome.Builder builder = new Builder(); - - if(biome.getContext().has(VanillaBiomeProperties.class)) { - VanillaBiomeProperties vanillaBiomeProperties = biome.getContext().get(VanillaBiomeProperties.class); - - effects.waterColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterColor(), vanilla.getWaterColor())) - .waterFogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterFogColor(), vanilla.getWaterFogColor())) - .fogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getFogColor(), vanilla.getFogColor())) - .skyColor(Objects.requireNonNullElse(vanillaBiomeProperties.getSkyColor(), vanilla.getSkyColor())) - .grassColorModifier( - Objects.requireNonNullElse(vanillaBiomeProperties.getModifier(), vanilla.getEffects().getGrassColorModifier())); - - - if(vanillaBiomeProperties.getGrassColor() == null) { - vanilla.getEffects().getGrassColor().ifPresent(effects::grassColor); - } else { - effects.grassColor(vanillaBiomeProperties.getGrassColor()); - } - - if(vanillaBiomeProperties.getFoliageColor() == null) { - vanilla.getEffects().getFoliageColor().ifPresent(effects::foliageColor); - } else { - effects.foliageColor(vanillaBiomeProperties.getFoliageColor()); - } - - builder.precipitation(Objects.requireNonNullElse(vanillaBiomeProperties.getPrecipitation(), vanilla.getPrecipitation())); - - } else { - effects.waterColor(vanilla.getWaterColor()) - .waterFogColor(vanilla.getWaterFogColor()) - .fogColor(vanilla.getFogColor()) - .skyColor(vanilla.getSkyColor()); - vanilla.getEffects().getFoliageColor().ifPresent(effects::foliageColor); - vanilla.getEffects().getGrassColor().ifPresent(effects::grassColor); - - builder.precipitation(vanilla.getPrecipitation()); - } - - vanilla.getLoopSound().ifPresent(effects::loopSound); - vanilla.getAdditionsSound().ifPresent(effects::additionsSound); - vanilla.getMoodSound().ifPresent(effects::moodSound); - vanilla.getMusic().ifPresent(effects::music); - vanilla.getParticleConfig().ifPresent(effects::particleConfig); - - return builder - .temperature(vanilla.getTemperature()) - .downfall(vanilla.getDownfall()) - .effects(effects.build()) - .spawnSettings(vanilla.getSpawnSettings()) - .generationSettings(generationSettings.build()) - .build(); - } } diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java index 42f001e8e..38a1e2237 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java @@ -56,7 +56,7 @@ public final class TagUtil { logger.info("Doing biome tag garbage...."); Map, List>> collect = tagsToMutableMap(registry); - BiomeUtil + MinecraftUtil .getTerraBiomeMap() .forEach((vb, terraBiomes) -> MinecraftUtil diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/MinecraftUtil.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/MinecraftUtil.java index 9f7a36712..80178c3be 100644 --- a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/MinecraftUtil.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/MinecraftUtil.java @@ -5,6 +5,10 @@ import com.dfsek.terra.api.block.entity.Container; import com.dfsek.terra.api.block.entity.MobSpawner; import com.dfsek.terra.api.block.entity.Sign; +import com.dfsek.terra.api.config.ConfigPack; +import com.dfsek.terra.mod.config.VanillaBiomeProperties; +import com.dfsek.terra.mod.mixin_ifaces.FloraFeatureHolder; + import net.minecraft.block.entity.LootableContainerBlockEntity; import net.minecraft.block.entity.MobSpawnerBlockEntity; import net.minecraft.block.entity.SignBlockEntity; @@ -12,12 +16,29 @@ import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; import net.minecraft.util.registry.Registry; import net.minecraft.util.registry.RegistryEntry; +import net.minecraft.util.registry.RegistryKey; import net.minecraft.world.WorldAccess; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.Biome.Builder; +import net.minecraft.world.biome.BiomeEffects; +import net.minecraft.world.biome.GenerationSettings; +import net.minecraft.world.gen.feature.ConfiguredFeature; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; import java.util.Optional; public final class MinecraftUtil { + public static final Logger logger = LoggerFactory.getLogger(MinecraftUtil.class); + public static final Map> + TERRA_BIOME_MAP = new HashMap<>(); + private MinecraftUtil() { } @@ -39,4 +60,95 @@ public final class MinecraftUtil { } return null; } + + public static void registerFlora(Registry biomes) { + logger.info("Injecting flora into Terra biomes..."); + TERRA_BIOME_MAP + .forEach((vb, terraBiomes) -> + biomes.getOrEmpty(vb) + .ifPresentOrElse(vanilla -> terraBiomes + .forEach(tb -> biomes.getOrEmpty(tb) + .ifPresentOrElse( + terra -> { + List> flowerFeatures = List.copyOf(vanilla.getGenerationSettings().getFlowerFeatures()); + logger.debug("Injecting flora into biome {} : {}", tb, flowerFeatures); + ((FloraFeatureHolder) terra.getGenerationSettings()).setFloraFeatures(flowerFeatures); + }, + () -> logger.error( + "No such biome: {}", + tb))), + () -> logger.error("No vanilla biome: {}", vb))); + + } + + public static Map> getTerraBiomeMap() { + return Map.copyOf(TERRA_BIOME_MAP); + } + + public static RegistryKey registerKey(Identifier identifier) { + return RegistryKey.of(Registry.BIOME_KEY, identifier); + } + + public static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla) { + GenerationSettings.Builder generationSettings = new GenerationSettings.Builder(); + + BiomeEffects.Builder effects = new BiomeEffects.Builder(); + + Biome.Builder builder = new Builder(); + + if(biome.getContext().has(VanillaBiomeProperties.class)) { + VanillaBiomeProperties vanillaBiomeProperties = biome.getContext().get(VanillaBiomeProperties.class); + + effects.waterColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterColor(), vanilla.getWaterColor())) + .waterFogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterFogColor(), vanilla.getWaterFogColor())) + .fogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getFogColor(), vanilla.getFogColor())) + .skyColor(Objects.requireNonNullElse(vanillaBiomeProperties.getSkyColor(), vanilla.getSkyColor())) + .grassColorModifier( + Objects.requireNonNullElse(vanillaBiomeProperties.getModifier(), vanilla.getEffects().getGrassColorModifier())); + + + if(vanillaBiomeProperties.getGrassColor() == null) { + vanilla.getEffects().getGrassColor().ifPresent(effects::grassColor); + } else { + effects.grassColor(vanillaBiomeProperties.getGrassColor()); + } + + if(vanillaBiomeProperties.getFoliageColor() == null) { + vanilla.getEffects().getFoliageColor().ifPresent(effects::foliageColor); + } else { + effects.foliageColor(vanillaBiomeProperties.getFoliageColor()); + } + + builder.precipitation(Objects.requireNonNullElse(vanillaBiomeProperties.getPrecipitation(), vanilla.getPrecipitation())); + + } else { + effects.waterColor(vanilla.getWaterColor()) + .waterFogColor(vanilla.getWaterFogColor()) + .fogColor(vanilla.getFogColor()) + .skyColor(vanilla.getSkyColor()); + vanilla.getEffects().getFoliageColor().ifPresent(effects::foliageColor); + vanilla.getEffects().getGrassColor().ifPresent(effects::grassColor); + + builder.precipitation(vanilla.getPrecipitation()); + } + + vanilla.getLoopSound().ifPresent(effects::loopSound); + vanilla.getAdditionsSound().ifPresent(effects::additionsSound); + vanilla.getMoodSound().ifPresent(effects::moodSound); + vanilla.getMusic().ifPresent(effects::music); + vanilla.getParticleConfig().ifPresent(effects::particleConfig); + + return builder + .temperature(vanilla.getTemperature()) + .downfall(vanilla.getDownfall()) + .effects(effects.build()) + .spawnSettings(vanilla.getSpawnSettings()) + .generationSettings(generationSettings.build()) + .build(); + } + + public static String createBiomeID(ConfigPack pack, com.dfsek.terra.api.registry.key.RegistryKey biomeID) { + return pack.getID() + .toLowerCase() + "/" + biomeID.getNamespace().toLowerCase(Locale.ROOT) + "/" + biomeID.getID().toLowerCase(Locale.ROOT); + } } From 3b156586dc8f1bd56d8a37319d093e75e8f47801 Mon Sep 17 00:00:00 2001 From: dfsek Date: Tue, 21 Jun 2022 18:21:54 -0700 Subject: [PATCH 32/38] common-ify LifecycleUtil --- .../terra/api/util/generic/pair/Pair.java | 6 ++ .../dfsek/terra/fabric/FabricEntryPoint.java | 12 +++ .../com/dfsek/terra/fabric/PlatformImpl.java | 12 +++ .../client/MinecraftClientMixin.java | 6 +- .../lifecycle/server/ServerMainMixin.java | 6 +- .../com/dfsek/terra/fabric/util/TagUtil.java | 4 +- .../dfsek/terra/forge/ForgeEntryPoint.java | 16 ++- .../com/dfsek/terra/forge/PlatformImpl.java | 6 ++ .../dfsek/terra/forge/util/LifecycleUtil.java | 102 ------------------ .../com/dfsek/terra/forge/util/TagUtil.java | 4 +- .../java/com/dfsek/terra/mod/ModPlatform.java | 10 ++ .../com/dfsek/terra/mod/util/PresetUtil.java} | 71 ++++++------ 12 files changed, 97 insertions(+), 158 deletions(-) delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java rename platforms/{fabric/src/main/java/com/dfsek/terra/fabric/util/LifecycleUtil.java => mod-common/src/main/java/com/dfsek/terra/mod/util/PresetUtil.java} (65%) diff --git a/common/api/src/main/java/com/dfsek/terra/api/util/generic/pair/Pair.java b/common/api/src/main/java/com/dfsek/terra/api/util/generic/pair/Pair.java index ad4c2c879..4727b57e2 100644 --- a/common/api/src/main/java/com/dfsek/terra/api/util/generic/pair/Pair.java +++ b/common/api/src/main/java/com/dfsek/terra/api/util/generic/pair/Pair.java @@ -11,6 +11,7 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import java.util.Objects; +import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -145,6 +146,11 @@ public final class Pair { } } + public Pair apply(BiConsumer consumer) { + consumer.accept(this.left, this.right); + return this; + } + @Override public String toString() { return String.format("{%s,%s}", left, right); diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricEntryPoint.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricEntryPoint.java index d85b330e0..ca110eccf 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricEntryPoint.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/FabricEntryPoint.java @@ -24,9 +24,14 @@ import cloud.commandframework.fabric.FabricServerCommandManager; import com.dfsek.terra.api.command.CommandSender; import com.dfsek.terra.api.event.events.platform.CommandRegistrationEvent; +import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; +import com.dfsek.terra.fabric.util.BiomeUtil; +import com.dfsek.terra.mod.CommonPlatform; + import net.fabricmc.api.ModInitializer; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.util.Identifier; +import net.minecraft.util.registry.BuiltinRegistries; import net.minecraft.util.registry.Registry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,6 +54,13 @@ public class FabricEntryPoint implements ModInitializer { Registry.register(Registry.BIOME_SOURCE, new Identifier("terra:terra"), Codecs.TERRA_BIOME_SOURCE); } + public static void initialize() { + getPlatform().getEventManager().callEvent( + new PlatformInitializationEvent()); + BiomeUtil.registerBiomes(); + CommonPlatform.get().registerWorldTypes((id, preset) -> BuiltinRegistries.add(BuiltinRegistries.WORLD_PRESET, id, preset)); + } + @Override public void onInitialize() { logger.info("Initializing Terra Fabric mod..."); diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/PlatformImpl.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/PlatformImpl.java index efa3bfe17..66ddb8c67 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/PlatformImpl.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/PlatformImpl.java @@ -25,9 +25,18 @@ import com.dfsek.terra.fabric.util.BiomeUtil; import com.dfsek.terra.mod.CommonPlatform; import com.dfsek.terra.mod.ModPlatform; +import com.dfsek.terra.mod.generation.TerraBiomeSource; + +import com.dfsek.terra.mod.util.PresetUtil; + import net.fabricmc.loader.api.FabricLoader; import net.minecraft.MinecraftVersion; import net.minecraft.server.MinecraftServer; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.BuiltinRegistries; +import net.minecraft.world.dimension.DimensionOptions; +import net.minecraft.world.gen.WorldPreset; +import net.minecraft.world.gen.chunk.ChunkGenerator; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -35,6 +44,9 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.function.BiConsumer; import com.dfsek.terra.addon.EphemeralAddon; import com.dfsek.terra.api.addon.BaseAddon; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/client/MinecraftClientMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/client/MinecraftClientMixin.java index 620ebf100..b605d8cdb 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/client/MinecraftClientMixin.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/client/MinecraftClientMixin.java @@ -17,8 +17,6 @@ package com.dfsek.terra.fabric.mixin.lifecycle.client; -import com.dfsek.terra.fabric.util.LifecycleUtil; - import net.minecraft.client.MinecraftClient; import net.minecraft.client.RunArgs; import org.spongepowered.asm.mixin.Mixin; @@ -26,9 +24,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; import com.dfsek.terra.fabric.FabricEntryPoint; -import com.dfsek.terra.fabric.util.BiomeUtil; @Mixin(MinecraftClient.class) @@ -40,6 +36,6 @@ public class MinecraftClientMixin { // sorta arbitrary position, after mod init, before window opens shift = At.Shift.BEFORE)) public void injectConstructor(RunArgs args, CallbackInfo callbackInfo) { - LifecycleUtil.initialize(); + FabricEntryPoint.initialize(); } } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/server/ServerMainMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/server/ServerMainMixin.java index ecf5e933b..16e107631 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/server/ServerMainMixin.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/server/ServerMainMixin.java @@ -17,16 +17,12 @@ package com.dfsek.terra.fabric.mixin.lifecycle.server; -import com.dfsek.terra.fabric.util.BiomeUtil; -import com.dfsek.terra.fabric.util.LifecycleUtil; - import net.minecraft.server.Main; 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 com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; import com.dfsek.terra.fabric.FabricEntryPoint; @@ -39,6 +35,6 @@ public class ServerMainMixin { // after registry manager creation ) private static void injectConstructor(String[] args, CallbackInfo ci) { - LifecycleUtil.initialize(); + FabricEntryPoint.initialize(); } } diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java index 78c180283..f921cba34 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java @@ -2,6 +2,8 @@ package com.dfsek.terra.fabric.util; import com.dfsek.terra.mod.util.MinecraftUtil; +import com.dfsek.terra.mod.util.PresetUtil; + import com.google.common.collect.ImmutableMap; import net.minecraft.tag.TagKey; import net.minecraft.tag.WorldPresetTags; @@ -38,7 +40,7 @@ public final class TagUtil { logger.info("Doing preset tag garbage...."); Map, List>> collect = tagsToMutableMap(registry); - LifecycleUtil + PresetUtil .getPresets() .forEach(id -> MinecraftUtil .getEntry(registry, id) diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java index 5208f01ec..dbc919781 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/ForgeEntryPoint.java @@ -17,8 +17,12 @@ package com.dfsek.terra.forge; +import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; +import com.dfsek.terra.forge.util.BiomeUtil; + import net.minecraft.util.Identifier; import net.minecraft.util.registry.Registry; +import net.minecraft.world.biome.Biome; import net.minecraftforge.eventbus.api.EventPriority; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -28,12 +32,12 @@ import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.registries.ForgeRegistries.Keys; import net.minecraftforge.registries.RegisterEvent; +import net.minecraftforge.registries.RegisterEvent.RegisterHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.dfsek.terra.forge.AwfulForgeHacks.RegistrySanityCheck; import com.dfsek.terra.forge.AwfulForgeHacks.RegistryStep; -import com.dfsek.terra.forge.util.LifecycleUtil; import com.dfsek.terra.mod.data.Codecs; @@ -62,11 +66,17 @@ public class ForgeEntryPoint { modEventBus.register(this); } + public static void initialize(RegisterHelper helper) { + getPlatform().getEventManager().callEvent( + new PlatformInitializationEvent()); + BiomeUtil.registerBiomes(helper); + } + @SubscribeEvent(priority = EventPriority.LOWEST) public void registerBiomes(RegisterEvent event) { event.register(Keys.BLOCKS, helper -> sanityCheck.progress(RegistryStep.BLOCK, () -> logger.debug("Block registration detected."))); - event.register(Keys.BIOMES, helper -> sanityCheck.progress(RegistryStep.BIOME, () -> LifecycleUtil.initialize(helper))); - event.register(Registry.WORLD_PRESET_KEY, helper -> sanityCheck.progress(RegistryStep.WORLD_TYPE, () -> LifecycleUtil.registerWorldTypes(helper))); + event.register(Keys.BIOMES, helper -> sanityCheck.progress(RegistryStep.BIOME, () -> initialize(helper))); + event.register(Registry.WORLD_PRESET_KEY, helper -> sanityCheck.progress(RegistryStep.WORLD_TYPE, () -> TERRA_PLUGIN.registerWorldTypes(helper::register))); event.register(Registry.CHUNK_GENERATOR_KEY, helper -> helper.register(new Identifier("terra:terra"), Codecs.MINECRAFT_CHUNK_GENERATOR_WRAPPER)); diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java index 294fa01d9..b3996a9d8 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/PlatformImpl.java @@ -20,8 +20,13 @@ package com.dfsek.terra.forge; import ca.solostudios.strata.Versions; import ca.solostudios.strata.parser.tokenizer.ParseException; import ca.solostudios.strata.version.Version; + +import com.dfsek.terra.mod.util.PresetUtil; + import net.minecraft.MinecraftVersion; import net.minecraft.server.MinecraftServer; +import net.minecraft.util.Identifier; +import net.minecraft.world.gen.WorldPreset; import net.minecraftforge.fml.loading.FMLLoader; import net.minecraftforge.server.ServerLifecycleHooks; import org.jetbrains.annotations.NotNull; @@ -31,6 +36,7 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.function.BiConsumer; import com.dfsek.terra.addon.EphemeralAddon; import com.dfsek.terra.api.addon.BaseAddon; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java deleted file mode 100644 index abaabaa0e..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/LifecycleUtil.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.dfsek.terra.forge.util; - -import net.minecraft.structure.StructureSet; -import net.minecraft.util.Identifier; -import net.minecraft.util.math.noise.DoublePerlinNoiseSampler.NoiseParameters; -import net.minecraft.util.registry.BuiltinRegistries; -import net.minecraft.util.registry.Registry; -import net.minecraft.util.registry.RegistryEntry; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.biome.source.MultiNoiseBiomeSource; -import net.minecraft.world.biome.source.TheEndBiomeSource; -import net.minecraft.world.dimension.DimensionOptions; -import net.minecraft.world.dimension.DimensionType; -import net.minecraft.world.dimension.DimensionTypes; -import net.minecraft.world.gen.WorldPreset; -import net.minecraft.world.gen.chunk.ChunkGenerator; -import net.minecraft.world.gen.chunk.ChunkGeneratorSettings; -import net.minecraft.world.gen.chunk.NoiseChunkGenerator; -import net.minecraftforge.registries.RegisterEvent.RegisterHelper; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; -import com.dfsek.terra.forge.ForgeEntryPoint; -import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; -import com.dfsek.terra.mod.generation.TerraBiomeSource; - - -public class LifecycleUtil { - private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleUtil.class); - - private static final List PRESETS = new ArrayList<>(); - public static void initialize(RegisterHelper helper) { - ForgeEntryPoint.getPlatform().getEventManager().callEvent( - new PlatformInitializationEvent()); - BiomeUtil.registerBiomes(helper); - } - - public static void registerWorldTypes(RegisterHelper helper) { - LOGGER.info("Registering Terra world types..."); - - Registry dimensionTypeRegistry = BuiltinRegistries.DIMENSION_TYPE; - Registry chunkGeneratorSettingsRegistry = BuiltinRegistries.CHUNK_GENERATOR_SETTINGS; - Registry structureSetRegistry = BuiltinRegistries.STRUCTURE_SET; - Registry noiseParametersRegistry = BuiltinRegistries.NOISE_PARAMETERS; - Registry biomeRegistry = BuiltinRegistries.BIOME; - - RegistryEntry theNetherDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.THE_NETHER); - RegistryEntry - netherChunkGeneratorSettings = chunkGeneratorSettingsRegistry.getOrCreateEntry(ChunkGeneratorSettings.NETHER); - DimensionOptions netherDimensionOptions = new DimensionOptions(theNetherDimensionType, - new NoiseChunkGenerator(structureSetRegistry, - noiseParametersRegistry, - MultiNoiseBiomeSource.Preset.NETHER.getBiomeSource( - biomeRegistry), - netherChunkGeneratorSettings)); - RegistryEntry theEndDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.THE_END); - RegistryEntry endChunkGeneratorSettings = chunkGeneratorSettingsRegistry.getOrCreateEntry( - ChunkGeneratorSettings.END); - DimensionOptions endDimensionOptions = new DimensionOptions(theEndDimensionType, - new NoiseChunkGenerator(structureSetRegistry, noiseParametersRegistry, - new TheEndBiomeSource(biomeRegistry), - endChunkGeneratorSettings)); - - RegistryEntry overworldDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.OVERWORLD); - - RegistryEntry overworld = chunkGeneratorSettingsRegistry.getOrCreateEntry(ChunkGeneratorSettings.OVERWORLD); - ForgeEntryPoint - .getPlatform() - .getRawConfigRegistry() - .forEach((id, pack) -> { - Identifier generatorID = Identifier.of("terra", pack.getID().toLowerCase(Locale.ROOT) + "/" + pack.getNamespace().toLowerCase( - Locale.ROOT)); - - PRESETS.add(generatorID); - - TerraBiomeSource biomeSource = new TerraBiomeSource(biomeRegistry, pack); - ChunkGenerator generator = new MinecraftChunkGeneratorWrapper(structureSetRegistry, biomeSource, pack, overworld); - - DimensionOptions dimensionOptions = new DimensionOptions(overworldDimensionType, generator); - WorldPreset preset = new WorldPreset( - Map.of( - DimensionOptions.OVERWORLD, dimensionOptions, - DimensionOptions.NETHER, netherDimensionOptions, - DimensionOptions.END, endDimensionOptions - ) - ); - helper.register(generatorID, preset); - LOGGER.info("Registered world type \"{}\"", generatorID); - } - ); - } - - public static List getPresets() { - return PRESETS; - } -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java index 38a1e2237..462a6719e 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java @@ -2,6 +2,8 @@ package com.dfsek.terra.forge.util; import com.dfsek.terra.mod.util.MinecraftUtil; +import com.dfsek.terra.mod.util.PresetUtil; + import com.google.common.collect.ImmutableMap; import net.minecraft.tag.TagKey; import net.minecraft.tag.WorldPresetTags; @@ -38,7 +40,7 @@ public final class TagUtil { logger.info("Doing preset tag garbage...."); Map, List>> collect = tagsToMutableMap(registry); - LifecycleUtil + PresetUtil .getPresets() .forEach(id -> MinecraftUtil .getEntry(registry, id) diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/ModPlatform.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/ModPlatform.java index 48fa219c2..5a75d0cc2 100644 --- a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/ModPlatform.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/ModPlatform.java @@ -12,6 +12,8 @@ import com.dfsek.terra.api.world.biome.PlatformBiome; import com.dfsek.terra.mod.config.ProtoPlatformBiome; +import com.dfsek.terra.mod.util.PresetUtil; + import net.minecraft.command.CommandSource; import net.minecraft.server.MinecraftServer; import net.minecraft.util.Identifier; @@ -19,14 +21,22 @@ import net.minecraft.util.registry.BuiltinRegistries; import net.minecraft.world.biome.Biome; import net.minecraft.world.biome.Biome.Precipitation; import net.minecraft.world.biome.BiomeEffects.GrassColorModifier; +import net.minecraft.world.gen.WorldPreset; import java.util.List; import java.util.Locale; +import java.util.function.BiConsumer; +import java.util.function.Consumer; public abstract class ModPlatform extends AbstractPlatform { public abstract MinecraftServer getServer(); + public void registerWorldTypes(BiConsumer registerFunction) { + getRawConfigRegistry() + .forEach(pack -> PresetUtil.createDefault(pack).apply(registerFunction)); + } + @Override public void register(TypeRegistry registry) { super.register(registry); diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/LifecycleUtil.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/PresetUtil.java similarity index 65% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/LifecycleUtil.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/PresetUtil.java index d91d4e263..7b3e57ca5 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/LifecycleUtil.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/PresetUtil.java @@ -1,7 +1,8 @@ -package com.dfsek.terra.fabric.util; +package com.dfsek.terra.mod.util; -import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent; -import com.dfsek.terra.fabric.FabricEntryPoint; +import com.dfsek.terra.api.config.ConfigPack; + +import com.dfsek.terra.api.util.generic.pair.Pair; import com.dfsek.terra.mod.generation.MinecraftChunkGeneratorWrapper; import com.dfsek.terra.mod.generation.TerraBiomeSource; @@ -30,24 +31,17 @@ import java.util.Locale; import java.util.Map; -public class LifecycleUtil { - private static final Logger LOGGER = LoggerFactory.getLogger(LifecycleUtil.class); - +public class PresetUtil { + private static final Logger LOGGER = LoggerFactory.getLogger(PresetUtil.class); private static final List PRESETS = new ArrayList<>(); - public static void initialize() { - FabricEntryPoint.getPlatform().getEventManager().callEvent( - new PlatformInitializationEvent()); - BiomeUtil.registerBiomes(); - - - LOGGER.info("Registering Terra world types..."); - + + public static Pair createDefault(ConfigPack pack) { Registry dimensionTypeRegistry = BuiltinRegistries.DIMENSION_TYPE; Registry chunkGeneratorSettingsRegistry = BuiltinRegistries.CHUNK_GENERATOR_SETTINGS; Registry structureSetRegistry = BuiltinRegistries.STRUCTURE_SET; Registry noiseParametersRegistry = BuiltinRegistries.NOISE_PARAMETERS; Registry biomeRegistry = BuiltinRegistries.BIOME; - + RegistryEntry theNetherDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.THE_NETHER); RegistryEntry netherChunkGeneratorSettings = chunkGeneratorSettingsRegistry.getOrCreateEntry(ChunkGeneratorSettings.NETHER); @@ -64,34 +58,29 @@ public class LifecycleUtil { new NoiseChunkGenerator(structureSetRegistry, noiseParametersRegistry, new TheEndBiomeSource(biomeRegistry), endChunkGeneratorSettings)); - + RegistryEntry overworldDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.OVERWORLD); - + RegistryEntry overworld = chunkGeneratorSettingsRegistry.getOrCreateEntry(ChunkGeneratorSettings.OVERWORLD); - FabricEntryPoint - .getPlatform() - .getRawConfigRegistry() - .forEach((id, pack) -> { - Identifier generatorID = Identifier.of("terra", pack.getID().toLowerCase(Locale.ROOT) + "/" + pack.getNamespace().toLowerCase( - Locale.ROOT)); - - PRESETS.add(generatorID); - - TerraBiomeSource biomeSource = new TerraBiomeSource(biomeRegistry, pack); - ChunkGenerator generator = new MinecraftChunkGeneratorWrapper(structureSetRegistry, biomeSource, pack, overworld); - - DimensionOptions dimensionOptions = new DimensionOptions(overworldDimensionType, generator); - WorldPreset preset = new WorldPreset( - Map.of( - DimensionOptions.OVERWORLD, dimensionOptions, - DimensionOptions.NETHER, netherDimensionOptions, - DimensionOptions.END, endDimensionOptions - ) - ); - BuiltinRegistries.add(BuiltinRegistries.WORLD_PRESET, generatorID, preset); - LOGGER.info("Registered world type \"{}\"", generatorID); - } - ); + + Identifier generatorID = Identifier.of("terra", pack.getID().toLowerCase(Locale.ROOT) + "/" + pack.getNamespace().toLowerCase( + Locale.ROOT)); + + PRESETS.add(generatorID); + + TerraBiomeSource biomeSource = new TerraBiomeSource(biomeRegistry, pack); + ChunkGenerator generator = new MinecraftChunkGeneratorWrapper(structureSetRegistry, biomeSource, pack, overworld); + + DimensionOptions dimensionOptions = new DimensionOptions(overworldDimensionType, generator); + WorldPreset preset = new WorldPreset( + Map.of( + DimensionOptions.OVERWORLD, dimensionOptions, + DimensionOptions.NETHER, netherDimensionOptions, + DimensionOptions.END, endDimensionOptions + ) + ); + LOGGER.info("Created world type \"{}\"", generatorID); + return Pair.of(generatorID, preset); } public static List getPresets() { From 2ae4f8035101cb09149a81481decab05a430c84c Mon Sep 17 00:00:00 2001 From: dfsek Date: Wed, 22 Jun 2022 06:10:41 -0700 Subject: [PATCH 33/38] move tagutil into common --- .../lifecycle/DataPackContentsMixin.java | 2 +- .../com/dfsek/terra/fabric/util/TagUtil.java | 107 ------------------ .../lifecycle/DataPackContentsMixin.java | 3 +- .../com/dfsek/terra/mod}/util/TagUtil.java | 6 +- 4 files changed, 4 insertions(+), 114 deletions(-) delete mode 100644 platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java rename platforms/{forge/src/main/java/com/dfsek/terra/forge => mod-common/src/main/java/com/dfsek/terra/mod}/util/TagUtil.java (97%) diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/DataPackContentsMixin.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/DataPackContentsMixin.java index e355e4f2d..5dcb1de72 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/DataPackContentsMixin.java +++ b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/DataPackContentsMixin.java @@ -1,6 +1,6 @@ package com.dfsek.terra.fabric.mixin.lifecycle; -import com.dfsek.terra.fabric.util.TagUtil; +import com.dfsek.terra.mod.util.TagUtil; import com.dfsek.terra.mod.util.MinecraftUtil; import net.minecraft.server.DataPackContents; diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java b/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java deleted file mode 100644 index f921cba34..000000000 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/util/TagUtil.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.dfsek.terra.fabric.util; - -import com.dfsek.terra.mod.util.MinecraftUtil; - -import com.dfsek.terra.mod.util.PresetUtil; - -import com.google.common.collect.ImmutableMap; -import net.minecraft.tag.TagKey; -import net.minecraft.tag.WorldPresetTags; -import net.minecraft.util.registry.Registry; -import net.minecraft.util.registry.RegistryEntry; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.gen.WorldPreset; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - - -public final class TagUtil { - private static final Logger logger = LoggerFactory.getLogger(TagUtil.class); - - private TagUtil() { - - } - - private static Map, List>> tagsToMutableMap(Registry registry) { - return registry - .streamTagsAndEntries() - .collect(HashMap::new, - (map, pair) -> - map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())), - HashMap::putAll); - } - - public static void registerWorldPresetTags(Registry registry) { - logger.info("Doing preset tag garbage...."); - Map, List>> collect = tagsToMutableMap(registry); - - PresetUtil - .getPresets() - .forEach(id -> MinecraftUtil - .getEntry(registry, id) - .ifPresentOrElse( - preset -> collect - .computeIfAbsent(WorldPresetTags.NORMAL, tag -> new ArrayList<>()) - .add(preset), - () -> logger.error("Preset {} does not exist!", id))); - - registry.clearTags(); - registry.populateTags(ImmutableMap.copyOf(collect)); - } - - public static void registerBiomeTags(Registry registry) { - logger.info("Doing biome tag garbage...."); - Map, List>> collect = tagsToMutableMap(registry); - - MinecraftUtil - .getTerraBiomeMap() - .forEach((vb, terraBiomes) -> - MinecraftUtil - .getEntry(registry, vb) - .ifPresentOrElse( - vanilla -> terraBiomes - .forEach(tb -> MinecraftUtil - .getEntry(registry, tb) - .ifPresentOrElse( - terra -> { - logger.debug( - vanilla.getKey() - .orElseThrow() - .getValue() + - " (vanilla for " + - terra.getKey() - .orElseThrow() - .getValue() + - ": " + - vanilla.streamTags() - .toList()); - - vanilla.streamTags() - .forEach( - tag -> collect - .computeIfAbsent( - tag, - t -> new ArrayList<>()) - .add(terra)); - }, - () -> logger.error( - "No such biome: {}", - tb))), - () -> logger.error("No vanilla biome: {}", vb))); - - registry.clearTags(); - registry.populateTags(ImmutableMap.copyOf(collect)); - - if(logger.isDebugEnabled()) { - registry.streamEntries() - .map(e -> e.registryKey().getValue() + ": " + - e.streamTags().reduce("", (s, t) -> t.id() + ", " + s, String::concat)) - .forEach(logger::debug); - } - } -} diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/DataPackContentsMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/DataPackContentsMixin.java index b7db9106a..99e886389 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/DataPackContentsMixin.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/DataPackContentsMixin.java @@ -1,9 +1,10 @@ package com.dfsek.terra.forge.mixin.lifecycle; import com.dfsek.terra.forge.util.BiomeUtil; -import com.dfsek.terra.forge.util.TagUtil; import com.dfsek.terra.mod.util.MinecraftUtil; +import com.dfsek.terra.mod.util.TagUtil; + import net.minecraft.server.DataPackContents; import net.minecraft.util.registry.DynamicRegistryManager; import net.minecraft.util.registry.Registry; diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/TagUtil.java similarity index 97% rename from platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/TagUtil.java index 462a6719e..8edf50afc 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/util/TagUtil.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/TagUtil.java @@ -1,8 +1,4 @@ -package com.dfsek.terra.forge.util; - -import com.dfsek.terra.mod.util.MinecraftUtil; - -import com.dfsek.terra.mod.util.PresetUtil; +package com.dfsek.terra.mod.util; import com.google.common.collect.ImmutableMap; import net.minecraft.tag.TagKey; From 42cf7b95437c38b4d510b0d9df5f7aecc9ce74c2 Mon Sep 17 00:00:00 2001 From: dfsek Date: Wed, 22 Jun 2022 06:31:38 -0700 Subject: [PATCH 34/38] move DataPackContentsMixin to common --- .../main/resources/terra.fabric.mixins.json | 1 - .../lifecycle/DataPackContentsMixin.java | 31 ------- .../main/resources/terra.forge.mixins.json | 1 - .../lifecycle/DataPackContentsMixin.java | 2 +- .../main/resources/terra.common.mixins.json | 89 ++++++++++--------- 5 files changed, 46 insertions(+), 78 deletions(-) delete mode 100644 platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/DataPackContentsMixin.java rename platforms/{fabric/src/main/java/com/dfsek/terra/fabric => mod-common/src/main/java/com/dfsek/terra/mod}/mixin/lifecycle/DataPackContentsMixin.java (95%) diff --git a/platforms/fabric/src/main/resources/terra.fabric.mixins.json b/platforms/fabric/src/main/resources/terra.fabric.mixins.json index d28c0541c..52882ee43 100644 --- a/platforms/fabric/src/main/resources/terra.fabric.mixins.json +++ b/platforms/fabric/src/main/resources/terra.fabric.mixins.json @@ -4,7 +4,6 @@ "package": "com.dfsek.terra.fabric.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ - "lifecycle.DataPackContentsMixin", "lifecycle.MinecraftServerMixin", "lifecycle.NoiseConfigMixin", "lifecycle.RegistryMixin" diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/DataPackContentsMixin.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/DataPackContentsMixin.java deleted file mode 100644 index 99e886389..000000000 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/mixin/lifecycle/DataPackContentsMixin.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.dfsek.terra.forge.mixin.lifecycle; - -import com.dfsek.terra.forge.util.BiomeUtil; -import com.dfsek.terra.mod.util.MinecraftUtil; - -import com.dfsek.terra.mod.util.TagUtil; - -import net.minecraft.server.DataPackContents; -import net.minecraft.util.registry.DynamicRegistryManager; -import net.minecraft.util.registry.Registry; -import net.minecraft.world.biome.Biome; -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; - - -@Mixin(DataPackContents.class) -public class DataPackContentsMixin { - /* - * #refresh populates all tags in the registries - */ - @Inject(method = "refresh(Lnet/minecraft/util/registry/DynamicRegistryManager;)V", at = @At("RETURN")) - private void injectReload(DynamicRegistryManager dynamicRegistryManager, CallbackInfo ci) { - TagUtil.registerWorldPresetTags(dynamicRegistryManager.get(Registry.WORLD_PRESET_KEY)); - - Registry biomeRegistry = dynamicRegistryManager.get(Registry.BIOME_KEY); - TagUtil.registerBiomeTags(biomeRegistry); - MinecraftUtil.registerFlora(biomeRegistry); - } -} diff --git a/platforms/forge/src/main/resources/terra.forge.mixins.json b/platforms/forge/src/main/resources/terra.forge.mixins.json index a1316f288..355d77483 100644 --- a/platforms/forge/src/main/resources/terra.forge.mixins.json +++ b/platforms/forge/src/main/resources/terra.forge.mixins.json @@ -4,7 +4,6 @@ "package": "com.dfsek.terra.forge.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ - "lifecycle.DataPackContentsMixin", "lifecycle.NoiseConfigMixin" ], "client": [ diff --git a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/DataPackContentsMixin.java b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/lifecycle/DataPackContentsMixin.java similarity index 95% rename from platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/DataPackContentsMixin.java rename to platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/lifecycle/DataPackContentsMixin.java index 5dcb1de72..d18fbf8d2 100644 --- a/platforms/fabric/src/main/java/com/dfsek/terra/fabric/mixin/lifecycle/DataPackContentsMixin.java +++ b/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/lifecycle/DataPackContentsMixin.java @@ -1,4 +1,4 @@ -package com.dfsek.terra.fabric.mixin.lifecycle; +package com.dfsek.terra.mod.mixin.lifecycle; import com.dfsek.terra.mod.util.TagUtil; import com.dfsek.terra.mod.util.MinecraftUtil; diff --git a/platforms/mod-common/src/main/resources/terra.common.mixins.json b/platforms/mod-common/src/main/resources/terra.common.mixins.json index c8142c28a..b084bee6f 100644 --- a/platforms/mod-common/src/main/resources/terra.common.mixins.json +++ b/platforms/mod-common/src/main/resources/terra.common.mixins.json @@ -1,46 +1,47 @@ { - "required": true, - "minVersion": "0.8", - "package": "com.dfsek.terra.mod.mixin", - "compatibilityLevel": "JAVA_17", - "mixins": [ - "access.MobSpawnerLogicAccessor", - "access.StateAccessor", - "access.StructureAccessorAccessor", - "fix.BeeMoveGoalsUnsynchronizedRandomAccessFix", - "fix.NetherFossilOptimization", - "implementations.compat.GenerationSettingsFloraFeaturesMixin", - "implementations.terra.BiomeMixin", - "implementations.terra.HandleImplementationMixin", - "implementations.terra.block.BlockMixin", - "implementations.terra.block.entity.BlockEntityMixin", - "implementations.terra.block.entity.LootableContainerBlockEntityMixin", - "implementations.terra.block.entity.MobSpawnerBlockEntityMixin", - "implementations.terra.block.entity.SignBlockEntityMixin", - "implementations.terra.block.state.BlockStateMixin", - "implementations.terra.block.state.PropertyMixin", - "implementations.terra.chunk.ChunkRegionMixin", - "implementations.terra.chunk.WorldChunkMixin", - "implementations.terra.chunk.data.ProtoChunkMixin", - "implementations.terra.entity.EntityMixin", - "implementations.terra.entity.EntityTypeMixin", - "implementations.terra.entity.PlayerEntityMixin", - "implementations.terra.entity.ServerCommandSourceMixin", - "implementations.terra.inventory.LockableContainerBlockEntityMixin", - "implementations.terra.inventory.item.ItemMixin", - "implementations.terra.inventory.item.ItemStackMixin", - "implementations.terra.inventory.meta.EnchantmentMixin", - "implementations.terra.inventory.meta.ItemStackDamageableMixin", - "implementations.terra.inventory.meta.ItemStackMetaMixin", - "implementations.terra.world.ChunkRegionMixin", - "implementations.terra.world.ServerWorldMixin" - ], - "client": [ - ], - "server": [ - ], - "injectors": { - "defaultRequire": 1 - }, - "refmap": "terra-common-refmap.json" + "required": true, + "minVersion": "0.8", + "package": "com.dfsek.terra.mod.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "access.MobSpawnerLogicAccessor", + "access.StateAccessor", + "access.StructureAccessorAccessor", + "fix.BeeMoveGoalsUnsynchronizedRandomAccessFix", + "fix.NetherFossilOptimization", + "implementations.compat.GenerationSettingsFloraFeaturesMixin", + "implementations.terra.BiomeMixin", + "implementations.terra.HandleImplementationMixin", + "implementations.terra.block.BlockMixin", + "implementations.terra.block.entity.BlockEntityMixin", + "implementations.terra.block.entity.LootableContainerBlockEntityMixin", + "implementations.terra.block.entity.MobSpawnerBlockEntityMixin", + "implementations.terra.block.entity.SignBlockEntityMixin", + "implementations.terra.block.state.BlockStateMixin", + "implementations.terra.block.state.PropertyMixin", + "implementations.terra.chunk.ChunkRegionMixin", + "implementations.terra.chunk.WorldChunkMixin", + "implementations.terra.chunk.data.ProtoChunkMixin", + "implementations.terra.entity.EntityMixin", + "implementations.terra.entity.EntityTypeMixin", + "implementations.terra.entity.PlayerEntityMixin", + "implementations.terra.entity.ServerCommandSourceMixin", + "implementations.terra.inventory.LockableContainerBlockEntityMixin", + "implementations.terra.inventory.item.ItemMixin", + "implementations.terra.inventory.item.ItemStackMixin", + "implementations.terra.inventory.meta.EnchantmentMixin", + "implementations.terra.inventory.meta.ItemStackDamageableMixin", + "implementations.terra.inventory.meta.ItemStackMetaMixin", + "implementations.terra.world.ChunkRegionMixin", + "implementations.terra.world.ServerWorldMixin", + "lifecycle.DataPackContentsMixin" + ], + "client": [ + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + }, + "refmap": "terra-common-refmap.json" } \ No newline at end of file From 3139416b358cae01c20c9bebd99f8be77a65a392 Mon Sep 17 00:00:00 2001 From: dfsek Date: Wed, 22 Jun 2022 07:23:39 -0700 Subject: [PATCH 35/38] rename mod-common to mixin-common --- platforms/fabric/build.gradle.kts | 4 ++-- platforms/forge/build.gradle.kts | 6 +++--- platforms/{mod-common => mixin-common}/README.md | 0 platforms/{mod-common => mixin-common}/build.gradle.kts | 0 .../src/main/java/com/dfsek/terra/mod/CommonPlatform.java | 0 .../src/main/java/com/dfsek/terra/mod/MinecraftAddon.java | 0 .../src/main/java/com/dfsek/terra/mod/ModPlatform.java | 0 .../terra/mod/config/PostLoadCompatibilityOptions.java | 0 .../dfsek/terra/mod/config/PreLoadCompatibilityOptions.java | 0 .../java/com/dfsek/terra/mod/config/ProtoPlatformBiome.java | 0 .../com/dfsek/terra/mod/config/VanillaBiomeProperties.java | 0 .../src/main/java/com/dfsek/terra/mod/data/Codecs.java | 0 .../mod/generation/MinecraftChunkGeneratorWrapper.java | 0 .../com/dfsek/terra/mod/generation/TerraBiomeSource.java | 0 .../com/dfsek/terra/mod/handle/MinecraftItemHandle.java | 0 .../com/dfsek/terra/mod/handle/MinecraftWorldHandle.java | 0 .../terra/mod/mixin/access/MobSpawnerLogicAccessor.java | 0 .../com/dfsek/terra/mod/mixin/access/StateAccessor.java | 0 .../terra/mod/mixin/access/StructureAccessorAccessor.java | 0 .../fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java | 0 .../dfsek/terra/mod/mixin/fix/NetherFossilOptimization.java | 0 .../compat/GenerationSettingsFloraFeaturesMixin.java | 0 .../terra/mod/mixin/implementations/terra/BiomeMixin.java | 0 .../implementations/terra/HandleImplementationMixin.java | 0 .../mod/mixin/implementations/terra/block/BlockMixin.java | 0 .../terra/block/entity/BlockEntityMixin.java | 0 .../block/entity/LootableContainerBlockEntityMixin.java | 0 .../terra/block/entity/MobSpawnerBlockEntityMixin.java | 0 .../terra/block/entity/SignBlockEntityMixin.java | 0 .../implementations/terra/block/state/BlockStateMixin.java | 0 .../implementations/terra/block/state/PropertyMixin.java | 0 .../mixin/implementations/terra/chunk/ChunkRegionMixin.java | 0 .../mixin/implementations/terra/chunk/WorldChunkMixin.java | 0 .../implementations/terra/chunk/data/ProtoChunkMixin.java | 0 .../mod/mixin/implementations/terra/entity/EntityMixin.java | 0 .../mixin/implementations/terra/entity/EntityTypeMixin.java | 0 .../implementations/terra/entity/PlayerEntityMixin.java | 0 .../terra/entity/ServerCommandSourceMixin.java | 0 .../terra/inventory/LockableContainerBlockEntityMixin.java | 0 .../implementations/terra/inventory/item/ItemMixin.java | 0 .../terra/inventory/item/ItemStackMixin.java | 0 .../terra/inventory/meta/EnchantmentMixin.java | 0 .../terra/inventory/meta/ItemStackDamageableMixin.java | 0 .../terra/inventory/meta/ItemStackMetaMixin.java | 0 .../terra/mod/mixin/implementations/terra/package-info.java | 0 .../mixin/implementations/terra/world/ChunkRegionMixin.java | 0 .../mixin/implementations/terra/world/ServerWorldMixin.java | 0 .../terra/mod/mixin/lifecycle/DataPackContentsMixin.java | 0 .../dfsek/terra/mod/mixin_ifaces/FloraFeatureHolder.java | 0 .../java/com/dfsek/terra/mod/util/MinecraftAdapter.java | 0 .../main/java/com/dfsek/terra/mod/util/MinecraftUtil.java | 0 .../src/main/java/com/dfsek/terra/mod/util/PresetUtil.java | 0 .../src/main/java/com/dfsek/terra/mod/util/SeedHack.java | 0 .../src/main/java/com/dfsek/terra/mod/util/TagUtil.java | 0 .../src/main/resources/fabric.mod.json | 0 .../src/main/resources/terra.common.mixins.json | 0 56 files changed, 5 insertions(+), 5 deletions(-) rename platforms/{mod-common => mixin-common}/README.md (100%) rename platforms/{mod-common => mixin-common}/build.gradle.kts (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/CommonPlatform.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/MinecraftAddon.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/ModPlatform.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/config/PostLoadCompatibilityOptions.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/config/PreLoadCompatibilityOptions.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/config/ProtoPlatformBiome.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/config/VanillaBiomeProperties.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/data/Codecs.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/generation/MinecraftChunkGeneratorWrapper.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/generation/TerraBiomeSource.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/handle/MinecraftItemHandle.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/handle/MinecraftWorldHandle.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/access/MobSpawnerLogicAccessor.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/access/StateAccessor.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/access/StructureAccessorAccessor.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/fix/NetherFossilOptimization.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/BiomeMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/HandleImplementationMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/BlockMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/BlockEntityMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/BlockStateMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/PropertyMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/ChunkRegionMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/WorldChunkMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityTypeMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/PlayerEntityMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/ServerCommandSourceMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemStackMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/package-info.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ChunkRegionMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ServerWorldMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin/lifecycle/DataPackContentsMixin.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/mixin_ifaces/FloraFeatureHolder.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/util/MinecraftAdapter.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/util/MinecraftUtil.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/util/PresetUtil.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/util/SeedHack.java (100%) rename platforms/{mod-common => mixin-common}/src/main/java/com/dfsek/terra/mod/util/TagUtil.java (100%) rename platforms/{mod-common => mixin-common}/src/main/resources/fabric.mod.json (100%) rename platforms/{mod-common => mixin-common}/src/main/resources/terra.common.mixins.json (100%) diff --git a/platforms/fabric/build.gradle.kts b/platforms/fabric/build.gradle.kts index 2af355a9a..4b7d3c70e 100644 --- a/platforms/fabric/build.gradle.kts +++ b/platforms/fabric/build.gradle.kts @@ -22,8 +22,8 @@ dependencies { "annotationProcessor"("net.fabricmc:sponge-mixin:${Versions.Fabric.mixin}") "annotationProcessor"("net.fabricmc:fabric-loom:${Versions.Fabric.loom}") - "common"(project(path = ":platforms:mod-common", configuration = "namedElements")) { isTransitive = false } - shaded(project(path = ":platforms:mod-common", configuration = "transformProductionFabric")) { isTransitive = false } + "common"(project(path = ":platforms:mixin-common", configuration = "namedElements")) { isTransitive = false } + shaded(project(path = ":platforms:mixin-common", configuration = "transformProductionFabric")) { isTransitive = false } minecraft("com.mojang:minecraft:${Versions.Fabric.minecraft}") mappings("net.fabricmc:yarn:${Versions.Fabric.yarn}:v2") diff --git a/platforms/forge/build.gradle.kts b/platforms/forge/build.gradle.kts index 9fcf26433..b09a9a1b1 100644 --- a/platforms/forge/build.gradle.kts +++ b/platforms/forge/build.gradle.kts @@ -18,9 +18,9 @@ configurations { dependencies { shadedApi(project(":common:implementation:base")) - "common"(project(path = ":platforms:mod-common", configuration = "namedElements")) { isTransitive = false } - shaded(project(path = ":platforms:mod-common", configuration = "transformProductionForge")) { isTransitive = false } - "developmentForge"(project(":platforms:mod-common", configuration = "namedElements")) { + "common"(project(path = ":platforms:mixin-common", configuration = "namedElements")) { isTransitive = false } + shaded(project(path = ":platforms:mixin-common", configuration = "transformProductionForge")) { isTransitive = false } + "developmentForge"(project(":platforms:mixin-common", configuration = "namedElements")) { isTransitive = false } diff --git a/platforms/mod-common/README.md b/platforms/mixin-common/README.md similarity index 100% rename from platforms/mod-common/README.md rename to platforms/mixin-common/README.md diff --git a/platforms/mod-common/build.gradle.kts b/platforms/mixin-common/build.gradle.kts similarity index 100% rename from platforms/mod-common/build.gradle.kts rename to platforms/mixin-common/build.gradle.kts diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/CommonPlatform.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/CommonPlatform.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/CommonPlatform.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/CommonPlatform.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/MinecraftAddon.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/MinecraftAddon.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/MinecraftAddon.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/MinecraftAddon.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/ModPlatform.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/ModPlatform.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/ModPlatform.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/ModPlatform.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/PostLoadCompatibilityOptions.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/PostLoadCompatibilityOptions.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/PostLoadCompatibilityOptions.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/PostLoadCompatibilityOptions.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/PreLoadCompatibilityOptions.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/PreLoadCompatibilityOptions.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/PreLoadCompatibilityOptions.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/PreLoadCompatibilityOptions.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/ProtoPlatformBiome.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/ProtoPlatformBiome.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/ProtoPlatformBiome.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/ProtoPlatformBiome.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/VanillaBiomeProperties.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/VanillaBiomeProperties.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/config/VanillaBiomeProperties.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/config/VanillaBiomeProperties.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/data/Codecs.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/data/Codecs.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/data/Codecs.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/data/Codecs.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/generation/MinecraftChunkGeneratorWrapper.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/generation/MinecraftChunkGeneratorWrapper.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/generation/MinecraftChunkGeneratorWrapper.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/generation/MinecraftChunkGeneratorWrapper.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/generation/TerraBiomeSource.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/generation/TerraBiomeSource.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/generation/TerraBiomeSource.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/generation/TerraBiomeSource.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftItemHandle.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftItemHandle.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftItemHandle.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftItemHandle.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftWorldHandle.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftWorldHandle.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftWorldHandle.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/handle/MinecraftWorldHandle.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/access/MobSpawnerLogicAccessor.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/MobSpawnerLogicAccessor.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/access/MobSpawnerLogicAccessor.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/MobSpawnerLogicAccessor.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/access/StateAccessor.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/StateAccessor.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/access/StateAccessor.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/StateAccessor.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/access/StructureAccessorAccessor.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/StructureAccessorAccessor.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/access/StructureAccessorAccessor.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/access/StructureAccessorAccessor.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/fix/BeeMoveGoalsUnsynchronizedRandomAccessFix.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/fix/NetherFossilOptimization.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/fix/NetherFossilOptimization.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/fix/NetherFossilOptimization.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/fix/NetherFossilOptimization.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/compat/GenerationSettingsFloraFeaturesMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/BiomeMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/BiomeMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/BiomeMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/BiomeMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/HandleImplementationMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/HandleImplementationMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/HandleImplementationMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/HandleImplementationMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/BlockMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/BlockMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/BlockMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/BlockMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/BlockEntityMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/BlockEntityMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/BlockEntityMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/BlockEntityMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/LootableContainerBlockEntityMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/MobSpawnerBlockEntityMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/entity/SignBlockEntityMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/BlockStateMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/BlockStateMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/BlockStateMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/BlockStateMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/PropertyMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/PropertyMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/PropertyMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/block/state/PropertyMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/ChunkRegionMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/ChunkRegionMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/ChunkRegionMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/ChunkRegionMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/WorldChunkMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/WorldChunkMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/WorldChunkMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/WorldChunkMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/chunk/data/ProtoChunkMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityTypeMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityTypeMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityTypeMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/EntityTypeMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/PlayerEntityMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/PlayerEntityMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/PlayerEntityMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/PlayerEntityMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/ServerCommandSourceMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/ServerCommandSourceMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/ServerCommandSourceMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/entity/ServerCommandSourceMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/LockableContainerBlockEntityMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemStackMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemStackMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemStackMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/item/ItemStackMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/EnchantmentMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackDamageableMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/inventory/meta/ItemStackMetaMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/package-info.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/package-info.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/package-info.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/package-info.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ChunkRegionMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ChunkRegionMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ChunkRegionMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ChunkRegionMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ServerWorldMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ServerWorldMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ServerWorldMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/implementations/terra/world/ServerWorldMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/lifecycle/DataPackContentsMixin.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/lifecycle/DataPackContentsMixin.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin/lifecycle/DataPackContentsMixin.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin/lifecycle/DataPackContentsMixin.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin_ifaces/FloraFeatureHolder.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin_ifaces/FloraFeatureHolder.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/mixin_ifaces/FloraFeatureHolder.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/mixin_ifaces/FloraFeatureHolder.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/MinecraftAdapter.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/MinecraftAdapter.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/MinecraftAdapter.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/MinecraftAdapter.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/MinecraftUtil.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/MinecraftUtil.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/MinecraftUtil.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/MinecraftUtil.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/PresetUtil.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/PresetUtil.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/PresetUtil.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/PresetUtil.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/SeedHack.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/SeedHack.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/SeedHack.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/SeedHack.java diff --git a/platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/TagUtil.java b/platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/TagUtil.java similarity index 100% rename from platforms/mod-common/src/main/java/com/dfsek/terra/mod/util/TagUtil.java rename to platforms/mixin-common/src/main/java/com/dfsek/terra/mod/util/TagUtil.java diff --git a/platforms/mod-common/src/main/resources/fabric.mod.json b/platforms/mixin-common/src/main/resources/fabric.mod.json similarity index 100% rename from platforms/mod-common/src/main/resources/fabric.mod.json rename to platforms/mixin-common/src/main/resources/fabric.mod.json diff --git a/platforms/mod-common/src/main/resources/terra.common.mixins.json b/platforms/mixin-common/src/main/resources/terra.common.mixins.json similarity index 100% rename from platforms/mod-common/src/main/resources/terra.common.mixins.json rename to platforms/mixin-common/src/main/resources/terra.common.mixins.json From e4d05312aac1f30ad71c61b6e07a87e2b36edef9 Mon Sep 17 00:00:00 2001 From: dfsek Date: Fri, 24 Jun 2022 16:00:35 -0700 Subject: [PATCH 36/38] ignore mixins from common package in AwfulForgeHacks --- .../src/main/java/com/dfsek/terra/forge/AwfulForgeHacks.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platforms/forge/src/main/java/com/dfsek/terra/forge/AwfulForgeHacks.java b/platforms/forge/src/main/java/com/dfsek/terra/forge/AwfulForgeHacks.java index 5565fd1ba..0ddb92caa 100644 --- a/platforms/forge/src/main/java/com/dfsek/terra/forge/AwfulForgeHacks.java +++ b/platforms/forge/src/main/java/com/dfsek/terra/forge/AwfulForgeHacks.java @@ -61,7 +61,8 @@ public final class AwfulForgeHacks { try(JarFile jar = getTerraJar()) { jar.stream() .forEach(jarEntry -> { - if(jarEntry.getName().startsWith("com/dfsek/terra/forge/mixin")) { + if(jarEntry.getName().startsWith("com/dfsek/terra/forge/mixin") + || jarEntry.getName().startsWith("com/dfsek/terra/mod/mixin")) { return; } if(jarEntry.getName().endsWith(".class")) { From cffdf7aeeb836e6f708955bbcc421b173cf335b4 Mon Sep 17 00:00:00 2001 From: dfsek Date: Fri, 24 Jun 2022 16:00:47 -0700 Subject: [PATCH 37/38] use Fabric Loom --- platforms/fabric/build.gradle.kts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/platforms/fabric/build.gradle.kts b/platforms/fabric/build.gradle.kts index 4b7d3c70e..4020713db 100644 --- a/platforms/fabric/build.gradle.kts +++ b/platforms/fabric/build.gradle.kts @@ -1,13 +1,8 @@ plugins { - id("dev.architectury.loom") version Versions.Mod.architecuryLoom - id("architectury-plugin") version Versions.Mod.architectutyPlugin + id("fabric-loom") version Versions.Fabric.loom id("io.github.juuxel.loom-quiltflower") version Versions.Fabric.loomQuiltflower } -architectury { - fabric() -} - configurations { val common by creating From b05852e0746c9a2664f10b0c10c8accba46285d4 Mon Sep 17 00:00:00 2001 From: dfsek Date: Fri, 24 Jun 2022 17:50:40 -0700 Subject: [PATCH 38/38] make slf4j testImplementation --- common/api/build.gradle.kts | 1 + common/implementation/base/build.gradle.kts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/common/api/build.gradle.kts b/common/api/build.gradle.kts index fe36f682e..2fce99b17 100644 --- a/common/api/build.gradle.kts +++ b/common/api/build.gradle.kts @@ -1,6 +1,7 @@ dependencies { api("ca.solo-studios", "strata", Versions.Libraries.strata) compileOnlyApi("org.slf4j", "slf4j-api", Versions.Libraries.slf4j) + testImplementation("org.slf4j", "slf4j-api", Versions.Libraries.slf4j) api("cloud.commandframework", "cloud-core", Versions.Libraries.cloud) api("com.dfsek.tectonic", "common", Versions.Libraries.tectonic) diff --git a/common/implementation/base/build.gradle.kts b/common/implementation/base/build.gradle.kts index 64c176c77..1910484f0 100644 --- a/common/implementation/base/build.gradle.kts +++ b/common/implementation/base/build.gradle.kts @@ -2,6 +2,8 @@ dependencies { api(project(":common:api")) api(project(":common:implementation:bootstrap-addon-loader")) + testImplementation("org.slf4j", "slf4j-api", Versions.Libraries.slf4j) + implementation("commons-io", "commons-io", Versions.Libraries.Internal.apacheIO) implementation("org.apache.commons", "commons-text", Versions.Libraries.Internal.apacheText)

C7Im@Ow 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 Date: Sun, 19 Jun 2022 22:11:12 -0700 Subject: [PATCH 02/38] architectury launches now --- platforms/forge/build.gradle.kts | 92 +++++------------- .../src/main/resources/assets/terra/icon.png | Bin 129860 -> 0 bytes .../resources/assets/terra/lang/en_us.json | 4 - .../forge/src/main/resources/pack.mcmeta | 6 ++ .../src/main/resources/terra.mixins.json | 76 +++++++-------- settings.gradle.kts | 14 ++- 6 files changed, 78 insertions(+), 114 deletions(-) delete mode 100644 platforms/forge/src/main/resources/assets/terra/icon.png delete mode 100644 platforms/forge/src/main/resources/assets/terra/lang/en_us.json create mode 100644 platforms/forge/src/main/resources/pack.mcmeta diff --git a/platforms/forge/build.gradle.kts b/platforms/forge/build.gradle.kts index 73aee97a0..31c5632f2 100644 --- a/platforms/forge/build.gradle.kts +++ b/platforms/forge/build.gradle.kts @@ -1,11 +1,19 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar -import com.modrinth.minotaur.TaskModrinthUpload +import java.util.* import net.fabricmc.loom.task.RemapJarTask -import java.util.Date plugins { id("dev.architectury.loom") version Versions.Forge.architecuryLoom - id("com.modrinth.minotaur") version Versions.Fabric.minotaur +} + +dependencies { + shadedApi(project(":common:implementation:base")) + forgeRuntimeLibrary(project(":common:implementation:base")) + + forge(group = "net.minecraftforge", name = "forge", version = Versions.Forge.forge) + + minecraft("com.mojang:minecraft:${Versions.Forge.minecraft}") + mappings("net.fabricmc:yarn:${Versions.Forge.yarn}:v2") } loom { @@ -17,72 +25,22 @@ loom { mixinConfigs.set(listOf("terra.mixins.json")) } - } -dependencies { - shadedApi(project(":common:implementation:base")) - - forge("net.minecraftforge:forge:${Versions.Forge.forge}") - - minecraft("com.mojang:minecraft:${Versions.Forge.minecraft}") - mappings("net.fabricmc:yarn:${Versions.Forge.yarn}:v2") -} +tasks { + jar { + manifest { + attributes( + mapOf( + "Implementation-Title" to rootProject.name, + "Implementation-Version" to project.version, + ) + ) + } + } - - - - -addonDir(project.file("./run/config/Terra/addons"), tasks.named("runClient").get()) -addonDir(project.file("./run/config/Terra/addons"), tasks.named("runServer").get()) - -tasks.withType().configureEach { - options.release.set(17) -} - -tasks.getByName("shadowJar") { - exclude("org/slf4j/**") -} - -val remapped = tasks.register("remapShadedJar") { - dependsOn("installAddons") - group = "loom" - val shadowJar = tasks.getByName("shadowJar") - dependsOn(shadowJar) - inputFile.set(shadowJar.archiveFile) - archiveFileName.set(shadowJar.archiveFileName.get().replace(Regex("-shaded\\.jar$"), "-shaded-mapped.jar")) - addNestedDependencies.set(true) -} - -tasks.named("assemble").configure { - dependsOn("remapShadedJar") -} - -tasks.withType { - finalizedBy(remapped) - manifest { - attributes( - mapOf( - "Specification-Title" to "terra", - "Specification-Vendor" to "Terra Contributors", - "Specification-Version" to "1", - "Implementation-Title" to project.name, - "Implementation-Version" to "@VERSION@", - "Implementation-Vendor" to "Terra Contributors", - "Implementation-Timestamp" to Date().toString() - ) - ) + remapJar { + inputFile.set(shadowJar.get().archiveFile) + archiveFileName.set("${rootProject.name.capitalize()}-${project.version}.jar") } } - -tasks.register("publishModrinth") { - dependsOn("remapShadedJar") - group = "loom" - token = System.getenv("MODRINTH_SECRET") - projectId = "FIlZB9L0" - versionNumber = "${project.version}-forge" - uploadFile = remapped.get().archiveFile.get().asFile - releaseType = "beta" - addGameVersion(Versions.Forge.minecraft) - addLoader("forge") -} \ No newline at end of file diff --git a/platforms/forge/src/main/resources/assets/terra/icon.png b/platforms/forge/src/main/resources/assets/terra/icon.png deleted file mode 100644 index a8f458866a0d1cd397e5fa592ef1707a97722f1f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 129860 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%0DMHvKS|?`Q93A21D4 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