begin architectury implementation

This commit is contained in:
dfsek
2022-06-19 21:24:22 -07:00
parent 536733911b
commit 98a9035ae8
67 changed files with 3814 additions and 0 deletions

View File

@@ -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 {

View File

@@ -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"

View File

@@ -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<JavaCompile>().configureEach {
options.release.set(17)
}
tasks.getByName<ShadowJar>("shadowJar") {
exclude("org/slf4j/**")
}
val remapped = tasks.register<RemapJarTask>("remapShadedJar") {
dependsOn("installAddons")
group = "loom"
val shadowJar = tasks.getByName<ShadowJar>("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<Jar> {
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<TaskModrinthUpload>("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")
}

View File

@@ -0,0 +1 @@
loom.platform=forge

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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";
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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...");
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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<File> 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<BaseAddon> platformAddon() {
List<BaseAddon> 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);
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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 {
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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;
}
}

View File

@@ -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<RegistryKey> 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<ConfigPack> 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<TerraBiomeSource> 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<FabricChunkGeneratorWrapper> 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))
);
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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<StructureSet> noiseRegistry;
private final RegistryEntry<ChunkGeneratorSettings> settings;
private ChunkGenerator delegate;
private ConfigPack pack;
public FabricChunkGeneratorWrapper(Registry<StructureSet> noiseRegistry, TerraBiomeSource biomeSource, ConfigPack configPack,
RegistryEntry<ChunkGeneratorSettings> 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<StructureSet> getNoiseRegistry() {
return noiseRegistry;
}
@Override
protected Codec<? extends net.minecraft.world.gen.chunk.ChunkGenerator> 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<Biome> 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<Chunk> 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<String> 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<ChunkGeneratorSettings> getSettings() {
return settings;
}
@Override
public TerraBiomeSource getBiomeSource() {
return biomeSource;
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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<net.minecraft.world.biome.Biome> biomeRegistry;
private ConfigPack pack;
public TerraBiomeSource(Registry<net.minecraft.world.biome.Biome> 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<? extends BiomeSource> getCodec() {
return Codecs.TERRA_BIOME_SOURCE;
}
@Override
public RegistryEntry<net.minecraft.world.biome.Biome> 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<net.minecraft.world.biome.Biome> getBiomeRegistry() {
return biomeRegistry;
}
public ConfigPack getPack() {
return pack;
}
public void setPack(ConfigPack pack) {
this.pack = pack;
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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<Enchantment> getEnchantments() {
return Registry.ENCHANTMENT.stream().map(enchantment -> (Enchantment) enchantment).collect(Collectors.toSet());
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@@ -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<Chunk> getChunks();
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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<Map.Entry<Property<?>, Comparable<?>>, String> getPropertyMapPrinter() {
throw new UnsupportedOperationException();
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}

View File

@@ -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 = "<init>", 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.
}
}

View File

@@ -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<Optional<StructurePosition>> cir) {
if(context.chunkGenerator() instanceof FabricChunkGeneratorWrapper) {
cir.setReturnValue(Optional.empty());
}
}
}

View File

@@ -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<ConfiguredFeature<?, ?>> flora;
public void terra$setFloraFeatures(List<ConfiguredFeature<?, ?>> features) {
this.flora = features;
}
@Inject(method = "getFlowerFeatures", cancellable = true, at = @At("HEAD"))
public void inject(CallbackInfoReturnable<List<ConfiguredFeature<?, ?>>> cir) {
if(flora != null) {
cir.setReturnValue(flora);
}
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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 {
}

View File

@@ -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;
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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);
}
});
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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);
});
}
}

View File

@@ -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<Block, net.minecraft.block.BlockState> {
private BlockStateMixin(Block owner, ImmutableMap<net.minecraft.state.property.Property<?>, Comparable<?>> entries,
MapCodec<net.minecraft.block.BlockState> 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 <T extends Comparable<T>> boolean terra$has(Property<T> property) {
if(property instanceof net.minecraft.state.property.Property<?> minecraftProperty) {
return contains(minecraftProperty);
}
return false;
}
@SuppressWarnings("unchecked")
@Intrinsic
public <T extends Comparable<T>> T terra$get(Property<T> property) {
return get((net.minecraft.state.property.Property<T>) property);
}
@SuppressWarnings("unchecked")
@Intrinsic
public <T extends Comparable<T>> BlockState terra$set(Property<T> property, T value) {
return (BlockState) with((net.minecraft.state.property.Property<T>) 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();
}
}

View File

@@ -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<T> {
@Shadow
@Final
private Class<T> type;
@Shadow
@Final
private String name;
@Shadow
public abstract Collection<T> getValues();
@Intrinsic
public Collection<T> terra$values() {
return getValues();
}
@Intrinsic
public Class<T> terra$getType() {
return type;
}
@Intrinsic
public String terra$getID() {
return name;
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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 {
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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 {
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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<Entity> terra$getEntity() {
return Optional.ofNullable((Entity) getEntity());
}
public Optional<Player> terra$getPlayer() {
try {
return Optional.ofNullable((Player) getPlayer());
} catch(CommandSyntaxException e) {
return Optional.empty();
}
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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<Enchantment, Integer> terra$getEnchantments() {
if(!hasEnchantments()) return Collections.emptyMap();
Map<Enchantment, Integer> map = new HashMap<>();
getEnchantments().forEach(enchantment -> {
NbtCompound eTag = (NbtCompound) enchantment;
map.put((Enchantment) Registry.ENCHANTMENT.get(eTag.getInt("id")), eTag.getInt("lvl"));
});
return map;
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
/**
* Mixins in this package implement Terra
* interfaces in Minecraft classes.
*/
package com.dfsek.terra.forge.mixin.implementations.terra;

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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<Fluid> fluidTickScheduler;
@Inject(at = @At("RETURN"),
method = "<init>(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<net.minecraft.world.chunk.Chunk> 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;
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@@ -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<Biome> biomeRegistry = dynamicRegistryManager.get(Registry.BIOME_KEY);
TagUtil.registerBiomeTags(biomeRegistry);
BiomeUtil.registerFlora(biomeRegistry);
}
}

View File

@@ -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 = "<init>(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);
}
}

View File

@@ -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 = "<init>(Lnet/minecraft/world/gen/chunk/ChunkGeneratorSettings;Lnet/minecraft/util/registry/Registry;J)V", at = @At("TAIL"))
private void mapMultiNoise(ChunkGeneratorSettings chunkGeneratorSettings, Registry<DoublePerlinNoiseSampler.NoiseParameters> noiseRegistry, long seed, CallbackInfo ci) {
SeedHack.register(multiNoiseSampler, seed);
}
}

View File

@@ -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 = "<clinit>", at = @At("RETURN"))
private static void registerTerraGenerators(CallbackInfo ci) {
ForgeEntryPoint.register();
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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 = "<init>", 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();
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
/**
* Mixins that inject behavior into the client/server lifecycle.
*/
package com.dfsek.terra.forge.mixin.lifecycle;

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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;<init>(Lnet/minecraft/resource/ResourceType;" +
"[Lnet/minecraft/resource/ResourcePackProvider;)V")
// after registry manager creation
)
private static void injectConstructor(String[] args, CallbackInfo ci) {
LifecycleUtil.initialize();
}
}

View File

@@ -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<ConfiguredFeature<?, ?>> features);
}

View File

@@ -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<Identifier, List<Identifier>>
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<net.minecraft.world.biome.Biome> registry = BuiltinRegistries.BIOME;
RegistryKey<net.minecraft.world.biome.Biome> 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<net.minecraft.world.biome.Biome> 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<ConfiguredFeature<?, ?>> 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<Identifier, List<Identifier>> getTerraBiomeMap() {
return Map.copyOf(TERRA_BIOME_MAP);
}
private static RegistryKey<net.minecraft.world.biome.Biome> 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();
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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;
};
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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 <T> Optional<RegistryEntry<T>> getEntry(Registry<T> registry, Identifier identifier) {
return registry.getOrEmpty(identifier)
.flatMap(registry::getKey)
.map(registry::getOrCreateEntry);
}
}

View File

@@ -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<Identifier> PRESETS = new ArrayList<>();
public static void initialize() {
ForgeEntryPoint.getPlatform().getEventManager().callEvent(
new PlatformInitializationEvent());
BiomeUtil.registerBiomes();
LOGGER.info("Registering Terra world types...");
Registry<DimensionType> dimensionTypeRegistry = BuiltinRegistries.DIMENSION_TYPE;
Registry<ChunkGeneratorSettings> chunkGeneratorSettingsRegistry = BuiltinRegistries.CHUNK_GENERATOR_SETTINGS;
Registry<StructureSet> structureSetRegistry = BuiltinRegistries.STRUCTURE_SET;
Registry<NoiseParameters> noiseParametersRegistry = BuiltinRegistries.NOISE_PARAMETERS;
Registry<Biome> biomeRegistry = BuiltinRegistries.BIOME;
RegistryEntry<DimensionType> theNetherDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.THE_NETHER);
RegistryEntry<ChunkGeneratorSettings>
netherChunkGeneratorSettings = chunkGeneratorSettingsRegistry.getOrCreateEntry(ChunkGeneratorSettings.NETHER);
DimensionOptions netherDimensionOptions = new DimensionOptions(theNetherDimensionType,
new NoiseChunkGenerator(structureSetRegistry,
noiseParametersRegistry,
MultiNoiseBiomeSource.Preset.NETHER.getBiomeSource(
biomeRegistry),
netherChunkGeneratorSettings));
RegistryEntry<DimensionType> theEndDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.THE_END);
RegistryEntry<ChunkGeneratorSettings> endChunkGeneratorSettings = chunkGeneratorSettingsRegistry.getOrCreateEntry(
ChunkGeneratorSettings.END);
DimensionOptions endDimensionOptions = new DimensionOptions(theEndDimensionType,
new NoiseChunkGenerator(structureSetRegistry, noiseParametersRegistry,
new TheEndBiomeSource(biomeRegistry),
endChunkGeneratorSettings));
RegistryEntry<DimensionType> overworldDimensionType = dimensionTypeRegistry.getOrCreateEntry(DimensionTypes.OVERWORLD);
RegistryEntry<ChunkGeneratorSettings> 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<Identifier> getPresets() {
return PRESETS;
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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<Biome> delegate;
public ProtoPlatformBiome(Identifier identifier) {
this.identifier = identifier;
}
public RegistryKey<Biome> get(Registry<net.minecraft.world.biome.Biome> registry) {
return FabricUtil.getEntry(registry, identifier).orElseThrow().getKey().orElseThrow();
}
@Override
public Object getHandle() {
return identifier;
}
public RegistryKey<Biome> getDelegate() {
return delegate;
}
public void setDelegate(RegistryKey<Biome> delegate) {
this.delegate = Objects.requireNonNull(delegate);
}
}

View File

@@ -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<MultiNoiseSampler> 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);
}
}

View File

@@ -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 <T> Map<TagKey<T>, List<RegistryEntry<T>>> tagsToMutableMap(Registry<T> 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<WorldPreset> registry) {
logger.info("Doing preset tag garbage....");
Map<TagKey<WorldPreset>, List<RegistryEntry<WorldPreset>>> 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<Biome> registry) {
logger.info("Doing biome tag garbage....");
Map<TagKey<Biome>, List<RegistryEntry<Biome>>> 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);
}
}
}

View File

@@ -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"

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

View File

@@ -0,0 +1,4 @@
{
"generator.terra": "Terra"
}

View File

@@ -0,0 +1,53 @@
{
"required": true,
"minVersion": "0.8",
"package": "com.dfsek.terra.fabric.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
"com.dfsek.terra.forge.mixin.access.ChunkRegionAccessor",
"com.dfsek.terra.forge.mixin.access.MobSpawnerLogicAccessor",
"com.dfsek.terra.forge.mixin.access.StateAccessor",
"com.dfsek.terra.forge.mixin.access.StructureAccessorAccessor",
"com.dfsek.terra.forge.mixin.fix.BeeMoveGoalsUnsynchronizedRandomAccessFix",
"com.dfsek.terra.forge.mixin.fix.NetherFossilOptimization",
"com.dfsek.terra.forge.mixin.implementations.compat.GenerationSettingsFloraFeaturesMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.BiomeMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.HandleImplementationMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.block.BlockMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.block.entity.BlockEntityMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.block.entity.LootableContainerBlockEntityMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.block.entity.MobSpawnerBlockEntityMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.block.entity.SignBlockEntityMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.block.state.BlockStateMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.block.state.PropertyMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.chunk.ChunkRegionMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.chunk.WorldChunkMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.chunk.data.ProtoChunkMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.entity.EntityMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.entity.EntityTypeMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.entity.PlayerEntityMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.entity.ServerCommandSourceMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.inventory.LockableContainerBlockEntityMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.inventory.item.ItemMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.inventory.item.ItemStackMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.inventory.meta.EnchantmentMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.inventory.meta.ItemStackDamageableMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.inventory.meta.ItemStackMetaMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.world.ChunkRegionMixin",
"com.dfsek.terra.forge.mixin.implementations.terra.world.ServerWorldMixin",
"com.dfsek.terra.forge.mixin.lifecycle.DataPackContentsMixin",
"com.dfsek.terra.forge.mixin.lifecycle.MinecraftServerMixin",
"com.dfsek.terra.forge.mixin.lifecycle.NoiseConfigMixin",
"com.dfsek.terra.forge.mixin.lifecycle.RegistryMixin"
],
"client": [
"com.dfsek.terra.forge.mixin.lifecycle.client.MinecraftClientMixin"
],
"server": [
"com.dfsek.terra.forge.mixin.lifecycle.server.ServerMainMixin"
],
"injectors": {
"defaultRequire": 1
},
"refmap": "terra-refmap.json"
}

View File

@@ -27,6 +27,8 @@ pluginManagement {
maven("https://maven.fabricmc.net") {
name = "Fabric"
}
maven ( "https://maven.architectury.dev/" )
maven ( "https://files.minecraftforge.net/maven/" )
gradlePluginPortal()
}
}