Merge remote-tracking branch 'origin/master' into dev/layered-generator

This commit is contained in:
Zoe Gidiere
2024-10-13 18:51:14 -06:00
967 changed files with 10918 additions and 11559 deletions

View File

@@ -1,18 +1,10 @@
plugins {
id("xyz.jpenilla.run-paper") version "1.0.6"
}
repositories {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
id("xyz.jpenilla.run-paper") version Versions.Bukkit.runPaper
}
dependencies {
shaded(project(":platforms:bukkit:common"))
shaded(project(":platforms:bukkit:nms:v1_18_R2", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_19_R1", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_19_R2", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_19_R3", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_20_R1", configuration = "reobf"))
shaded(project(":platforms:bukkit:nms:v1_21", configuration = "reobf"))
shaded("xyz.jpenilla", "reflection-remapper", Versions.Bukkit.reflectionRemapper)
}
@@ -29,7 +21,7 @@ tasks {
exclude("com/google/j2objc/**")
exclude("javax/**")
}
runServer {
minecraftVersion(Versions.Bukkit.minecraft)
dependsOn(shadowJar)

View File

@@ -4,15 +4,12 @@ repositories {
dependencies {
shadedApi(project(":common:implementation:base"))
api("org.slf4j:slf4j-api:1.8.0-beta4") {
because("Minecraft 1.17+ includes slf4j 1.8.0-beta4, so we need to shade it for other versions.")
}
compileOnly("io.papermc.paper:paper-api:${Versions.Bukkit.paper}")
compileOnly("io.papermc.paper", "paper-api", Versions.Bukkit.paper)
shadedApi("io.papermc", "paperlib", Versions.Bukkit.paperLib)
shadedApi("com.google.guava:guava:30.0-jre")
shadedApi("cloud.commandframework", "cloud-paper", Versions.Libraries.cloud)
shadedApi("com.google.guava", "guava", Versions.Libraries.Internal.guava)
shadedApi("org.incendo", "cloud-paper", Versions.Libraries.cloudPaper)
}

View File

@@ -14,37 +14,37 @@ import com.dfsek.terra.bukkit.config.VanillaBiomeProperties;
public class BukkitAddon implements BaseAddon {
private static final Version VERSION = Versions.getVersion(1, 0, 0);
private final PlatformImpl terraBukkitPlugin;
public BukkitAddon(PlatformImpl terraBukkitPlugin) {
this.terraBukkitPlugin = terraBukkitPlugin;
}
@Override
public void initialize() {
terraBukkitPlugin.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
.then(event -> event.getPack().getContext().put(event.loadTemplate(new PreLoadCompatibilityOptions())))
.global();
.getHandler(FunctionalEventHandler.class)
.register(this, ConfigPackPreLoadEvent.class)
.then(event -> event.getPack().getContext().put(event.loadTemplate(new PreLoadCompatibilityOptions())))
.global();
terraBukkitPlugin.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();
.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-bukkit";

View File

@@ -29,16 +29,16 @@ import com.dfsek.terra.bukkit.world.BukkitAdapter;
public class BukkitCommandSender implements CommandSender {
private final org.bukkit.command.CommandSender delegate;
public BukkitCommandSender(org.bukkit.command.CommandSender delegate) {
this.delegate = delegate;
}
@Override
public void sendMessage(String message) {
delegate.sendMessage(ChatColor.translateAlternateColorCodes('&', message));
}
@Override
public Optional<Entity> getEntity() {
if(delegate instanceof org.bukkit.entity.Entity entity) {
@@ -46,7 +46,7 @@ public class BukkitCommandSender implements CommandSender {
}
return Optional.empty();
}
@Override
public Optional<Player> getPlayer() {
if(delegate instanceof org.bukkit.entity.Player player) {
@@ -54,7 +54,7 @@ public class BukkitCommandSender implements CommandSender {
}
return Optional.empty();
}
@Override
public org.bukkit.command.CommandSender getHandle() {
return delegate;

View File

@@ -17,6 +17,7 @@
package com.dfsek.terra.bukkit;
import io.papermc.lib.PaperLib;
import org.bukkit.Location;
import com.dfsek.terra.api.entity.Entity;
@@ -27,33 +28,33 @@ import com.dfsek.terra.bukkit.world.BukkitAdapter;
public class BukkitEntity implements Entity {
private final org.bukkit.entity.Entity entity;
public BukkitEntity(org.bukkit.entity.Entity entity) {
this.entity = entity;
}
@Override
public org.bukkit.entity.Entity getHandle() {
return entity;
}
@Override
public Vector3 position() {
return BukkitAdapter.adapt(entity.getLocation().toVector());
}
@Override
public void position(Vector3 location) {
entity.teleport(BukkitAdapter.adapt(location).toLocation(entity.getWorld()));
PaperLib.teleportAsync(entity, BukkitAdapter.adapt(location).toLocation(entity.getWorld()));
}
@Override
public void world(ServerWorld world) {
Location newLoc = entity.getLocation().clone();
newLoc.setWorld(BukkitAdapter.adapt(world));
entity.teleport(newLoc);
PaperLib.teleportAsync(entity, newLoc);
}
@Override
public ServerWorld world() {
return BukkitAdapter.adapt(entity.getWorld());

View File

@@ -17,6 +17,7 @@
package com.dfsek.terra.bukkit;
import io.papermc.lib.PaperLib;
import org.bukkit.Location;
import com.dfsek.terra.api.entity.Player;
@@ -27,34 +28,34 @@ import com.dfsek.terra.bukkit.world.BukkitAdapter;
public class BukkitPlayer implements Player {
private final org.bukkit.entity.Player delegate;
public BukkitPlayer(org.bukkit.entity.Player delegate) {
this.delegate = delegate;
}
@Override
public org.bukkit.entity.Player getHandle() {
return delegate;
}
@Override
public Vector3 position() {
org.bukkit.Location bukkit = delegate.getLocation();
return Vector3.of(bukkit.getX(), bukkit.getY(), bukkit.getZ());
}
@Override
public void position(Vector3 location) {
delegate.teleport(BukkitAdapter.adapt(location).toLocation(delegate.getWorld()));
PaperLib.teleportAsync(delegate, BukkitAdapter.adapt(location).toLocation(delegate.getWorld()));
}
@Override
public void world(ServerWorld world) {
Location newLoc = delegate.getLocation().clone();
newLoc.setWorld(BukkitAdapter.adapt(world));
delegate.teleport(newLoc);
PaperLib.teleportAsync(delegate, newLoc);
}
@Override
public ServerWorld world() {
return BukkitAdapter.adapt(delegate.getWorld());

View File

@@ -44,28 +44,28 @@ import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
public class PlatformImpl extends AbstractPlatform {
private static final Logger LOGGER = LoggerFactory.getLogger(PlatformImpl.class);
private final ItemHandle itemHandle = new BukkitItemHandle();
private final WorldHandle handle = new BukkitWorldHandle();
private final TerraBukkitPlugin plugin;
public PlatformImpl(TerraBukkitPlugin plugin) {
this.plugin = plugin;
load();
}
public TerraBukkitPlugin getPlugin() {
return plugin;
}
@Override
public boolean reload() {
getTerraConfig().load(this);
getRawConfigRegistry().clear();
boolean succeed = getRawConfigRegistry().loadAll(this);
Bukkit.getWorlds().forEach(world -> {
if(world.getGenerator() instanceof BukkitChunkGeneratorWrapper wrapper) {
getConfigRegistry().get(wrapper.getPack().getRegistryKey()).ifPresent(pack -> {
@@ -74,49 +74,49 @@ public class PlatformImpl extends AbstractPlatform {
});
}
});
return succeed;
}
@Override
public @NotNull String platformName() {
return "Bukkit";
}
@Override
public void runPossiblyUnsafeTask(@NotNull Runnable task) {
Bukkit.getScheduler().runTask(plugin, task);
public void runPossiblyUnsafeTask(@NotNull Runnable runnable) {
plugin.getGlobalRegionScheduler().run(plugin, task -> runnable.run());
}
@Override
protected Iterable<BaseAddon> platformAddon() {
return List.of(new BukkitAddon(this));
}
@Override
public @NotNull WorldHandle getWorldHandle() {
return handle;
}
@Override
public @NotNull File getDataFolder() {
return plugin.getDataFolder();
}
@Override
public @NotNull ItemHandle getItemHandle() {
return itemHandle;
}
@Override
public void register(TypeRegistry registry) {
super.register(registry);
registry.registerLoader(BlockState.class, (type, o, loader, depthTracker) -> handle.createBlockState((String) o))
.registerLoader(PlatformBiome.class, (type, o, loader, depthTracker) -> parseBiome((String) o, depthTracker))
.registerLoader(EntityType.class, (type, o, loader, depthTracker) -> EntityType.valueOf((String) o));
.registerLoader(PlatformBiome.class, (type, o, loader, depthTracker) -> parseBiome((String) o, depthTracker))
.registerLoader(EntityType.class, (type, o, loader, depthTracker) -> EntityType.valueOf((String) o));
}
private BukkitPlatformBiome parseBiome(String id, DepthTracker depthTracker) throws LoadException {
if(!id.startsWith("minecraft:")) throw new LoadException("Invalid biome identifier " + id, depthTracker);
return new BukkitPlatformBiome(org.bukkit.block.Biome.valueOf(id.toUpperCase(Locale.ROOT).substring(10)));

View File

@@ -17,13 +17,16 @@
package com.dfsek.terra.bukkit;
import cloud.commandframework.brigadier.CloudBrigadierManager;
import cloud.commandframework.bukkit.CloudBukkitCapabilities;
import cloud.commandframework.execution.CommandExecutionCoordinator;
import cloud.commandframework.paper.PaperCommandManager;
import io.papermc.paper.threadedregions.scheduler.AsyncScheduler;
import io.papermc.paper.threadedregions.scheduler.GlobalRegionScheduler;
import org.bukkit.Bukkit;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.java.JavaPlugin;
import org.incendo.cloud.SenderMapper;
import org.incendo.cloud.brigadier.CloudBrigadierManager;
import org.incendo.cloud.bukkit.CloudBukkitCapabilities;
import org.incendo.cloud.execution.ExecutionCoordinator;
import org.incendo.cloud.paper.LegacyPaperCommandManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
@@ -31,6 +34,7 @@ import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import com.dfsek.terra.api.command.CommandSender;
import com.dfsek.terra.api.config.ConfigPack;
@@ -46,67 +50,86 @@ import com.dfsek.terra.bukkit.world.BukkitAdapter;
public class TerraBukkitPlugin extends JavaPlugin {
private static final Logger logger = LoggerFactory.getLogger(TerraBukkitPlugin.class);
private final PlatformImpl platform = new PlatformImpl(this);
private final Map<String, com.dfsek.terra.api.world.chunk.generation.ChunkGenerator> generatorMap = new HashMap<>();
private AsyncScheduler asyncScheduler = this.getServer().getAsyncScheduler();
private GlobalRegionScheduler globalRegionScheduler = this.getServer().getGlobalRegionScheduler();
@Override
public void onEnable() {
if(!doVersionCheck()) {
return;
}
platform.getEventManager().callEvent(new PlatformInitializationEvent());
if(!Initializer.init(platform)) {
Bukkit.getPluginManager().disablePlugin(this);
return;
}
try {
PaperCommandManager<CommandSender> commandManager = new PaperCommandManager<>(this,
CommandExecutionCoordinator.simpleCoordinator(),
BukkitAdapter::adapt,
BukkitAdapter::adapt);
if(commandManager.queryCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) {
commandManager.registerBrigadier();
final CloudBrigadierManager<?, ?> brigManager = commandManager.brigadierManager();
if(brigManager != null) {
brigManager.setNativeNumberSuggestions(false);
}
}
if(commandManager.queryCapability(CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)) {
commandManager.registerAsynchronousCompletions();
}
LegacyPaperCommandManager<CommandSender> commandManager = getCommandSenderPaperCommandManager();
platform.getEventManager().callEvent(new CommandRegistrationEvent(commandManager));
} catch(Exception e) { // This should never happen.
logger.error("""
TERRA HAS BEEN DISABLED
Errors occurred while registering commands.
Please report this to Terra.
""".strip(), e);
Bukkit.getPluginManager().disablePlugin(this);
return;
}
Bukkit.getPluginManager().registerEvents(new CommonListener(), this); // Register master event listener
PaperUtil.checkPaper(this);
Initializer.init(platform);
}
@NotNull
private LegacyPaperCommandManager<CommandSender> getCommandSenderPaperCommandManager() throws Exception {
// TODO: Update to PaperCommandManager
LegacyPaperCommandManager<CommandSender> commandManager = new LegacyPaperCommandManager<>(
this,
ExecutionCoordinator.simpleCoordinator(),
SenderMapper.create(
BukkitAdapter::adapt,
BukkitAdapter::adapt
));
if(commandManager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) {
commandManager.registerBrigadier();
final CloudBrigadierManager<?, ?> brigManager = commandManager.brigadierManager();
if(brigManager != null) {
brigManager.setNativeNumberSuggestions(false);
}
} else if(commandManager.hasCapability(CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)) {
commandManager.registerAsynchronousCompletions();
}
return commandManager;
}
public PlatformImpl getPlatform() {
return platform;
}
@SuppressWarnings({ "deprecation", "AccessOfSystemProperties" })
private boolean doVersionCheck() {
logger.info("Running on Minecraft version {} with server implementation {}.", VersionUtil.getMinecraftVersionInfo(),
Bukkit.getServer().getName());
Bukkit.getServer().getName());
if(!VersionUtil.getSpigotVersionInfo().isSpigot())
logger.error("YOU ARE RUNNING A CRAFTBUKKIT OR BUKKIT SERVER. PLEASE UPGRADE TO PAPER.");
if(!VersionUtil.getSpigotVersionInfo().isPaper())
logger.error("YOU ARE RUNNING A SPIGOT SERVER. PLEASE UPGRADE TO PAPER.");
if(VersionUtil.getSpigotVersionInfo().isMohist()) {
if(System.getProperty("IKnowMohistCausesLotsOfIssuesButIWillUseItAnyways") == null) {
Runnable runnable = () -> { // scary big block of text
@@ -150,7 +173,7 @@ public class TerraBukkitPlugin extends JavaPlugin {
""".strip());
};
runnable.run();
Bukkit.getScheduler().scheduleAsyncDelayedTask(this, runnable, 200L);
asyncScheduler.runDelayed(this, task -> runnable.run(), 200L, TimeUnit.SECONDS);
// Bukkit.shutdown(); // we're not *that* evil
Bukkit.getPluginManager().disablePlugin(this);
return false;
@@ -158,7 +181,7 @@ public class TerraBukkitPlugin extends JavaPlugin {
logger.warn("""
You are using Mohist, so we will not give you any support for issues that may arise.
Since you enabled the "IKnowMohistCausesLotsOfIssuesButIWillUseItAnyways" flag, we won't disable Terra. But be warned.
> I felt a great disturbance in the JVM, as if millions of plugins suddenly cried out in stack traces and were suddenly silenced.
> I fear something terrible has happened.
> - Astrash
@@ -167,14 +190,23 @@ public class TerraBukkitPlugin extends JavaPlugin {
}
return true;
}
@Override
public @Nullable
ChunkGenerator getDefaultWorldGenerator(@NotNull String worldName, String id) {
if(id == null || id.trim().equals("")) { return null; }
return new BukkitChunkGeneratorWrapper(generatorMap.computeIfAbsent(worldName, name -> {
ConfigPack pack = platform.getConfigRegistry().getByID(id).orElseThrow(
() -> new IllegalArgumentException("No such config pack \"" + id + "\""));
() -> new IllegalArgumentException("No such config pack \"" + id + "\""));
return pack.getGeneratorProvider().newInstance(pack);
}), platform.getRawConfigRegistry().getByID(id).orElseThrow(), platform.getWorldHandle().air());
}
public AsyncScheduler getAsyncScheduler() {
return asyncScheduler;
}
public GlobalRegionScheduler getGlobalRegionScheduler() {
return globalRegionScheduler;
}
}

View File

@@ -29,31 +29,31 @@ public class PreLoadCompatibilityOptions implements ConfigTemplate, Properties {
@Value("minecraft.use-vanilla-biomes")
@Default
private boolean vanillaBiomes = false;
@Value("minecraft.beard.enable")
@Default
private boolean beard = true;
@Value("minecraft.beard.threshold")
@Default
private double beardThreshold = 0.5;
@Value("minecraft.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

@@ -11,47 +11,47 @@ 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;
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;
}

View File

@@ -14,22 +14,22 @@ import com.dfsek.terra.api.world.biome.Biome;
public class BukkitBiomeProvider extends BiomeProvider implements Handle {
private final com.dfsek.terra.api.world.biome.generation.BiomeProvider delegate;
public BukkitBiomeProvider(com.dfsek.terra.api.world.biome.generation.BiomeProvider delegate) { this.delegate = delegate; }
@Override
public @NotNull org.bukkit.block.Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z) {
Biome biome = delegate.getBiome(x, y, z, worldInfo.getSeed());
return (org.bukkit.block.Biome) biome.getPlatformBiome().getHandle();
}
@Override
public @NotNull List<org.bukkit.block.Biome> getBiomes(@NotNull WorldInfo worldInfo) {
return StreamSupport.stream(delegate.getBiomes().spliterator(), false)
.map(terraBiome -> (org.bukkit.block.Biome) terraBiome.getPlatformBiome().getHandle())
.collect(Collectors.toList());
.map(terraBiome -> (org.bukkit.block.Biome) terraBiome.getPlatformBiome().getHandle())
.collect(Collectors.toList());
}
@Override
public Object getHandle() {
return delegate;

View File

@@ -13,21 +13,22 @@ import com.dfsek.terra.bukkit.world.BukkitProtoWorld;
public class BukkitBlockPopulator extends BlockPopulator {
private ConfigPack pack;
private final BlockState air;
private ConfigPack pack;
public BukkitBlockPopulator(ConfigPack pack, BlockState air) {
this.pack = pack;
this.air = air;
}
public void setPack(ConfigPack pack) {
this.pack = pack;
}
@Override
public void populate(@NotNull WorldInfo worldInfo, @NotNull Random random, int chunkX, int chunkZ,
@NotNull LimitedRegion limitedRegion) {
pack.getStages().forEach(generationStage -> generationStage.populate(new BukkitProtoWorld(limitedRegion, air, pack.getBiomeProvider())));
pack.getStages().forEach(
generationStage -> generationStage.populate(new BukkitProtoWorld(limitedRegion, air, pack.getBiomeProvider())));
}
}

View File

@@ -20,7 +20,6 @@ package com.dfsek.terra.bukkit.generator;
import org.bukkit.World;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.BlockPopulator;
import org.bukkit.generator.LimitedRegion;
import org.bukkit.generator.WorldInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -29,24 +28,22 @@ import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
import com.dfsek.terra.api.world.chunk.generation.util.GeneratorWrapper;
import com.dfsek.terra.api.world.info.WorldProperties;
import com.dfsek.terra.bukkit.world.BukkitProtoWorld;
import com.dfsek.terra.bukkit.world.BukkitWorldProperties;
public class BukkitChunkGeneratorWrapper extends org.bukkit.generator.ChunkGenerator implements GeneratorWrapper {
private static final Logger LOGGER = LoggerFactory.getLogger(BukkitChunkGeneratorWrapper.class);
private final BlockState air;
private final BukkitBlockPopulator blockPopulator;
private ChunkGenerator delegate;
private ConfigPack pack;
private final BukkitBlockPopulator blockPopulator;
public BukkitChunkGeneratorWrapper(ChunkGenerator delegate, ConfigPack pack, BlockState air) {
this.delegate = delegate;
@@ -54,38 +51,38 @@ public class BukkitChunkGeneratorWrapper extends org.bukkit.generator.ChunkGener
this.air = air;
this.blockPopulator = new BukkitBlockPopulator(pack, air);
}
public void setDelegate(ChunkGenerator delegate) {
this.delegate = delegate;
}
@Override
public @Nullable BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) {
return new BukkitBiomeProvider(pack.getBiomeProvider());
}
@Override
public void generateNoise(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull ChunkData chunkData) {
BukkitWorldProperties properties = new BukkitWorldProperties(worldInfo);
delegate.generateChunkData(new BukkitProtoChunk(chunkData), properties, pack.getBiomeProvider(), x, z);
}
@Override
public @NotNull List<BlockPopulator> getDefaultPopulators(@NotNull World world) {
return List.of(blockPopulator);
}
@Override
public boolean shouldGenerateCaves() {
return false;
//return pack.vanillaCaves();
}
@Override
public boolean shouldGenerateDecorations() {
return true;
}
@Override
public boolean shouldGenerateMobs() {
return true;
@@ -95,21 +92,21 @@ public class BukkitChunkGeneratorWrapper extends org.bukkit.generator.ChunkGener
public boolean shouldGenerateStructures() {
return true;
}
public ConfigPack getPack() {
return pack;
}
public void setPack(ConfigPack pack) {
this.pack = pack;
setDelegate(pack.getGeneratorProvider().newInstance(pack));
}
@Override
public ChunkGenerator getHandle() {
return delegate;
}
private record SeededVector(int x, int z, WorldProperties worldProperties) {
@Override

View File

@@ -26,30 +26,30 @@ import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState;
public class BukkitProtoChunk implements ProtoChunk {
private final ChunkGenerator.ChunkData delegate;
public BukkitProtoChunk(ChunkGenerator.ChunkData delegate) {
this.delegate = delegate;
}
@Override
public ChunkGenerator.ChunkData getHandle() {
return delegate;
}
@Override
public int getMaxHeight() {
return delegate.getMaxHeight();
}
@Override
public void setBlock(int x, int y, int z, @NotNull BlockState blockState) {
delegate.setBlock(x, y, z, ((BukkitBlockState) blockState).getHandle());
}
@Override
public @NotNull BlockState getBlock(int x, int y, int z) {
return BukkitBlockState.newInstance(delegate.getBlockData(x, y, z));

View File

@@ -32,18 +32,18 @@ import com.dfsek.terra.bukkit.world.BukkitAdapter;
public class BukkitItemHandle implements ItemHandle {
@Override
public Item createItem(String data) {
return BukkitAdapter.adapt(Material.matchMaterial(data));
}
@Override
public Enchantment getEnchantment(String id) {
return BukkitAdapter.adapt(
org.bukkit.enchantments.Enchantment.getByKey(NamespacedKey.minecraft(MinecraftUtils.stripMinecraftNamespace(id))));
org.bukkit.enchantments.Enchantment.getByKey(NamespacedKey.minecraft(MinecraftUtils.stripMinecraftNamespace(id))));
}
@Override
public Set<Enchantment> getEnchantments() {
return Arrays.stream(org.bukkit.enchantments.Enchantment.values()).map(BukkitAdapter::adapt).collect(Collectors.toSet());

View File

@@ -20,44 +20,45 @@ package com.dfsek.terra.bukkit.handles;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.dfsek.terra.api.block.state.BlockState;
import com.dfsek.terra.api.entity.EntityType;
import com.dfsek.terra.api.handle.WorldHandle;
import com.dfsek.terra.bukkit.util.BukkitUtils;
import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState;
import com.dfsek.terra.bukkit.world.entity.BukkitEntityType;
public class BukkitWorldHandle implements WorldHandle {
private static final Logger logger = LoggerFactory.getLogger(BukkitWorldHandle.class);
private final BlockState air;
public BukkitWorldHandle() {
this.air = BukkitBlockState.newInstance(Material.AIR.createBlockData());
}
@Override
public synchronized @NotNull BlockState createBlockState(@NotNull String data) {
if(data.equals("minecraft:grass")) { //TODO: remove in 7.0
data = "minecraft:short_grass";
logger.warn(
"Translating minecraft:grass to minecraft:short_grass. In 1.20.3 minecraft:grass was renamed to minecraft:short_grass" +
". You are advised to perform this rename in your config backs as this translation will be removed in the next major " +
"version of Terra.");
}
org.bukkit.block.data.BlockData bukkitData = Bukkit.createBlockData(
data); // somehow bukkit managed to make this not thread safe! :)
data); // somehow bukkit managed to make this not thread safe! :)
return BukkitBlockState.newInstance(bukkitData);
}
@Override
public @NotNull BlockState air() {
return air;
}
@Override
public @NotNull EntityType getEntity(@NotNull String id) {
if(!id.startsWith("minecraft:")) throw new IllegalArgumentException("Invalid entity identifier " + id);
String entityID = id.toUpperCase(Locale.ROOT).substring(10);
return new BukkitEntityType(switch(entityID) {
case "END_CRYSTAL" -> org.bukkit.entity.EntityType.ENDER_CRYSTAL;
case "ENDER_CRYSTAL" -> throw new IllegalArgumentException("Invalid entity identifier " + id); // make sure this issue can't happen the other way around.
default -> org.bukkit.entity.EntityType.valueOf(entityID);
});
return BukkitUtils.getEntityType(id);
}
}

View File

@@ -39,11 +39,11 @@ import com.dfsek.terra.api.Platform;
public class SpigotListener implements Listener {
private static final Logger logger = LoggerFactory.getLogger(SpigotListener.class);
private final Platform platform;
public SpigotListener(Platform platform) {
this.platform = platform;
}
@EventHandler(priority = EventPriority.NORMAL)
public void onEnderEye(EntitySpawnEvent e) {
/*
@@ -68,7 +68,7 @@ public class SpigotListener implements Listener {
}
*/
}
@EventHandler
public void onCartographerChange(VillagerAcquireTradeEvent e) {
if(!(e.getEntity() instanceof Villager))
@@ -85,7 +85,7 @@ public class SpigotListener implements Listener {
e.setCancelled(true); // Cancel leveling if the villager is a Cartographer, to prevent crashing server.
}
}
@EventHandler
public void onCartographerLevel(VillagerCareerChangeEvent e) {
if(e.getProfession() == Villager.Profession.CARTOGRAPHER) {

View File

@@ -1,20 +1,25 @@
package com.dfsek.terra.bukkit.nms;
import org.bukkit.Bukkit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.dfsek.terra.bukkit.PlatformImpl;
import com.dfsek.terra.bukkit.util.VersionUtil;
public interface Initializer {
String NMS = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
String NMS = VersionUtil.getMinecraftVersionInfo().toString().replace(".", "_");
String TERRA_PACKAGE = Initializer.class.getPackageName();
static void init(PlatformImpl platform) {
static boolean init(PlatformImpl platform) {
Logger logger = LoggerFactory.getLogger(Initializer.class);
try {
Class<?> initializerClass = Class.forName(TERRA_PACKAGE + "." + NMS + ".NMSInitializer");
String packageVersion = NMS;
if(NMS.equals("v1_21_1")) {
packageVersion = "v1_21";
}
Class<?> initializerClass = Class.forName(TERRA_PACKAGE + "." + packageVersion + ".NMSInitializer");
try {
Initializer initializer = (Initializer) initializerClass.getConstructor().newInstance();
initializer.initialize(platform);
@@ -24,17 +29,28 @@ public interface Initializer {
} catch(ClassNotFoundException e) {
logger.error("NMS bindings for version {} do not exist. Support for this version is limited.", NMS);
logger.error("This is usually due to running Terra on an unsupported Minecraft version.");
logger.error("");
logger.error("");
for(int i = 0; i < 20; i++) {
logger.error("PROCEEDING WITH AN EXISTING TERRA WORLD WILL RESULT IN CORRUPTION!!!");
String bypassKey = "IKnowThereAreNoNMSBindingsFor" + NMS + "ButIWillProceedAnyway";
if(System.getProperty(bypassKey) == null) {
logger.error("Because of this **TERRA HAS BEEN DISABLED**.");
logger.error("Do not come ask us why it is not working.");
logger.error("If you wish to proceed anyways, you can add the JVM System Property \"{}\" to enable the plugin.", bypassKey);
return false;
} else {
logger.error("");
logger.error("");
for(int i = 0; i < 20; i++) {
logger.error("PROCEEDING WITH AN EXISTING TERRA WORLD WILL RESULT IN CORRUPTION!!!");
}
logger.error("");
logger.error("");
logger.error("NMS bindings for version {} do not exist. Support for this version is limited.", NMS);
logger.error("This is usually due to running Terra on an unsupported Minecraft version.");
logger.error("We will not give you any support for issues that may arise.");
logger.error("Since you enabled the \"{}\" flag, we won't disable Terra. But be warned.", bypassKey);
}
logger.error("");
logger.error("");
logger.error("NMS bindings for version {} do not exist. Support for this version is limited.", NMS);
logger.error("This is usually due to running Terra on an unsupported Minecraft version.");
}
return true;
}
void initialize(PlatformImpl plugin);
}

View File

@@ -0,0 +1,41 @@
package com.dfsek.terra.bukkit.util;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Locale;
import com.dfsek.terra.api.entity.EntityType;
import com.dfsek.terra.bukkit.world.entity.BukkitEntityType;
public class BukkitUtils {
private static final Logger logger = LoggerFactory.getLogger(BukkitUtils.class);
public static boolean isLiquid(BlockData blockState) {
Material material = blockState.getMaterial();
return material == Material.WATER || material == Material.LAVA;
}
public static EntityType getEntityType(String id) {
if(!id.contains(":")) { //TODO: remove in 7.0
String newid = "minecraft:" + id.toLowerCase();
;
logger.warn(
"Translating " + id + " to " + newid + ". In 1.20.3 entity parsing was reworked" +
". You are advised to perform this rename in your config backs as this translation will be removed in the next major " +
"version of Terra.");
}
if(!id.startsWith("minecraft:")) throw new IllegalArgumentException("Invalid entity identifier " + id);
String entityID = id.toUpperCase(Locale.ROOT).substring(10);
return new BukkitEntityType(switch(entityID) {
case "END_CRYSTAL" -> org.bukkit.entity.EntityType.END_CRYSTAL;
case "ENDER_CRYSTAL" -> throw new IllegalArgumentException(
"Invalid entity identifier " + id); // make sure this issue can't happen the other way around.
default -> org.bukkit.entity.EntityType.valueOf(entityID);
});
}
}

View File

@@ -18,18 +18,20 @@
package com.dfsek.terra.bukkit.util;
import io.papermc.lib.PaperLib;
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import java.util.concurrent.TimeUnit;
import com.dfsek.terra.bukkit.TerraBukkitPlugin;
import static io.papermc.lib.PaperLib.suggestPaper;
public final class PaperUtil {
public static void checkPaper(JavaPlugin main) {
Bukkit.getScheduler().scheduleSyncDelayedTask(main, () -> {
public static void checkPaper(TerraBukkitPlugin plugin) {
plugin.getAsyncScheduler().runDelayed(plugin, task -> {
if(!PaperLib.isPaper()) {
suggestPaper(main);
suggestPaper(plugin);
}
}, 100L);
}, 100L, TimeUnit.SECONDS);
}
}

View File

@@ -12,12 +12,12 @@ import java.util.regex.Pattern;
public final class VersionUtil {
public static final SpigotVersionInfo SPIGOT_VERSION_INFO;
public static final MinecraftVersionInfo MINECRAFT_VERSION_INFO;
private static final Logger logger = LoggerFactory.getLogger(VersionUtil.class);
static {
SPIGOT_VERSION_INFO = new SpigotVersionInfo();
MinecraftVersionInfo mcVersionInfo;
try {
mcVersionInfo = new MinecraftVersionInfo();
@@ -27,28 +27,28 @@ public final class VersionUtil {
}
MINECRAFT_VERSION_INFO = mcVersionInfo;
}
public static MinecraftVersionInfo getMinecraftVersionInfo() {
return MINECRAFT_VERSION_INFO;
}
public static SpigotVersionInfo getSpigotVersionInfo() {
return SPIGOT_VERSION_INFO;
}
public static final class SpigotVersionInfo {
private final boolean spigot;
private final boolean paper;
private final boolean mohist;
public SpigotVersionInfo() {
logger.debug("Parsing spigot version info...");
paper = PaperLib.isPaper();
spigot = PaperLib.isSpigot();
boolean isMohist = false;
try {
Class.forName("com.mohistmc.MohistMC");
@@ -56,73 +56,77 @@ public final class VersionUtil {
isMohist = true;
} catch(ClassNotFoundException ignore) { }
this.mohist = isMohist;
logger.debug("Spigot version info parsed successfully.");
}
public boolean isPaper() {
return paper;
}
public boolean isMohist() {
return mohist;
}
public boolean isSpigot() {
return spigot;
}
}
public static final class MinecraftVersionInfo {
private static final Logger logger = LoggerFactory.getLogger(MinecraftVersionInfo.class);
private static final Pattern VERSION_PATTERN = Pattern.compile("v?(\\d+)_(\\d+)_R(\\d+)");
private static final Pattern VERSION_PATTERN = Pattern.compile("(\\d+)\\.(\\d+)(?:\\.(\\d+))?");
private final int major;
private final int minor;
private final int patch;
private MinecraftVersionInfo() {
this(Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3]);
this(Bukkit.getServer().getBukkitVersion().split("-")[0]);
}
private MinecraftVersionInfo(int major, int minor, int patch) {
this.major = major;
this.minor = minor;
this.patch = patch;
}
private MinecraftVersionInfo(String versionString) {
Matcher versionMatcher = VERSION_PATTERN.matcher(versionString);
if(versionMatcher.find()) {
major = Integer.parseInt(versionMatcher.group(1));
minor = Integer.parseInt(versionMatcher.group(2));
patch = Integer.parseInt(versionMatcher.group(3));
patch = versionMatcher.group(3) != null ? Integer.parseInt(versionMatcher.group(3)) : -1;
} else {
logger.warn("Error while parsing minecraft version info. Continuing launch, but setting all versions to -1.");
major = -1;
minor = -1;
patch = -1;
}
}
@Override
public String toString() {
if(major == -1 && minor == -1 && patch == -1)
return "Unknown";
return String.format("v%d.%d.%d", major, minor, patch);
if(patch >= 0) {
return String.format("v%d.%d.%d", major, minor, patch);
} else {
return String.format("v%d.%d", major, minor);
}
}
public int getMajor() {
return major;
}
public int getMinor() {
return minor;
}
public int getPatch() {
return patch;
}

View File

@@ -20,7 +20,6 @@ package com.dfsek.terra.bukkit.world;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.TreeType;
import org.bukkit.entity.Player;
import org.bukkit.generator.WorldInfo;
import org.bukkit.util.Vector;
@@ -46,35 +45,20 @@ import com.dfsek.terra.bukkit.world.block.BukkitBlockTypeAndItem;
import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState;
import com.dfsek.terra.bukkit.world.inventory.BukkitItemStack;
import com.dfsek.terra.bukkit.world.inventory.meta.BukkitEnchantment;
import com.dfsek.terra.transform.MapTransform;
import com.dfsek.terra.transform.TransformerImpl;
/**
* Utility class to adapt Bukkit enums to Terra enums.
*/
public final class BukkitAdapter {
public static TransformerImpl<TreeType, String> TREE_TRANSFORMER = new TransformerImpl.Builder<TreeType, String>()
.addTransform(new MapTransform<TreeType, String>()
.add(TreeType.COCOA_TREE, "JUNGLE_COCOA")
.add(TreeType.BIG_TREE, "LARGE_OAK")
.add(TreeType.TALL_REDWOOD, "LARGE_SPRUCE")
.add(TreeType.REDWOOD, "SPRUCE")
.add(TreeType.TREE, "OAK")
.add(TreeType.MEGA_REDWOOD, "MEGA_SPRUCE")
.add(TreeType.SWAMP, "SWAMP_OAK"))
.addTransform(TreeType::toString)
.build();
public static BlockState adapt(org.bukkit.block.data.BlockData data) {
return BukkitBlockState.newInstance(data);
}
public static org.bukkit.block.data.BlockData adapt(BlockState data) {
return ((BukkitBlockState) data).getHandle();
}
public static Axis adapt(org.bukkit.Axis axis) {
return switch(axis) {
case X -> Axis.X;
@@ -82,22 +66,22 @@ public final class BukkitAdapter {
case Z -> Axis.Z;
};
}
public static WorldProperties adapt(WorldInfo worldInfo) {
return new BukkitWorldProperties(worldInfo);
}
public static WorldInfo adapt(WorldProperties properties) {
return (WorldInfo) properties.getHandle();
}
public static Half adapt(org.bukkit.block.data.Bisected.Half half) {
return switch(half) {
case BOTTOM -> Half.BOTTOM;
case TOP -> Half.TOP;
};
}
public static RedstoneConnection adapt(org.bukkit.block.data.type.RedstoneWire.Connection connection) {
return switch(connection) {
case NONE -> RedstoneConnection.NONE;
@@ -105,7 +89,7 @@ public final class BukkitAdapter {
case SIDE -> RedstoneConnection.SIDE;
};
}
public static org.bukkit.block.data.type.RedstoneWire.Connection adapt(RedstoneConnection connection) {
return switch(connection) {
case SIDE -> org.bukkit.block.data.type.RedstoneWire.Connection.SIDE;
@@ -113,7 +97,7 @@ public final class BukkitAdapter {
case NONE -> org.bukkit.block.data.type.RedstoneWire.Connection.NONE;
};
}
public static RailShape adapt(org.bukkit.block.data.Rail.Shape shape) {
return switch(shape) {
case SOUTH_WEST -> RailShape.SOUTH_WEST;
@@ -128,7 +112,7 @@ public final class BukkitAdapter {
case EAST_WEST -> RailShape.EAST_WEST;
};
}
public static org.bukkit.block.data.Rail.Shape adapt(RailShape shape) {
return switch(shape) {
case EAST_WEST -> org.bukkit.block.data.Rail.Shape.EAST_WEST;
@@ -143,8 +127,8 @@ public final class BukkitAdapter {
case SOUTH_WEST -> org.bukkit.block.data.Rail.Shape.SOUTH_WEST;
};
}
public static org.bukkit.block.data.Bisected.Half adapt(Half half) {
return switch(half) {
case TOP -> org.bukkit.block.data.Bisected.Half.TOP;
@@ -152,7 +136,7 @@ public final class BukkitAdapter {
default -> throw new IllegalStateException();
};
}
public static org.bukkit.Axis adapt(Axis axis) {
return switch(axis) {
case Z -> org.bukkit.Axis.Z;
@@ -160,75 +144,75 @@ public final class BukkitAdapter {
case X -> org.bukkit.Axis.X;
};
}
public static Vector3 adapt(Location location) {
return Vector3.of(location.getX(), location.getY(), location.getZ());
}
public static Vector adapt(Vector3 vector3) {
return new Vector(vector3.getX(), vector3.getY(), vector3.getZ());
}
public static Vector3 adapt(Vector vector) {
return Vector3.of(vector.getX(), vector.getY(), vector.getZ());
}
public static CommandSender adapt(org.bukkit.command.CommandSender sender) {
return new BukkitCommandSender(sender);
}
public static Entity adapt(org.bukkit.entity.Entity entity) {
return new BukkitEntity(entity);
}
public static org.bukkit.command.CommandSender adapt(CommandSender sender) {
return ((BukkitCommandSender) sender).getHandle();
}
public static ServerWorld adapt(org.bukkit.World world) {
return new BukkitServerWorld(world);
}
public static org.bukkit.World adapt(ServerWorld world) {
return (org.bukkit.World) world.getHandle();
}
public static Chunk adapt(org.bukkit.Chunk chunk) {
return new BukkitChunk(chunk);
}
public static org.bukkit.Chunk adapt(Chunk chunk) {
return (org.bukkit.Chunk) chunk.getHandle();
}
public static Enchantment adapt(org.bukkit.enchantments.Enchantment enchantment) {
return new BukkitEnchantment(enchantment);
}
public static org.bukkit.enchantments.Enchantment adapt(Enchantment enchantment) {
return ((BukkitEnchantment) enchantment).getHandle();
}
public static Player adapt(com.dfsek.terra.api.entity.Player player) {
return ((BukkitPlayer) player).getHandle();
}
public static com.dfsek.terra.api.entity.Player adapt(Player player) {
return new BukkitPlayer(player);
}
public static BukkitBlockTypeAndItem adapt(Material material) {
return new BukkitBlockTypeAndItem(material);
}
public static Material adapt(BlockType type) {
return ((BukkitBlockTypeAndItem) type).getHandle();
}
public static ItemStack adapt(org.bukkit.inventory.ItemStack in) {
return new BukkitItemStack(in);
}
public static org.bukkit.inventory.ItemStack adapt(ItemStack in) {
return ((BukkitItemStack) in).getHandle();
}

View File

@@ -26,41 +26,41 @@ import com.dfsek.terra.api.world.chunk.Chunk;
public class BukkitChunk implements Chunk {
private final org.bukkit.Chunk delegate;
public BukkitChunk(org.bukkit.Chunk delegate) {
this.delegate = delegate;
}
@Override
public org.bukkit.Chunk getHandle() {
return delegate;
}
@Override
public void setBlock(int x, int y, int z, BlockState data, boolean physics) {
delegate.getBlock(x, y, z).setBlockData(BukkitAdapter.adapt(data), physics);
}
@Override
public void setBlock(int x, int y, int z, @NotNull BlockState blockState) {
delegate.getBlock(x, y, z).setBlockData(BukkitAdapter.adapt(blockState));
}
@Override
public @NotNull BlockState getBlock(int x, int y, int z) {
return BukkitAdapter.adapt(delegate.getBlock(x, y, z).getBlockData());
}
@Override
public int getX() {
return delegate.getX();
}
@Override
public int getZ() {
return delegate.getZ();
}
@Override
public ServerWorld getWorld() {
return BukkitAdapter.adapt(delegate.getWorld());

View File

@@ -25,16 +25,16 @@ import com.dfsek.terra.api.world.biome.PlatformBiome;
public class BukkitPlatformBiome implements PlatformBiome, PropertyHolder {
private final org.bukkit.block.Biome biome;
private final Context context = new Context();
public BukkitPlatformBiome(org.bukkit.block.Biome biome) {
this.biome = biome;
}
@Override
public org.bukkit.block.Biome getHandle() {
return biome;
}
@Override
public Context getContext() {
return context;

View File

@@ -1,6 +1,7 @@
package com.dfsek.terra.bukkit.world;
import org.bukkit.Location;
import org.bukkit.block.data.BlockData;
import org.bukkit.generator.LimitedRegion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -20,6 +21,7 @@ import com.dfsek.terra.api.world.chunk.generation.ChunkGenerator;
import com.dfsek.terra.api.world.chunk.generation.ProtoWorld;
import com.dfsek.terra.bukkit.BukkitEntity;
import com.dfsek.terra.bukkit.generator.BukkitChunkGeneratorWrapper;
import com.dfsek.terra.bukkit.util.BukkitUtils;
import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState;
import com.dfsek.terra.bukkit.world.block.state.BukkitBlockEntity;
import com.dfsek.terra.bukkit.world.entity.BukkitEntityType;
@@ -30,114 +32,119 @@ public class BukkitProtoWorld implements ProtoWorld {
private static final AtomicBoolean warn = new AtomicBoolean(true);
private final LimitedRegion delegate;
private final BlockState air;
private final BiomeProvider biomeProvider;
public BukkitProtoWorld(LimitedRegion delegate, BlockState air, BiomeProvider provider) {
this.delegate = delegate;
this.air = air;
this.biomeProvider = provider;
}
@Override
public LimitedRegion getHandle() {
return delegate;
}
@Override
public void setBlockState(int x, int y, int z, BlockState data, boolean physics) {
access(x, y, z, () -> {
delegate.setBlockData(x, y, z, BukkitAdapter.adapt(data));
BlockData bukkitData = BukkitAdapter.adapt(data);
delegate.setBlockData(x, y, z, bukkitData);
if(physics) {
delegate.scheduleBlockUpdate(x, y, z);
if(BukkitUtils.isLiquid(bukkitData)) {
delegate.scheduleFluidUpdate(x, y, z);
} else {
delegate.scheduleBlockUpdate(x, y, z);
}
}
});
}
@Override
public long getSeed() {
return delegate.getWorld().getSeed();
}
@Override
public int getMaxHeight() {
return delegate.getWorld().getMaxHeight();
}
@Override
public BlockState getBlockState(int x, int y, int z) {
return access(x, y, z, () -> BukkitBlockState.newInstance(delegate.getBlockData(x, y, z))).orElse(air);
}
@Override
public BlockEntity getBlockEntity(int x, int y, int z) {
return access(x, y, z, () -> BukkitBlockEntity.newInstance(delegate.getBlockState(x, y, z))).orElse(null);
}
@Override
public int getMinHeight() {
return delegate.getWorld().getMinHeight();
}
@Override
public Entity spawnEntity(double x, double y, double z, EntityType entityType) {
return access((int) x, (int) y, (int) z, () -> new BukkitEntity(
delegate.spawnEntity(new Location(delegate.getWorld(), x, y, z), ((BukkitEntityType) entityType).getHandle()))).orElse(
null);
delegate.spawnEntity(new Location(delegate.getWorld(), x, y, z), ((BukkitEntityType) entityType).getHandle()))).orElse(
null);
}
@Override
public ChunkGenerator getGenerator() {
return ((BukkitChunkGeneratorWrapper) delegate.getWorld().getGenerator()).getHandle();
}
@Override
public BiomeProvider getBiomeProvider() {
return biomeProvider;
}
@Override
public ConfigPack getPack() {
return ((BukkitChunkGeneratorWrapper) delegate.getWorld().getGenerator()).getPack();
}
@Override
public int centerChunkX() {
return delegate.getCenterChunkX();
}
@Override
public int centerChunkZ() {
return delegate.getCenterChunkZ();
}
@Override
public ServerWorld getWorld() {
return new BukkitServerWorld(delegate.getWorld());
}
private <T> Optional<T> access(int x, int y, int z, Supplier<T> action) {
if(delegate.isInRegion(x, y, z)) {
return Optional.of(action.get());
} else if(warn.getAndSet(false)) {
LOGGER.warn("Detected world access at coordinates out of bounds: ({}, {}, {}) accessed for region [{}, {}]", x, y, z,
delegate.getCenterChunkX(), delegate.getCenterChunkZ());
delegate.getCenterChunkX(), delegate.getCenterChunkZ());
} else {
LOGGER.debug("Detected world access at coordinates out of bounds: ({}, {}, {}) accessed for region [{}, {}]", x, y, z,
delegate.getCenterChunkX(), delegate.getCenterChunkZ());
delegate.getCenterChunkX(), delegate.getCenterChunkZ());
}
return Optional.empty();
}
private void access(int x, int y, int z, Runnable action) {
if(delegate.isInRegion(x, y, z)) {
action.run();
} else if(warn.getAndSet(false)) {
LOGGER.warn("Detected world access at coordinates out of bounds: ({}, {}, {}) accessed for region [{}, {}]", x, y, z,
delegate.getCenterChunkX(), delegate.getCenterChunkZ());
delegate.getCenterChunkX(), delegate.getCenterChunkZ());
} else {
LOGGER.debug("Detected world access at coordinates out of bounds: ({}, {}, {}) accessed for region [{}, {}]", x, y, z,
delegate.getCenterChunkX(), delegate.getCenterChunkZ());
delegate.getCenterChunkX(), delegate.getCenterChunkZ());
}
}
}

View File

@@ -36,83 +36,83 @@ import com.dfsek.terra.bukkit.world.entity.BukkitEntityType;
public class BukkitServerWorld implements ServerWorld {
private final org.bukkit.World delegate;
public BukkitServerWorld(org.bukkit.World delegate) {
this.delegate = delegate;
}
@Override
public Entity spawnEntity(double x, double y, double z, EntityType entityType) {
return new BukkitEntity(
delegate.spawnEntity(new Location(delegate, x, y, z), ((BukkitEntityType) entityType).getHandle()));
delegate.spawnEntity(new Location(delegate, x, y, z), ((BukkitEntityType) entityType).getHandle()));
}
@Override
public void setBlockState(int x, int y, int z, BlockState data, boolean physics) {
delegate.getBlockAt(x, y, z).setBlockData(BukkitAdapter.adapt(data), physics);
}
@Override
public long getSeed() {
return delegate.getSeed();
}
@Override
public int getMaxHeight() {
return delegate.getMaxHeight();
}
@Override
public Chunk getChunkAt(int x, int z) {
return BukkitAdapter.adapt(delegate.getChunkAt(x, z));
}
@Override
public BlockState getBlockState(int x, int y, int z) {
return BukkitAdapter.adapt(delegate.getBlockAt(x, y, z).getBlockData());
}
@Override
public BlockEntity getBlockEntity(int x, int y, int z) {
return BukkitBlockEntity.newInstance(delegate.getBlockAt(x, y, z).getState());
}
@Override
public int getMinHeight() {
return delegate.getMinHeight();
}
@Override
public ChunkGenerator getGenerator() {
return ((BukkitChunkGeneratorWrapper) delegate.getGenerator()).getHandle();
}
@Override
public BiomeProvider getBiomeProvider() {
return ((BukkitChunkGeneratorWrapper) delegate.getGenerator()).getPack().getBiomeProvider();
}
@Override
public ConfigPack getPack() {
return ((BukkitChunkGeneratorWrapper) delegate.getGenerator()).getPack();
}
@Override
public org.bukkit.World getHandle() {
return delegate;
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof BukkitServerWorld other)) return false;
return other.getHandle().equals(delegate);
}
@Override
public String toString() {
return delegate.toString();

View File

@@ -1,42 +1,42 @@
package com.dfsek.terra.bukkit.world;
import org.bukkit.generator.WorldInfo;
import com.dfsek.terra.api.world.info.WorldProperties;
import org.bukkit.generator.WorldInfo;
public class BukkitWorldProperties implements WorldProperties {
private final WorldInfo delegate;
public BukkitWorldProperties(WorldInfo delegate) {
this.delegate = delegate;
}
@Override
public Object getHandle() {
return delegate;
}
@Override
public long getSeed() {
return delegate.getSeed();
}
@Override
public int getMaxHeight() {
return delegate.getMaxHeight();
}
@Override
public int getMinHeight() {
return delegate.getMinHeight();
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
if(obj instanceof WorldProperties that) {

View File

@@ -28,46 +28,46 @@ import com.dfsek.terra.bukkit.world.BukkitAdapter;
public class BukkitBlockTypeAndItem implements BlockType, Item {
private final Material delegate;
public BukkitBlockTypeAndItem(Material delegate) {
this.delegate = delegate;
}
@Override
public Material getHandle() {
return delegate;
}
@Override
public BlockState getDefaultState() {
return BukkitAdapter.adapt(delegate.createBlockData());
}
@Override
public boolean isSolid() {
return delegate.isOccluding();
}
@Override
public boolean isWater() {
return delegate == Material.WATER;
}
@Override
public ItemStack newItemStack(int amount) {
return BukkitAdapter.adapt(new org.bukkit.inventory.ItemStack(delegate, amount));
}
@Override
public double getMaxDurability() {
return delegate.getMaxDurability();
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof BukkitBlockTypeAndItem)) return false;

View File

@@ -25,51 +25,51 @@ import com.dfsek.terra.bukkit.world.BukkitAdapter;
public class BukkitBlockState implements BlockState {
private final org.bukkit.block.data.BlockData delegate;
protected BukkitBlockState(org.bukkit.block.data.BlockData delegate) {
this.delegate = delegate;
}
public static BlockState newInstance(org.bukkit.block.data.BlockData bukkitData) {
return new BukkitBlockState(bukkitData);
}
@Override
public org.bukkit.block.data.BlockData getHandle() {
return delegate;
}
@Override
public boolean matches(BlockState data) {
return delegate.getMaterial() == ((BukkitBlockState) data).getHandle().getMaterial();
}
@Override
public <T extends Comparable<T>> boolean has(Property<T> property) {
return false;
}
@Override
public <T extends Comparable<T>> T get(Property<T> property) {
return null;
}
@Override
public <T extends Comparable<T>> BlockState set(Property<T> property, T value) {
return null;
}
@Override
public BlockType getBlockType() {
return BukkitAdapter.adapt(delegate.getMaterial());
}
@Override
public String getAsString(boolean properties) {
return delegate.getAsString(!properties);
}
@Override
public boolean isAir() {
return delegate.getMaterial().isAir();

View File

@@ -30,48 +30,48 @@ import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState;
public class BukkitBlockEntity implements BlockEntity {
private final org.bukkit.block.BlockState delegate;
protected BukkitBlockEntity(org.bukkit.block.BlockState block) {
this.delegate = block;
}
public static BukkitBlockEntity newInstance(org.bukkit.block.BlockState block) {
if(block instanceof Container) return new BukkitContainer((Container) block);
if(block instanceof Sign) return new BukkitSign((Sign) block);
if(block instanceof CreatureSpawner) return new BukkitMobSpawner((CreatureSpawner) block);
return new BukkitBlockEntity(block);
}
@Override
public org.bukkit.block.BlockState getHandle() {
return delegate;
}
@Override
public boolean update(boolean applyPhysics) {
return delegate.update(true, applyPhysics);
}
@Override
public Vector3 getPosition() {
return BukkitAdapter.adapt(delegate.getBlock().getLocation().toVector());
}
@Override
public int getX() {
return delegate.getX();
}
@Override
public int getY() {
return delegate.getY();
}
@Override
public int getZ() {
return delegate.getZ();
}
@Override
public BlockState getBlockState() {
return BukkitBlockState.newInstance(delegate.getBlockData());

View File

@@ -23,16 +23,16 @@ import com.dfsek.terra.bukkit.world.inventory.BukkitInventory;
public class BukkitContainer extends BukkitBlockEntity implements Container {
protected BukkitContainer(org.bukkit.block.Container block) {
super(block);
}
@Override
public Inventory getInventory() {
return new BukkitInventory(((org.bukkit.block.Container) getHandle()).getInventory());
}
@Override
public boolean update(boolean applyPhysics) {
return false; // This clears the inventory. we don't want that.

View File

@@ -23,6 +23,7 @@ import org.jetbrains.annotations.NotNull;
import com.dfsek.terra.api.block.entity.MobSpawner;
import com.dfsek.terra.api.block.entity.SerialState;
import com.dfsek.terra.api.entity.EntityType;
import com.dfsek.terra.bukkit.util.BukkitUtils;
import com.dfsek.terra.bukkit.world.entity.BukkitEntityType;
@@ -30,92 +31,92 @@ public class BukkitMobSpawner extends BukkitBlockEntity implements MobSpawner {
protected BukkitMobSpawner(CreatureSpawner block) {
super(block);
}
@Override
public EntityType getSpawnedType() {
return new BukkitEntityType(((CreatureSpawner) getHandle()).getSpawnedType());
}
@Override
public void setSpawnedType(@NotNull EntityType creatureType) {
((CreatureSpawner) getHandle()).setSpawnedType(((BukkitEntityType) creatureType).getHandle());
}
@Override
public int getDelay() {
return ((CreatureSpawner) getHandle()).getDelay();
}
@Override
public void setDelay(int delay) {
((CreatureSpawner) getHandle()).setDelay(delay);
}
@Override
public int getMinSpawnDelay() {
return ((CreatureSpawner) getHandle()).getMinSpawnDelay();
}
@Override
public void setMinSpawnDelay(int delay) {
((CreatureSpawner) getHandle()).setMinSpawnDelay(delay);
}
@Override
public int getMaxSpawnDelay() {
return ((CreatureSpawner) getHandle()).getMaxSpawnDelay();
}
@Override
public void setMaxSpawnDelay(int delay) {
((CreatureSpawner) getHandle()).setMaxSpawnDelay(delay);
}
@Override
public int getSpawnCount() {
return ((CreatureSpawner) getHandle()).getSpawnCount();
}
@Override
public void setSpawnCount(int spawnCount) {
((CreatureSpawner) getHandle()).setSpawnCount(spawnCount);
}
@Override
public int getMaxNearbyEntities() {
return ((CreatureSpawner) getHandle()).getMaxNearbyEntities();
}
@Override
public void setMaxNearbyEntities(int maxNearbyEntities) {
((CreatureSpawner) getHandle()).setMaxNearbyEntities(maxNearbyEntities);
}
@Override
public int getRequiredPlayerRange() {
return ((CreatureSpawner) getHandle()).getRequiredPlayerRange();
}
@Override
public void setRequiredPlayerRange(int requiredPlayerRange) {
((CreatureSpawner) getHandle()).setRequiredPlayerRange(requiredPlayerRange);
}
@Override
public int getSpawnRange() {
return ((CreatureSpawner) getHandle()).getSpawnRange();
}
@Override
public void setSpawnRange(int spawnRange) {
((CreatureSpawner) getHandle()).setSpawnRange(spawnRange);
}
@Override
public void applyState(String state) {
SerialState.parse(state).forEach((k, v) -> {
switch(k) {
case "type" -> setSpawnedType(new BukkitEntityType(org.bukkit.entity.EntityType.valueOf(v.toUpperCase())));
case "type" -> setSpawnedType(BukkitUtils.getEntityType(v));
case "delay" -> setDelay(Integer.parseInt(v));
case "min_delay" -> setMinSpawnDelay(Integer.parseInt(v));
case "max_delay" -> setMaxSpawnDelay(Integer.parseInt(v));

View File

@@ -28,22 +28,22 @@ public class BukkitSign extends BukkitBlockEntity implements Sign {
protected BukkitSign(org.bukkit.block.Sign block) {
super(block);
}
@Override
public void setLine(int index, @NotNull String line) throws IndexOutOfBoundsException {
((org.bukkit.block.Sign) getHandle()).setLine(index, line);
}
@Override
public @NotNull String[] getLines() {
return ((org.bukkit.block.Sign) getHandle()).getLines();
}
@Override
public @NotNull String getLine(int index) throws IndexOutOfBoundsException {
return ((org.bukkit.block.Sign) getHandle()).getLine(index);
}
@Override
public void applyState(String state) {
SerialState.parse(state).forEach((k, v) -> {

View File

@@ -22,11 +22,11 @@ import com.dfsek.terra.api.entity.EntityType;
public class BukkitEntityType implements EntityType {
private final org.bukkit.entity.EntityType delegate;
public BukkitEntityType(org.bukkit.entity.EntityType delegate) {
this.delegate = delegate;
}
@Override
public org.bukkit.entity.EntityType getHandle() {
return delegate;

View File

@@ -23,27 +23,27 @@ import com.dfsek.terra.api.inventory.ItemStack;
public class BukkitInventory implements Inventory {
private final org.bukkit.inventory.Inventory delegate;
public BukkitInventory(org.bukkit.inventory.Inventory delegate) {
this.delegate = delegate;
}
@Override
public void setItem(int slot, ItemStack newStack) {
delegate.setItem(slot, ((BukkitItemStack) newStack).getHandle());
}
@Override
public int getSize() {
return delegate.getSize();
}
@Override
public ItemStack getItem(int slot) {
org.bukkit.inventory.ItemStack itemStack = delegate.getItem(slot);
return itemStack == null ? null : new BukkitItemStack(itemStack);
}
@Override
public org.bukkit.inventory.Inventory getHandle() {
return delegate;

View File

@@ -31,26 +31,26 @@ import com.dfsek.terra.bukkit.world.inventory.meta.BukkitEnchantment;
public class BukkitItemMeta implements ItemMeta {
private final org.bukkit.inventory.meta.ItemMeta delegate;
protected BukkitItemMeta(org.bukkit.inventory.meta.ItemMeta delegate) {
this.delegate = delegate;
}
public static BukkitItemMeta newInstance(org.bukkit.inventory.meta.ItemMeta delegate) {
if(delegate instanceof Damageable) return new BukkitDamageable((Damageable) delegate);
return new BukkitItemMeta(delegate);
}
@Override
public org.bukkit.inventory.meta.ItemMeta getHandle() {
return delegate;
}
@Override
public void addEnchantment(Enchantment enchantment, int level) {
delegate.addEnchant(((BukkitEnchantment) enchantment).getHandle(), level, true);
}
@Override
public Map<Enchantment, Integer> getEnchantments() {
Map<Enchantment, Integer> map = new HashMap<>();

View File

@@ -25,36 +25,36 @@ import com.dfsek.terra.bukkit.world.BukkitAdapter;
public class BukkitItemStack implements ItemStack {
private final org.bukkit.inventory.ItemStack delegate;
public BukkitItemStack(org.bukkit.inventory.ItemStack delegate) {
this.delegate = delegate;
}
@Override
public int getAmount() {
return delegate.getAmount();
}
@Override
public void setAmount(int i) {
delegate.setAmount(i);
}
@Override
public Item getType() {
return BukkitAdapter.adapt(delegate.getType());
}
@Override
public ItemMeta getItemMeta() {
return BukkitItemMeta.newInstance(delegate.getItemMeta());
}
@Override
public void setItemMeta(ItemMeta meta) {
delegate.setItemMeta(((BukkitItemMeta) meta).getHandle());
}
@Override
public org.bukkit.inventory.ItemStack getHandle() {
return delegate;

View File

@@ -25,17 +25,17 @@ public class BukkitDamageable extends BukkitItemMeta implements Damageable {
public BukkitDamageable(org.bukkit.inventory.meta.Damageable delegate) {
super(delegate);
}
@Override
public int getDamage() {
return ((org.bukkit.inventory.meta.Damageable) getHandle()).getDamage();
}
@Override
public void setDamage(int damage) {
((org.bukkit.inventory.meta.Damageable) getHandle()).setDamage(damage);
}
@Override
public boolean hasDamage() {
return ((org.bukkit.inventory.meta.Damageable) getHandle()).hasDamage();

View File

@@ -24,31 +24,31 @@ import com.dfsek.terra.bukkit.world.inventory.BukkitItemStack;
public class BukkitEnchantment implements Enchantment {
private final org.bukkit.enchantments.Enchantment delegate;
public BukkitEnchantment(org.bukkit.enchantments.Enchantment delegate) {
this.delegate = delegate;
}
@Override
public org.bukkit.enchantments.Enchantment getHandle() {
return delegate;
}
@Override
public boolean canEnchantItem(ItemStack itemStack) {
return delegate.canEnchantItem(((BukkitItemStack) itemStack).getHandle());
}
@Override
public boolean conflictsWith(Enchantment other) {
return delegate.conflictsWith(((BukkitEnchantment) other).getHandle());
}
@Override
public String getID() {
return delegate.getKey().toString();
}
@Override
public int getMaxLevel() {
return delegate.getMaxLevel();

View File

@@ -2,7 +2,8 @@ name: "Terra"
main: "com.dfsek.terra.bukkit.TerraBukkitPlugin"
version: "@VERSION@"
load: "STARTUP"
author: dfsek
authors: [ "dfsek", "duplexsystem", "Astrash", "solonovamax", "Sancires", "Aureus", "RogueShade" ]
website: "@WIKI@"
api-version: "1.13"
api-version: "1.21.1"
description: "@DESCRIPTION@"
folia-supported: true

View File

@@ -1,17 +0,0 @@
apply(plugin = "io.papermc.paperweight.userdev")
repositories {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
api(project(":platforms:bukkit:common"))
paperDevBundle("1.18.2-R0.1-SNAPSHOT")
implementation("xyz.jpenilla", "reflection-remapper", "0.1.0-SNAPSHOT")
}
tasks {
assemble {
dependsOn("reobfJar")
}
}

View File

@@ -1,115 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.Holder;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.data.BuiltinRegistries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.biome.Biome;
import org.bukkit.NamespacedKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
import com.dfsek.terra.registry.master.ConfigRegistry;
public class AwfulBukkitHacks {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSBiomeInjector.class);
private static final Map<ResourceLocation, List<ResourceLocation>> terraBiomeMap = new HashMap<>();
public static void registerBiomes(ConfigRegistry configRegistry) {
try {
LOGGER.info("Hacking biome registry...");
WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) Registries.biomeRegistry();
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, false);
configRegistry.forEach(pack -> pack.getRegistry(com.dfsek.terra.api.world.biome.Biome.class).forEach((key, biome) -> {
try {
BukkitPlatformBiome platformBiome = (BukkitPlatformBiome) biome.getPlatformBiome();
NamespacedKey vanillaBukkitKey = platformBiome.getHandle().getKey();
ResourceLocation vanillaMinecraftKey = new ResourceLocation(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey());
Biome platform = NMSBiomeInjector.createBiome(
biome,
biomeRegistry.get(vanillaMinecraftKey) // get
);
ResourceKey<Biome> delegateKey = ResourceKey.create(Registry.BIOME_REGISTRY, new ResourceLocation("terra",
NMSBiomeInjector.createBiomeID(
pack, key)));
BuiltinRegistries.register(BuiltinRegistries.BIOME, delegateKey, platform);
biomeRegistry.register(delegateKey, platform, Lifecycle.stable());
platformBiome.getContext().put(new NMSBiomeInfo(delegateKey));
terraBiomeMap.computeIfAbsent(vanillaMinecraftKey, i -> new ArrayList<>()).add(delegateKey.location());
LOGGER.debug("Registered biome: " + delegateKey);
} catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}));
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, true); // freeze registry again :)
LOGGER.info("Doing tag garbage....");
Map<TagKey<Biome>, List<Holder<Biome>>> collect = biomeRegistry
.getTags() // streamKeysAndEntries
.collect(HashMap::new,
(map, pair) ->
map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())),
HashMap::putAll);
terraBiomeMap
.forEach((vb, terraBiomes) ->
NMSBiomeInjector.getEntry(biomeRegistry, vb)
.ifPresentOrElse(
vanilla -> terraBiomes
.forEach(tb -> NMSBiomeInjector.getEntry(biomeRegistry, tb)
.ifPresentOrElse(
terra -> {
LOGGER.debug(
vanilla.unwrapKey()
.orElseThrow()
.location() +
" (vanilla for " +
terra.unwrapKey()
.orElseThrow()
.location() +
": " +
vanilla.tags()
.toList());
vanilla.tags()
.forEach(
tag -> collect
.computeIfAbsent(
tag,
t -> new ArrayList<>())
.add(terra));
},
() -> LOGGER.error(
"No such biome: {}",
tb))),
() -> LOGGER.error("No vanilla biome: {}", vb)));
biomeRegistry.resetTags(); // clearTags
biomeRegistry.bindTags(ImmutableMap.copyOf(collect)); // populateTags
} catch(SecurityException | IllegalArgumentException exception) {
throw new RuntimeException(exception);
}
}
}

View File

@@ -1,10 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
import com.dfsek.terra.api.properties.Properties;
public record NMSBiomeInfo(ResourceKey<Biome> biomeKey) implements Properties {
}

View File

@@ -1,79 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSpecialEffects;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.bukkit.config.VanillaBiomeProperties;
public class NMSBiomeInjector {
public static <T> Optional<Holder<T>> getEntry(Registry<T> registry, ResourceLocation identifier) {
return registry.getOptional(identifier)
.flatMap(registry::getResourceKey)
.map(registry::getOrCreateHolder);
}
public static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Biome.BiomeBuilder builder = new Biome.BiomeBuilder(); // Builder
builder.biomeCategory(Reflection.BIOME.getBiomeCategory(vanilla))
.precipitation(vanilla.getPrecipitation()) // getPrecipitation
.mobSpawnSettings(vanilla.getMobSettings())
.generationSettings(vanilla.getGenerationSettings())
.temperature(vanilla.getBaseTemperature())
.downfall(vanilla.getDownfall());
BiomeSpecialEffects.Builder effects = new BiomeSpecialEffects.Builder();
effects.grassColorModifier(vanilla.getSpecialEffects().getGrassColorModifier());
VanillaBiomeProperties vanillaBiomeProperties = biome.getContext().get(VanillaBiomeProperties.class);
effects.fogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getFogColor(), vanilla.getFogColor()))
.waterColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterColor(), vanilla.getWaterColor()))
.waterFogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterFogColor(), vanilla.getWaterFogColor()))
.skyColor(Objects.requireNonNullElse(vanillaBiomeProperties.getSkyColor(), vanilla.getSkyColor()));
if(vanillaBiomeProperties.getFoliageColor() == null) {
vanilla.getSpecialEffects().getFoliageColorOverride().ifPresent(effects::foliageColorOverride);
} else {
effects.foliageColorOverride(vanillaBiomeProperties.getFoliageColor());
}
if(vanillaBiomeProperties.getGrassColor() == null) {
vanilla.getSpecialEffects().getGrassColorOverride().ifPresent(effects::grassColorOverride);
} else {
effects.grassColorOverride(vanillaBiomeProperties.getGrassColor());
}
vanilla.getAmbientLoop().ifPresent(effects::ambientLoopSound);
vanilla.getAmbientAdditions().ifPresent(effects::ambientAdditionsSound);
vanilla.getAmbientMood().ifPresent(effects::ambientMoodSound);
vanilla.getBackgroundMusic().ifPresent(effects::backgroundMusic);
vanilla.getAmbientParticle().ifPresent(effects::ambientParticle);
builder.specialEffects(effects.build());
return builder.build(); // build()
}
public static String createBiomeID(ConfigPack pack, com.dfsek.terra.api.registry.key.RegistryKey biomeID) {
return pack.getID()
.toLowerCase() + "/" + biomeID.getNamespace().toLowerCase(Locale.ROOT) + "/" + biomeID.getID().toLowerCase(Locale.ROOT);
}
}

View File

@@ -1,49 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import com.mojang.serialization.Codec;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Climate.Sampler;
import org.jetbrains.annotations.NotNull;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
public class NMSBiomeProvider extends BiomeSource {
private final BiomeProvider delegate;
private final BiomeSource vanilla;
private final long seed;
private final Registry<Biome> biomeRegistry = Registries.biomeRegistry();
public NMSBiomeProvider(BiomeProvider delegate, BiomeSource vanilla, long seed) {
super(delegate.stream()
.map(biome -> Registries.biomeRegistry()
.getOrCreateHolder(((BukkitPlatformBiome) biome.getPlatformBiome()).getContext()
.get(NMSBiomeInfo.class)
.biomeKey())));
this.delegate = delegate;
this.vanilla = vanilla;
this.seed = seed;
}
@Override
protected Codec<? extends BiomeSource> codec() {
return BiomeSource.CODEC;
}
@Override
public @NotNull BiomeSource withSeed(long seed) {
return new NMSBiomeProvider(delegate, vanilla, seed);
}
@Override
public @NotNull Holder<Biome> getNoiseBiome(int x, int y, int z, @NotNull Sampler sampler) {
return biomeRegistry.getOrCreateHolder(((BukkitPlatformBiome) delegate.getBiome(x << 2, y << 2, z << 2, seed).getPlatformBiome())
.getContext()
.get(NMSBiomeInfo.class)
.biomeKey());
}
}

View File

@@ -1,253 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.SectionPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.NoiseColumn;
import net.minecraft.world.level.StructureFeatureManager;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.biome.Climate;
import net.minecraft.world.level.biome.Climate.Sampler;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.GenerationStep;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.blending.Blender;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
import net.minecraft.world.level.levelgen.structure.placement.StructurePlacement;
import org.bukkit.craftbukkit.v1_18_R2.block.data.CraftBlockData;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.util.generic.Lazy;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.info.WorldProperties;
public class NMSChunkGeneratorDelegate extends ChunkGenerator {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSChunkGeneratorDelegate.class);
private static final Lazy<List<ChunkPos>> EMPTY = Lazy.lazy(List::of);
private final NMSBiomeProvider biomeSource;
private final com.dfsek.terra.api.world.chunk.generation.ChunkGenerator delegate;
private final ChunkGenerator vanilla;
private final ConfigPack pack;
private final long seed;
private final Map<ConcentricRingsStructurePlacement, Lazy<List<ChunkPos>>> ringPositions = new Object2ObjectArrayMap<>();
private volatile boolean rings = false;
public NMSChunkGeneratorDelegate(ChunkGenerator vanilla, ConfigPack pack, NMSBiomeProvider biomeProvider, long seed) {
super(Registries.structureSet(), Optional.empty(), biomeProvider, biomeProvider, seed);
this.delegate = pack.getGeneratorProvider().newInstance(pack);
this.vanilla = vanilla;
this.biomeSource = biomeProvider;
this.pack = pack;
this.seed = seed;
}
@Override
public void applyCarvers(@NotNull WorldGenRegion chunkRegion, long seed, @NotNull BiomeManager biomeAccess,
@NotNull StructureFeatureManager structureAccessor,
@NotNull ChunkAccess chunk, GenerationStep.@NotNull Carving generationStep) {
// no-op
}
@Override
public void applyBiomeDecoration(@NotNull WorldGenLevel world, @NotNull ChunkAccess chunk,
@NotNull StructureFeatureManager structureAccessor) {
vanilla.applyBiomeDecoration(world, chunk, structureAccessor);
}
@Override
public int getSeaLevel() {
return vanilla.getSeaLevel();
}
@Override
public @NotNull CompletableFuture<ChunkAccess> fillFromNoise(@NotNull Executor executor, @NotNull Blender blender,
@NotNull StructureFeatureManager structureAccessor,
@NotNull ChunkAccess chunk) {
return vanilla.fillFromNoise(executor, blender, structureAccessor, chunk);
}
@Override
public void buildSurface(@NotNull WorldGenRegion region, @NotNull StructureFeatureManager structures, @NotNull ChunkAccess chunk) {
// no-op
}
@Override
protected @NotNull Codec<? extends ChunkGenerator> codec() {
return ChunkGenerator.CODEC;
}
@Override
public @NotNull NoiseColumn getBaseColumn(int x, int z, LevelHeightAccessor height) {
/*
BlockState[] array = new BlockState[height.getHeight()];
WorldProperties properties = new NMSWorldProperties(seed, height);
BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties);
for(int y = properties.getMaxHeight() - 1; y >= properties.getMinHeight(); y--) {
array[y - properties.getMinHeight()] = ((CraftBlockData) delegate.getBlock(properties, x, y, z, biomeProvider)
.getHandle()).getState();
}
return new NoiseColumn(getMinY(), array);
*/
return vanilla.getBaseColumn(x, z, height);
}
@Override // withSeed
public @NotNull ChunkGenerator withSeed(long seed) {
return new NMSChunkGeneratorDelegate(vanilla, pack, biomeSource, seed);
}
@Override
public void spawnOriginalMobs(@NotNull WorldGenRegion regionlimitedworldaccess) {
vanilla.spawnOriginalMobs(regionlimitedworldaccess);
}
@Override
public int getGenDepth() {
return vanilla.getGenDepth();
}
@Override
public @NotNull Sampler climateSampler() {
return Climate.empty();
}
@Override
public int getMinY() {
return vanilla.getMinY();
}
@Override
public int getBaseHeight(int x, int z, Heightmap.@NotNull Types heightmap, @NotNull LevelHeightAccessor world) {
WorldProperties properties = new NMSWorldProperties(seed, world);
int y = properties.getMaxHeight();
BiomeProvider biomeProvider = pack.getBiomeProvider();
while(y >= getMinY() && !heightmap.isOpaque().test(
((CraftBlockData) delegate.getBlock(properties, x, y - 1, z, biomeProvider).getHandle()).getState())) {
y--;
}
return y;
}
@Nullable
@Override
public List<ChunkPos> getRingPositionsFor(@NotNull ConcentricRingsStructurePlacement concentricringsstructureplacement) {
ensureStructuresGenerated();
return ringPositions.getOrDefault(concentricringsstructureplacement, EMPTY).value();
}
@Override
public synchronized void ensureStructuresGenerated() {
if(!this.rings) {
super.ensureStructuresGenerated();
this.populateStrongholdData();
this.rings = true;
}
}
private void populateStrongholdData() {
LOGGER.info("Generating safe stronghold data. This may take up to a minute.");
Set<Holder<Biome>> set = this.runtimeBiomeSource.possibleBiomes();
possibleStructureSets().map(Holder::value).forEach((holder) -> { // we dont need the spigot crap because it doesnt touch concentric.
StructurePlacement structureplacement = holder.placement();
if(structureplacement instanceof ConcentricRingsStructurePlacement concentricringsstructureplacement) {
if(holder.structures().stream().anyMatch((structureset_a1) -> structureset_a1.generatesInMatchingBiome(set::contains))) {
this.ringPositions.put(concentricringsstructureplacement,
Lazy.lazy(() -> this.generateRingPositions(holder, concentricringsstructureplacement)));
}
}
});
}
private List<ChunkPos> generateRingPositions(StructureSet holder,
ConcentricRingsStructurePlacement concentricringsstructureplacement) { // Spigot
if(concentricringsstructureplacement.count() == 0) {
return List.of();
}
List<ChunkPos> list = new ArrayList<>();
Set<Holder<Biome>> set = holder
.structures()
.stream()
.flatMap((structureset_a) -> structureset_a.structure().value().biomes().stream())
.collect(Collectors.toSet());
int i = concentricringsstructureplacement.distance();
int j = concentricringsstructureplacement.count();
int k = concentricringsstructureplacement.spread();
Random random = new Random();
// Paper start
if(this.conf.strongholdSeed != null && this.structureSets.getResourceKey(holder).orElse(null) ==
net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS) {
random.setSeed(this.conf.strongholdSeed);
} else {
// Paper end
random.setSeed(this.ringPlacementSeed);
} // Paper
double d0 = random.nextDouble() * 3.141592653589793D * 2.0D;
int l = 0;
int i1 = 0;
for(int j1 = 0; j1 < j; ++j1) {
double d1 = (double) (4 * i + i * i1 * 6) + (random.nextDouble() - 0.5D) * (double) i * 2.5D;
int k1 = (int) Math.round(Math.cos(d0) * d1);
int l1 = (int) Math.round(Math.sin(d0) * d1);
int i2 = SectionPos.sectionToBlockCoord(k1, 8);
int j2 = SectionPos.sectionToBlockCoord(l1, 8);
Objects.requireNonNull(set);
Pair<BlockPos, Holder<Biome>> pair = this.biomeSource.findBiomeHorizontal(i2, 0, j2, 112, set::contains, random,
this.climateSampler());
if(pair != null) {
BlockPos blockposition = pair.getFirst();
k1 = SectionPos.blockToSectionCoord(blockposition.getX());
l1 = SectionPos.blockToSectionCoord(blockposition.getZ());
}
list.add(new ChunkPos(k1, l1));
d0 += 6.283185307179586D / (double) k;
++l;
if(l == k) {
++i1;
l = 0;
k += 2 * k / (i1 + 1);
k = Math.min(k, j - j1);
d0 += random.nextDouble() * 3.141592653589793D * 2.0D;
}
}
return list;
}
@Override
public void addDebugScreenInfo(@NotNull List<String> arg0, @NotNull BlockPos arg1) {
}
}

View File

@@ -1,15 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import org.bukkit.Bukkit;
import com.dfsek.terra.bukkit.PlatformImpl;
import com.dfsek.terra.bukkit.nms.Initializer;
public class NMSInitializer implements Initializer {
@Override
public void initialize(PlatformImpl platform) {
AwfulBukkitHacks.registerBiomes(platform.getRawConfigRegistry());
Bukkit.getPluginManager().registerEvents(new NMSInjectListener(), platform.getPlugin());
}
}

View File

@@ -1,53 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkGenerator;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_18_R2.CraftWorld;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.bukkit.generator.BukkitChunkGeneratorWrapper;
public class NMSInjectListener implements Listener {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSInjectListener.class);
private static final Set<World> INJECTED = new HashSet<>();
private static final ReentrantLock INJECT_LOCK = new ReentrantLock();
@EventHandler
public void onWorldInit(WorldInitEvent event) {
if(!INJECTED.contains(event.getWorld()) &&
event.getWorld().getGenerator() instanceof BukkitChunkGeneratorWrapper bukkitChunkGeneratorWrapper) {
INJECT_LOCK.lock();
INJECTED.add(event.getWorld());
LOGGER.info("Preparing to take over the world: {}", event.getWorld().getName());
CraftWorld craftWorld = (CraftWorld) event.getWorld();
ServerLevel serverWorld = craftWorld.getHandle();
ConfigPack pack = bukkitChunkGeneratorWrapper.getPack();
ChunkGenerator vanilla = serverWorld.getChunkSource().getGenerator();
NMSBiomeProvider provider = new NMSBiomeProvider(pack.getBiomeProvider(), vanilla.getBiomeSource(), craftWorld.getSeed());
NMSChunkGeneratorDelegate custom = new NMSChunkGeneratorDelegate(vanilla, pack, provider, craftWorld.getSeed());
custom.conf = vanilla.conf; // world config from Spigot
serverWorld.getChunkSource().chunkMap.generator = custom;
LOGGER.info("Successfully injected into world.");
serverWorld.getChunkSource().chunkMap.generator.ensureStructuresGenerated(); // generate stronghold data now
INJECT_LOCK.unlock();
}
}
}

View File

@@ -1,36 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import net.minecraft.world.level.LevelHeightAccessor;
import com.dfsek.terra.api.world.info.WorldProperties;
public class NMSWorldProperties implements WorldProperties {
private final long seed;
private final LevelHeightAccessor height;
public NMSWorldProperties(long seed, LevelHeightAccessor height) {
this.seed = seed;
this.height = height;
}
@Override
public Object getHandle() {
return height;
}
@Override
public long getSeed() {
return seed;
}
@Override
public int getMaxHeight() {
return height.getMaxBuildHeight();
}
@Override
public int getMinHeight() {
return height.getMinBuildHeight();
}
}

View File

@@ -1,38 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import net.minecraft.core.MappedRegistry;
import net.minecraft.world.level.biome.Biome;
import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
import xyz.jpenilla.reflectionremapper.proxy.ReflectionProxyFactory;
import xyz.jpenilla.reflectionremapper.proxy.annotation.FieldGetter;
import xyz.jpenilla.reflectionremapper.proxy.annotation.FieldSetter;
import xyz.jpenilla.reflectionremapper.proxy.annotation.Proxies;
public class Reflection {
public static final MappedRegistryProxy MAPPED_REGISTRY;
public static final BiomeProxy BIOME;
static {
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
ReflectionProxyFactory reflectionProxyFactory = ReflectionProxyFactory.create(reflectionRemapper,
Reflection.class.getClassLoader());
MAPPED_REGISTRY = reflectionProxyFactory.reflectionProxy(MappedRegistryProxy.class);
BIOME = reflectionProxyFactory.reflectionProxy(BiomeProxy.class);
}
@Proxies(MappedRegistry.class)
public interface MappedRegistryProxy {
@FieldSetter("frozen")
void setFrozen(MappedRegistry<?> instance, boolean frozen);
}
@Proxies(Biome.class)
public interface BiomeProxy {
@FieldGetter("biomeCategory")
Biome.BiomeCategory getBiomeCategory(Biome instance);
}
}

View File

@@ -1,30 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_18_R2;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_18_R2.CraftServer;
public class Registries {
private static <T> Registry<T> getRegistry(ResourceKey<Registry<T>> key) {
CraftServer craftserver = (CraftServer) Bukkit.getServer();
DedicatedServer dedicatedserver = craftserver.getServer();
return dedicatedserver
.registryAccess()
.registryOrThrow( // getRegistry
key
);
}
public static Registry<Biome> biomeRegistry() {
return getRegistry(Registry.BIOME_REGISTRY);
}
public static Registry<StructureSet> structureSet() {
return getRegistry(Registry.STRUCTURE_SET_REGISTRY);
}
}

View File

@@ -1,17 +0,0 @@
apply(plugin = "io.papermc.paperweight.userdev")
repositories {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
api(project(":platforms:bukkit:common"))
paperDevBundle("1.19-R0.1-SNAPSHOT")
implementation("xyz.jpenilla", "reflection-remapper", "0.1.0-SNAPSHOT")
}
tasks {
assemble {
dependsOn("reobfJar")
}
}

View File

@@ -1,116 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.Holder;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.data.BuiltinRegistries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.biome.Biome;
import org.bukkit.NamespacedKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
import com.dfsek.terra.registry.master.ConfigRegistry;
public class AwfulBukkitHacks {
private static final Logger LOGGER = LoggerFactory.getLogger(AwfulBukkitHacks.class);
private static final Map<ResourceLocation, List<ResourceLocation>> terraBiomeMap = new HashMap<>();
public static void registerBiomes(ConfigRegistry configRegistry) {
try {
LOGGER.info("Hacking biome registry...");
WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) Registries.biomeRegistry();
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, false);
configRegistry.forEach(pack -> pack.getRegistry(com.dfsek.terra.api.world.biome.Biome.class).forEach((key, biome) -> {
try {
BukkitPlatformBiome platformBiome = (BukkitPlatformBiome) biome.getPlatformBiome();
NamespacedKey vanillaBukkitKey = platformBiome.getHandle().getKey();
ResourceLocation vanillaMinecraftKey = new ResourceLocation(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey());
Biome platform = NMSBiomeInjector.createBiome(
biome,
Objects.requireNonNull(biomeRegistry.get(vanillaMinecraftKey)) // get
);
ResourceKey<Biome> delegateKey = ResourceKey.create(Registry.BIOME_REGISTRY,
new ResourceLocation("terra",
NMSBiomeInjector.createBiomeID(pack, key)));
BuiltinRegistries.register(BuiltinRegistries.BIOME, delegateKey, platform);
biomeRegistry.register(delegateKey, platform, Lifecycle.stable());
platformBiome.getContext().put(new NMSBiomeInfo(delegateKey));
terraBiomeMap.computeIfAbsent(vanillaMinecraftKey, i -> new ArrayList<>()).add(delegateKey.location());
LOGGER.debug("Registered biome: " + delegateKey);
} catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}));
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, true); // freeze registry again :)
LOGGER.info("Doing tag garbage....");
Map<TagKey<Biome>, List<Holder<Biome>>> collect = biomeRegistry
.getTags() // streamKeysAndEntries
.collect(HashMap::new,
(map, pair) ->
map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())),
HashMap::putAll);
terraBiomeMap
.forEach((vb, terraBiomes) ->
NMSBiomeInjector.getEntry(biomeRegistry, vb)
.ifPresentOrElse(
vanilla -> terraBiomes
.forEach(tb -> NMSBiomeInjector.getEntry(biomeRegistry, tb)
.ifPresentOrElse(
terra -> {
LOGGER.debug(
vanilla.unwrapKey()
.orElseThrow()
.location() +
" (vanilla for " +
terra.unwrapKey()
.orElseThrow()
.location() +
": " +
vanilla.tags()
.toList());
vanilla.tags()
.forEach(
tag -> collect
.computeIfAbsent(
tag,
t -> new ArrayList<>())
.add(terra));
},
() -> LOGGER.error(
"No such biome: {}",
tb))),
() -> LOGGER.error("No vanilla biome: {}", vb)));
biomeRegistry.resetTags();
biomeRegistry.bindTags(ImmutableMap.copyOf(collect));
} catch(SecurityException | IllegalArgumentException exception) {
throw new RuntimeException(exception);
}
}
}

View File

@@ -1,10 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
import com.dfsek.terra.api.properties.Properties;
public record NMSBiomeInfo(ResourceKey<Biome> biomeKey) implements Properties {
}

View File

@@ -1,42 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import com.mojang.serialization.Codec;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Climate.Sampler;
import org.jetbrains.annotations.NotNull;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
public class NMSBiomeProvider extends BiomeSource {
private final BiomeProvider delegate;
private final long seed;
private final Registry<Biome> biomeRegistry = Registries.biomeRegistry();
public NMSBiomeProvider(BiomeProvider delegate, long seed) {
super(delegate.stream()
.map(biome -> Registries.biomeRegistry()
.getHolderOrThrow(((BukkitPlatformBiome) biome.getPlatformBiome()).getContext()
.get(NMSBiomeInfo.class)
.biomeKey())));
this.delegate = delegate;
this.seed = seed;
}
@Override
protected @NotNull Codec<? extends BiomeSource> codec() {
return BiomeSource.CODEC;
}
@Override
public @NotNull Holder<Biome> getNoiseBiome(int x, int y, int z, @NotNull Sampler sampler) {
return biomeRegistry.getHolderOrThrow(((BukkitPlatformBiome) delegate.getBiome(x << 2, y << 2, z << 2, seed)
.getPlatformBiome()).getContext()
.get(NMSBiomeInfo.class)
.biomeKey());
}
}

View File

@@ -1,295 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import com.dfsek.terra.bukkit.config.PreLoadCompatibilityOptions;
import com.dfsek.terra.bukkit.world.BukkitWorldProperties;
import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.core.SectionPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.NoiseColumn;
import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.Beardifier;
import net.minecraft.world.level.levelgen.DensityFunction;
import net.minecraft.world.level.levelgen.DensityFunction.FunctionContext;
import net.minecraft.world.level.levelgen.DensityFunction.SinglePointContext;
import net.minecraft.world.level.levelgen.GenerationStep.Carving;
import net.minecraft.world.level.levelgen.Heightmap.Types;
import net.minecraft.world.level.levelgen.RandomState;
import net.minecraft.world.level.levelgen.blending.Blender;
import net.minecraft.world.level.levelgen.structure.Structure;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import net.minecraft.world.level.levelgen.structure.StructureSet.StructureSelectionEntry;
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
import org.bukkit.craftbukkit.v1_19_R1.block.data.CraftBlockData;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.stream.Stream;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.util.generic.Lazy;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.api.world.info.WorldProperties;
public class NMSChunkGeneratorDelegate extends ChunkGenerator {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSChunkGeneratorDelegate.class);
private final com.dfsek.terra.api.world.chunk.generation.ChunkGenerator delegate;
private final ChunkGenerator vanilla;
private final ConfigPack pack;
private final long seed;
private final Map<ConcentricRingsStructurePlacement, Lazy<List<ChunkPos>>> ringPositions = new Object2ObjectArrayMap<>();
private volatile boolean rings = false;
public NMSChunkGeneratorDelegate(ChunkGenerator vanilla, ConfigPack pack, NMSBiomeProvider biomeProvider, long seed) {
super(Registries.structureSet(), Optional.empty(), biomeProvider);
this.delegate = pack.getGeneratorProvider().newInstance(pack);
this.vanilla = vanilla;
this.pack = pack;
this.seed = seed;
}
@Override
protected @NotNull Codec<? extends ChunkGenerator> codec() {
return ChunkGenerator.CODEC;
}
@Override
public void applyCarvers(@NotNull WorldGenRegion chunkRegion, long seed, @NotNull RandomState noiseConfig, @NotNull BiomeManager world,
@NotNull StructureManager structureAccessor, @NotNull ChunkAccess chunk, @NotNull Carving carverStep) {
// no-op
}
@Override
public void buildSurface(@NotNull WorldGenRegion region, @NotNull StructureManager structures, @NotNull RandomState noiseConfig,
@NotNull ChunkAccess chunk) {
// no-op
}
@Override
public void applyBiomeDecoration(@NotNull WorldGenLevel world, @NotNull ChunkAccess chunk,
@NotNull StructureManager structureAccessor) {
vanilla.applyBiomeDecoration(world, chunk, structureAccessor);
}
@Override
public void spawnOriginalMobs(@NotNull WorldGenRegion region) {
vanilla.spawnOriginalMobs(region);
}
@Override
public int getGenDepth() {
return vanilla.getGenDepth();
}
@Override
public @NotNull CompletableFuture<ChunkAccess> fillFromNoise(@NotNull Executor executor, @NotNull Blender blender,
@NotNull RandomState noiseConfig,
@NotNull StructureManager structureAccessor, @NotNull ChunkAccess chunk) {
return vanilla.fillFromNoise(executor, blender, noiseConfig, structureAccessor, chunk)
.thenApply(c -> {
LevelAccessor level = Reflection.STRUCTURE_MANAGER.getLevel(structureAccessor);
BiomeProvider biomeProvider = pack.getBiomeProvider();
PreLoadCompatibilityOptions compatibilityOptions = pack.getContext().get(PreLoadCompatibilityOptions.class);
if(compatibilityOptions.isBeard()) {
beard(structureAccessor, chunk, new BukkitWorldProperties(level.getMinecraftWorld().getWorld()), biomeProvider, compatibilityOptions);
}
return c;
});
}
private void beard(StructureManager structureAccessor, ChunkAccess chunk, WorldProperties world, BiomeProvider biomeProvider,
PreLoadCompatibilityOptions compatibilityOptions) {
Beardifier structureWeightSampler = Beardifier.forStructuresInChunk(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.compute(new SinglePointContext(x + xi, y, z + zi));
if(noise > threshold) {
chunk.setBlockState(new BlockPos(x, y, z), ((CraftBlockData) ((BukkitBlockState) delegate
.getPalette(x + xi, y, z + zi, world, biomeProvider)
.get(depth, x + xi, y, z + zi, world.getSeed())).getHandle()).getState(), false);
depth++;
} else if(noise < airThreshold) {
chunk.setBlockState(new BlockPos(x, y, z), Blocks.AIR.defaultBlockState(), false);
} else {
depth = 0;
}
}
}
}
}
@Override
public int getSeaLevel() {
return vanilla.getSeaLevel();
}
@Override
public int getMinY() {
return vanilla.getMinY();
}
@Override
public int getBaseHeight(int x, int z, @NotNull Types heightmap, @NotNull LevelHeightAccessor world, @NotNull RandomState noiseConfig) {
WorldProperties properties = new NMSWorldProperties(seed, world);
int y = properties.getMaxHeight();
BiomeProvider biomeProvider = pack.getBiomeProvider();
while(y >= getMinY() && !heightmap.isOpaque().test(
((CraftBlockData) delegate.getBlock(properties, x, y - 1, z, biomeProvider).getHandle()).getState())) {
y--;
}
return y;
}
@Override
public @NotNull NoiseColumn getBaseColumn(int x, int z, @NotNull LevelHeightAccessor world, @NotNull RandomState noiseConfig) {
/*
BlockState[] array = new BlockState[world.getHeight()];
WorldProperties properties = new NMSWorldProperties(seed, world);
BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties);
for(int y = properties.getMaxHeight() - 1; y >= properties.getMinHeight(); y--) {
array[y - properties.getMinHeight()] = ((CraftBlockData) delegate.getBlock(properties, x, y, z, biomeProvider)
.getHandle()).getState();
}
return new NoiseColumn(getMinY(), array);
*/
return vanilla.getBaseColumn(x, z, world, noiseConfig);
}
@Override
public void addDebugScreenInfo(@NotNull List<String> text, @NotNull RandomState noiseConfig, @NotNull BlockPos pos) {
}
@Override
public void ensureStructuresGenerated(@NotNull RandomState noiseConfig) {
if(!this.rings) {
super.ensureStructuresGenerated(noiseConfig);
this.populateStrongholdData(noiseConfig);
this.rings = true;
}
}
@Override
public List<ChunkPos> getRingPositionsFor(@NotNull ConcentricRingsStructurePlacement structurePlacement,
@NotNull RandomState noiseConfig) {
ensureStructuresGenerated(noiseConfig);
return ringPositions.get(structurePlacement).value();
}
private void populateStrongholdData(RandomState noiseConfig) {
LOGGER.info("Generating safe stronghold data. This may take up to a minute.");
Set<Holder<Biome>> set = this.biomeSource.possibleBiomes();
possibleStructureSets().map(Holder::value).forEach((holder) -> {
boolean match = false;
for(StructureSelectionEntry structureset_a : holder.structures()) {
Structure structure = structureset_a.structure().value();
Stream<Holder<Biome>> stream = structure.biomes().stream();
if(stream.anyMatch(set::contains)) {
match = true;
}
}
if(match) {
if(holder.placement() instanceof ConcentricRingsStructurePlacement concentricringsstructureplacement) {
this.ringPositions.put(concentricringsstructureplacement, Lazy.lazy(
() -> this.generateRingPositions(holder, noiseConfig, concentricringsstructureplacement)));
}
}
});
}
private List<ChunkPos> generateRingPositions(StructureSet holder, RandomState randomstate,
ConcentricRingsStructurePlacement concentricringsstructureplacement) { // Spigot
if(concentricringsstructureplacement.count() == 0) {
return List.of();
}
List<ChunkPos> list = new ArrayList<>();
int i = concentricringsstructureplacement.distance();
int j = concentricringsstructureplacement.count();
int k = concentricringsstructureplacement.spread();
HolderSet<Biome> holderset = concentricringsstructureplacement.preferredBiomes();
RandomSource randomsource = RandomSource.create();
if(this.conf.strongholdSeed != null && this.structureSets.getResourceKey(holder).orElse(null) ==
net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS) {
randomsource.setSeed(this.conf.strongholdSeed);
} else {
randomsource.setSeed(randomstate.legacyLevelSeed());
}
double d0 = randomsource.nextDouble() * 3.141592653589793D * 2.0D;
int l = 0;
int i1 = 0;
for(int j1 = 0; j1 < j; ++j1) {
double d1 = (double) (4 * i + i * i1 * 6) + (randomsource.nextDouble() - 0.5D) * (double) i * 2.5D;
int k1 = (int) Math.round(Math.cos(d0) * d1);
int l1 = (int) Math.round(Math.sin(d0) * d1);
int i2 = SectionPos.sectionToBlockCoord(k1, 8);
int j2 = SectionPos.sectionToBlockCoord(l1, 8);
Objects.requireNonNull(holderset);
Pair<BlockPos, Holder<Biome>> pair = this.biomeSource.findBiomeHorizontal(i2, 0, j2, 112, holderset::contains, randomsource,
randomstate.sampler());
if(pair != null) {
BlockPos blockposition = pair.getFirst();
k1 = SectionPos.blockToSectionCoord(blockposition.getX());
l1 = SectionPos.blockToSectionCoord(blockposition.getZ());
}
list.add(new ChunkPos(k1, l1));
d0 += 6.283185307179586D / (double) k;
++l;
if(l == k) {
++i1;
l = 0;
k += 2 * k / (i1 + 1);
k = Math.min(k, j - j1);
d0 += randomsource.nextDouble() * 3.141592653589793D * 2.0D;
}
}
return list;
}
}

View File

@@ -1,51 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkGenerator;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.bukkit.generator.BukkitChunkGeneratorWrapper;
public class NMSInjectListener implements Listener {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSInjectListener.class);
private static final Set<World> INJECTED = new HashSet<>();
private static final ReentrantLock INJECT_LOCK = new ReentrantLock();
@EventHandler
public void onWorldInit(WorldInitEvent event) {
if(!INJECTED.contains(event.getWorld()) &&
event.getWorld().getGenerator() instanceof BukkitChunkGeneratorWrapper bukkitChunkGeneratorWrapper) {
INJECT_LOCK.lock();
INJECTED.add(event.getWorld());
LOGGER.info("Preparing to take over the world: {}", event.getWorld().getName());
CraftWorld craftWorld = (CraftWorld) event.getWorld();
ServerLevel serverWorld = craftWorld.getHandle();
ConfigPack pack = bukkitChunkGeneratorWrapper.getPack();
ChunkGenerator vanilla = serverWorld.getChunkSource().getGenerator();
NMSBiomeProvider provider = new NMSBiomeProvider(pack.getBiomeProvider(), craftWorld.getSeed());
NMSChunkGeneratorDelegate custom = new NMSChunkGeneratorDelegate(vanilla, pack, provider, craftWorld.getSeed());
custom.conf = vanilla.conf; // world config from Spigot
serverWorld.getChunkSource().chunkMap.generator = custom;
LOGGER.info("Successfully injected into world.");
INJECT_LOCK.unlock();
}
}
}

View File

@@ -1,38 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import net.minecraft.core.MappedRegistry;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.StructureManager;
import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
import xyz.jpenilla.reflectionremapper.proxy.ReflectionProxyFactory;
import xyz.jpenilla.reflectionremapper.proxy.annotation.FieldGetter;
import xyz.jpenilla.reflectionremapper.proxy.annotation.FieldSetter;
import xyz.jpenilla.reflectionremapper.proxy.annotation.Proxies;
public class Reflection {
public static final MappedRegistryProxy MAPPED_REGISTRY;
public static final StructureManagerProxy STRUCTURE_MANAGER;
static {
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
ReflectionProxyFactory reflectionProxyFactory = ReflectionProxyFactory.create(reflectionRemapper,
Reflection.class.getClassLoader());
MAPPED_REGISTRY = reflectionProxyFactory.reflectionProxy(MappedRegistryProxy.class);
STRUCTURE_MANAGER = reflectionProxyFactory.reflectionProxy(StructureManagerProxy.class);
}
@Proxies(MappedRegistry.class)
public interface MappedRegistryProxy {
@FieldSetter("frozen")
void setFrozen(MappedRegistry<?> instance, boolean frozen);
}
@Proxies(StructureManager.class)
public interface StructureManagerProxy {
@FieldGetter("level")
LevelAccessor getLevel(StructureManager instance);
}
}

View File

@@ -1,30 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_19_R1.CraftServer;
public class Registries {
private static <T> Registry<T> getRegistry(ResourceKey<Registry<T>> key) {
CraftServer craftserver = (CraftServer) Bukkit.getServer();
DedicatedServer dedicatedserver = craftserver.getServer();
return dedicatedserver
.registryAccess()
.registryOrThrow( // getRegistry
key
);
}
public static Registry<Biome> biomeRegistry() {
return getRegistry(Registry.BIOME_REGISTRY);
}
public static Registry<StructureSet> structureSet() {
return getRegistry(Registry.STRUCTURE_SET_REGISTRY);
}
}

View File

@@ -1,17 +0,0 @@
apply(plugin = "io.papermc.paperweight.userdev")
repositories {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
api(project(":platforms:bukkit:common"))
paperDevBundle("1.19.3-R0.1-SNAPSHOT")
implementation("xyz.jpenilla", "reflection-remapper", "0.1.0-SNAPSHOT")
}
tasks {
assemble {
dependsOn("reobfJar")
}
}

View File

@@ -1,100 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.Holder;
import net.minecraft.core.Holder.Reference;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.biome.Biome;
import org.bukkit.NamespacedKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
import com.dfsek.terra.registry.master.ConfigRegistry;
public class AwfulBukkitHacks {
private static final Logger LOGGER = LoggerFactory.getLogger(AwfulBukkitHacks.class);
private static final Map<ResourceLocation, List<ResourceLocation>> terraBiomeMap = new HashMap<>();
public static void registerBiomes(ConfigRegistry configRegistry) {
try {
LOGGER.info("Hacking biome registry...");
WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) RegistryFetcher.biomeRegistry();
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, false);
configRegistry.forEach(pack -> pack.getRegistry(com.dfsek.terra.api.world.biome.Biome.class).forEach((key, biome) -> {
try {
BukkitPlatformBiome platformBiome = (BukkitPlatformBiome) biome.getPlatformBiome();
NamespacedKey vanillaBukkitKey = platformBiome.getHandle().getKey();
ResourceLocation vanillaMinecraftKey = new ResourceLocation(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey());
Biome platform = NMSBiomeInjector.createBiome(biome, Objects.requireNonNull(biomeRegistry.get(vanillaMinecraftKey)));
ResourceKey<Biome> delegateKey = ResourceKey.create(
Registries.BIOME,
new ResourceLocation("terra", NMSBiomeInjector.createBiomeID(pack, key))
);
Reference<Biome> holder = biomeRegistry.register(delegateKey, platform, Lifecycle.stable());
Reflection.REFERENCE.invokeBindValue(holder, platform); // IMPORTANT: bind holder.
platformBiome.getContext().put(new NMSBiomeInfo(delegateKey));
terraBiomeMap.computeIfAbsent(vanillaMinecraftKey, i -> new ArrayList<>()).add(delegateKey.location());
LOGGER.debug("Registered biome: " + delegateKey);
} catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}));
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, true); // freeze registry again :)
LOGGER.info("Doing tag garbage....");
Map<TagKey<Biome>, List<Holder<Biome>>> collect = biomeRegistry
.getTags() // streamKeysAndEntries
.collect(HashMap::new,
(map, pair) ->
map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())),
HashMap::putAll);
terraBiomeMap
.forEach((vb, terraBiomes) ->
NMSBiomeInjector.getEntry(biomeRegistry, vb).ifPresentOrElse(
vanilla -> terraBiomes.forEach(
tb -> NMSBiomeInjector.getEntry(biomeRegistry, tb).ifPresentOrElse(
terra -> {
LOGGER.debug("{} (vanilla for {}): {}",
vanilla.unwrapKey().orElseThrow().location(),
terra.unwrapKey().orElseThrow().location(),
vanilla.tags().toList());
vanilla.tags()
.forEach(tag -> collect
.computeIfAbsent(tag, t -> new ArrayList<>())
.add(terra));
},
() -> LOGGER.error("No such biome: {}", tb))),
() -> LOGGER.error("No vanilla biome: {}", vb)));
biomeRegistry.resetTags();
biomeRegistry.bindTags(ImmutableMap.copyOf(collect));
} catch(SecurityException | IllegalArgumentException exception) {
throw new RuntimeException(exception);
}
}
}

View File

@@ -1,81 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSpecialEffects;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.bukkit.config.VanillaBiomeProperties;
public class NMSBiomeInjector {
public static <T> Optional<Holder<T>> getEntry(Registry<T> registry, ResourceLocation identifier) {
return registry.getOptional(identifier)
.flatMap(registry::getResourceKey)
.flatMap(registry::getHolder);
}
public static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Biome.BiomeBuilder builder = new Biome.BiomeBuilder();
builder
.precipitation(vanilla.getPrecipitation())
.downfall(vanilla.getDownfall())
.temperature(vanilla.getBaseTemperature())
.mobSpawnSettings(vanilla.getMobSettings())
.generationSettings(vanilla.getGenerationSettings());
BiomeSpecialEffects.Builder effects = new BiomeSpecialEffects.Builder();
effects.grassColorModifier(vanilla.getSpecialEffects().getGrassColorModifier());
VanillaBiomeProperties vanillaBiomeProperties = biome.getContext().get(VanillaBiomeProperties.class);
effects.fogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getFogColor(), vanilla.getFogColor()))
.waterColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterColor(), vanilla.getWaterColor()))
.waterFogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterFogColor(), vanilla.getWaterFogColor()))
.skyColor(Objects.requireNonNullElse(vanillaBiomeProperties.getSkyColor(), vanilla.getSkyColor()));
if(vanillaBiomeProperties.getFoliageColor() == null) {
vanilla.getSpecialEffects().getFoliageColorOverride().ifPresent(effects::foliageColorOverride);
} else {
effects.foliageColorOverride(vanillaBiomeProperties.getFoliageColor());
}
if(vanillaBiomeProperties.getGrassColor() == null) {
vanilla.getSpecialEffects().getGrassColorOverride().ifPresent(effects::grassColorOverride);
} else {
// grass
effects.grassColorOverride(vanillaBiomeProperties.getGrassColor());
}
vanilla.getAmbientLoop().ifPresent(effects::ambientLoopSound);
vanilla.getAmbientAdditions().ifPresent(effects::ambientAdditionsSound);
vanilla.getAmbientMood().ifPresent(effects::ambientMoodSound);
vanilla.getBackgroundMusic().ifPresent(effects::backgroundMusic);
vanilla.getAmbientParticle().ifPresent(effects::ambientParticle);
builder.specialEffects(effects.build());
return builder.build();
}
public static String createBiomeID(ConfigPack pack, com.dfsek.terra.api.registry.key.RegistryKey biomeID) {
return pack.getID()
.toLowerCase() + "/" + biomeID.getNamespace().toLowerCase(Locale.ROOT) + "/" + biomeID.getID().toLowerCase(Locale.ROOT);
}
}

View File

@@ -1,42 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
import com.mojang.serialization.Codec;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Climate.Sampler;
import org.jetbrains.annotations.NotNull;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
public class NMSBiomeProvider extends BiomeSource {
private final BiomeProvider delegate;
private final long seed;
private final Registry<Biome> biomeRegistry = RegistryFetcher.biomeRegistry();
public NMSBiomeProvider(BiomeProvider delegate, long seed) {
super(delegate.stream()
.map(biome -> RegistryFetcher.biomeRegistry()
.getHolderOrThrow(((BukkitPlatformBiome) biome.getPlatformBiome()).getContext()
.get(NMSBiomeInfo.class)
.biomeKey())));
this.delegate = delegate;
this.seed = seed;
}
@Override
protected @NotNull Codec<? extends BiomeSource> codec() {
return BiomeSource.CODEC;
}
@Override
public @NotNull Holder<Biome> getNoiseBiome(int x, int y, int z, @NotNull Sampler sampler) {
return biomeRegistry.getHolderOrThrow(((BukkitPlatformBiome) delegate.getBiome(x << 2, y << 2, z << 2, seed)
.getPlatformBiome()).getContext()
.get(NMSBiomeInfo.class)
.biomeKey());
}
}

View File

@@ -1,173 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.NoiseColumn;
import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.Beardifier;
import net.minecraft.world.level.levelgen.DensityFunction.SinglePointContext;
import net.minecraft.world.level.levelgen.GenerationStep.Carving;
import net.minecraft.world.level.levelgen.Heightmap.Types;
import net.minecraft.world.level.levelgen.RandomState;
import net.minecraft.world.level.levelgen.blending.Blender;
import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
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.info.WorldProperties;
import com.dfsek.terra.bukkit.config.PreLoadCompatibilityOptions;
import com.dfsek.terra.bukkit.world.BukkitWorldProperties;
import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState;
public class NMSChunkGeneratorDelegate extends ChunkGenerator {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSChunkGeneratorDelegate.class);
private final com.dfsek.terra.api.world.chunk.generation.ChunkGenerator delegate;
private final ChunkGenerator vanilla;
private final ConfigPack pack;
private final long seed;
public NMSChunkGeneratorDelegate(ChunkGenerator vanilla, ConfigPack pack, NMSBiomeProvider biomeProvider, long seed) {
super(biomeProvider);
this.delegate = pack.getGeneratorProvider().newInstance(pack);
this.vanilla = vanilla;
this.pack = pack;
this.seed = seed;
}
@Override
protected @NotNull Codec<? extends ChunkGenerator> codec() {
return ChunkGenerator.CODEC;
}
@Override
public void applyCarvers(@NotNull WorldGenRegion chunkRegion, long seed, @NotNull RandomState noiseConfig, @NotNull BiomeManager world,
@NotNull StructureManager structureAccessor, @NotNull ChunkAccess chunk, @NotNull Carving carverStep) {
// no-op
}
@Override
public void buildSurface(@NotNull WorldGenRegion region, @NotNull StructureManager structures, @NotNull RandomState noiseConfig,
@NotNull ChunkAccess chunk) {
// no-op
}
@Override
public void applyBiomeDecoration(@NotNull WorldGenLevel world, @NotNull ChunkAccess chunk,
@NotNull StructureManager structureAccessor) {
vanilla.applyBiomeDecoration(world, chunk, structureAccessor);
}
@Override
public void spawnOriginalMobs(@NotNull WorldGenRegion region) {
vanilla.spawnOriginalMobs(region);
}
@Override
public int getGenDepth() {
return vanilla.getGenDepth();
}
@Override
public @NotNull CompletableFuture<ChunkAccess> fillFromNoise(@NotNull Executor executor, @NotNull Blender blender,
@NotNull RandomState noiseConfig,
@NotNull StructureManager structureAccessor, @NotNull ChunkAccess chunk) {
return vanilla.fillFromNoise(executor, blender, noiseConfig, structureAccessor, chunk)
.thenApply(c -> {
LevelAccessor level = Reflection.STRUCTURE_MANAGER.getLevel(structureAccessor);
BiomeProvider biomeProvider = pack.getBiomeProvider();
PreLoadCompatibilityOptions compatibilityOptions = pack.getContext().get(PreLoadCompatibilityOptions.class);
if(compatibilityOptions.isBeard()) {
beard(structureAccessor, chunk, new BukkitWorldProperties(level.getMinecraftWorld().getWorld()), biomeProvider, compatibilityOptions);
}
return c;
});
}
private void beard(StructureManager structureAccessor, ChunkAccess chunk, WorldProperties world, BiomeProvider biomeProvider,
PreLoadCompatibilityOptions compatibilityOptions) {
Beardifier structureWeightSampler = Beardifier.forStructuresInChunk(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.compute(new SinglePointContext(x + xi, y, z + zi));
if(noise > threshold) {
chunk.setBlockState(new BlockPos(x, y, z), ((CraftBlockData) ((BukkitBlockState) delegate
.getPalette(x + xi, y, z + zi, world, biomeProvider)
.get(depth, x + xi, y, z + zi, world.getSeed())).getHandle()).getState(), false);
depth++;
} else if(noise < airThreshold) {
chunk.setBlockState(new BlockPos(x, y, z), Blocks.AIR.defaultBlockState(), false);
} else {
depth = 0;
}
}
}
}
}
@Override
public int getSeaLevel() {
return vanilla.getSeaLevel();
}
@Override
public int getMinY() {
return vanilla.getMinY();
}
@Override
public int getBaseHeight(int x, int z, @NotNull Types heightmap, @NotNull LevelHeightAccessor world, @NotNull RandomState noiseConfig) {
WorldProperties properties = new NMSWorldProperties(seed, world);
int y = properties.getMaxHeight();
BiomeProvider biomeProvider = pack.getBiomeProvider();
while(y >= getMinY() && !heightmap.isOpaque().test(
((CraftBlockData) delegate.getBlock(properties, x, y - 1, z, biomeProvider).getHandle()).getState())) {
y--;
}
return y;
}
@Override
public @NotNull NoiseColumn getBaseColumn(int x, int z, @NotNull LevelHeightAccessor world, @NotNull RandomState noiseConfig) {
/*
BlockState[] array = new BlockState[world.getHeight()];
WorldProperties properties = new NMSWorldProperties(seed, world);
BiomeProvider biomeProvider = pack.getBiomeProvider().caching(properties);
for(int y = properties.getMaxHeight() - 1; y >= properties.getMinHeight(); y--) {
array[y - properties.getMinHeight()] = ((CraftBlockData) delegate.getBlock(properties, x, y, z, biomeProvider)
.getHandle()).getState();
}
return new NoiseColumn(getMinY(), array);
*/
return vanilla.getBaseColumn(x, z, world, noiseConfig);
}
@Override
public void addDebugScreenInfo(@NotNull List<String> text, @NotNull RandomState noiseConfig, @NotNull BlockPos pos) {
}
}

View File

@@ -1,15 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
import org.bukkit.Bukkit;
import com.dfsek.terra.bukkit.PlatformImpl;
import com.dfsek.terra.bukkit.nms.Initializer;
public class NMSInitializer implements Initializer {
@Override
public void initialize(PlatformImpl platform) {
AwfulBukkitHacks.registerBiomes(platform.getRawConfigRegistry());
Bukkit.getPluginManager().registerEvents(new NMSInjectListener(), platform.getPlugin());
}
}

View File

@@ -1,36 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
import net.minecraft.world.level.LevelHeightAccessor;
import com.dfsek.terra.api.world.info.WorldProperties;
public class NMSWorldProperties implements WorldProperties {
private final long seed;
private final LevelHeightAccessor height;
public NMSWorldProperties(long seed, LevelHeightAccessor height) {
this.seed = seed;
this.height = height;
}
@Override
public Object getHandle() {
return height;
}
@Override
public long getSeed() {
return seed;
}
@Override
public int getMaxHeight() {
return height.getMaxBuildHeight();
}
@Override
public int getMinHeight() {
return height.getMinBuildHeight();
}
}

View File

@@ -1,52 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
import net.minecraft.core.Holder;
import net.minecraft.core.Holder.Reference;
import net.minecraft.core.MappedRegistry;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.StructureManager;
import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
import xyz.jpenilla.reflectionremapper.proxy.ReflectionProxyFactory;
import xyz.jpenilla.reflectionremapper.proxy.annotation.FieldGetter;
import xyz.jpenilla.reflectionremapper.proxy.annotation.FieldSetter;
import xyz.jpenilla.reflectionremapper.proxy.annotation.MethodName;
import xyz.jpenilla.reflectionremapper.proxy.annotation.Proxies;
import java.util.Objects;
public class Reflection {
public static final MappedRegistryProxy MAPPED_REGISTRY;
public static final StructureManagerProxy STRUCTURE_MANAGER;
public static final ReferenceProxy REFERENCE;
static {
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
ReflectionProxyFactory reflectionProxyFactory = ReflectionProxyFactory.create(reflectionRemapper,
Reflection.class.getClassLoader());
MAPPED_REGISTRY = reflectionProxyFactory.reflectionProxy(MappedRegistryProxy.class);
STRUCTURE_MANAGER = reflectionProxyFactory.reflectionProxy(StructureManagerProxy.class);
REFERENCE = reflectionProxyFactory.reflectionProxy(ReferenceProxy.class);
}
@Proxies(MappedRegistry.class)
public interface MappedRegistryProxy {
@FieldSetter("frozen")
void setFrozen(MappedRegistry<?> instance, boolean frozen);
}
@Proxies(StructureManager.class)
public interface StructureManagerProxy {
@FieldGetter("level")
LevelAccessor getLevel(StructureManager instance);
}
@Proxies(Holder.Reference.class)
public interface ReferenceProxy {
@MethodName("bindValue")
<T> void invokeBindValue(Reference<T> instance, T value);
}
}

View File

@@ -1,25 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_19_R2.CraftServer;
public class RegistryFetcher {
private static <T> Registry<T> getRegistry(ResourceKey<Registry<T>> key) {
CraftServer craftserver = (CraftServer) Bukkit.getServer();
DedicatedServer dedicatedserver = craftserver.getServer();
return dedicatedserver
.registryAccess()
.registryOrThrow(key);
}
public static Registry<Biome> biomeRegistry() {
return getRegistry(Registries.BIOME);
}
}

View File

@@ -1,17 +0,0 @@
apply(plugin = "io.papermc.paperweight.userdev")
repositories {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
api(project(":platforms:bukkit:common"))
paperDevBundle("1.19.4-R0.1-SNAPSHOT")
implementation("xyz.jpenilla", "reflection-remapper", "0.1.0-SNAPSHOT")
}
tasks {
assemble {
dependsOn("reobfJar")
}
}

View File

@@ -1,101 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.Holder;
import net.minecraft.core.Holder.Reference;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.level.biome.Biome;
import org.bukkit.NamespacedKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
import com.dfsek.terra.registry.master.ConfigRegistry;
public class AwfulBukkitHacks {
private static final Logger LOGGER = LoggerFactory.getLogger(AwfulBukkitHacks.class);
private static final Map<ResourceLocation, List<ResourceLocation>> terraBiomeMap = new HashMap<>();
public static void registerBiomes(ConfigRegistry configRegistry) {
try {
LOGGER.info("Hacking biome registry...");
WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) RegistryFetcher.biomeRegistry();
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, false);
configRegistry.forEach(pack -> pack.getRegistry(com.dfsek.terra.api.world.biome.Biome.class).forEach((key, biome) -> {
try {
BukkitPlatformBiome platformBiome = (BukkitPlatformBiome) biome.getPlatformBiome();
NamespacedKey vanillaBukkitKey = platformBiome.getHandle().getKey();
ResourceLocation vanillaMinecraftKey = new ResourceLocation(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey());
Biome platform = NMSBiomeInjector.createBiome(biome, Objects.requireNonNull(biomeRegistry.get(vanillaMinecraftKey)));
ResourceKey<Biome> delegateKey = ResourceKey.create(
Registries.BIOME,
new ResourceLocation("terra", NMSBiomeInjector.createBiomeID(pack, key))
);
Reference<Biome> holder = biomeRegistry.register(delegateKey, platform, Lifecycle.stable());
Reflection.REFERENCE.invokeBindValue(holder, platform); // IMPORTANT: bind holder.
platformBiome.getContext().put(new NMSBiomeInfo(delegateKey));
terraBiomeMap.computeIfAbsent(vanillaMinecraftKey, i -> new ArrayList<>()).add(delegateKey.location());
LOGGER.debug("Registered biome: " + delegateKey);
} catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}));
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, true); // freeze registry again :)
LOGGER.info("Doing tag garbage....");
Map<TagKey<Biome>, List<Holder<Biome>>> collect = biomeRegistry
.getTags() // streamKeysAndEntries
.collect(HashMap::new,
(map, pair) ->
map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())),
HashMap::putAll);
terraBiomeMap
.forEach((vb, terraBiomes) ->
NMSBiomeInjector.getEntry(biomeRegistry, vb).ifPresentOrElse(
vanilla -> terraBiomes.forEach(
tb -> NMSBiomeInjector.getEntry(biomeRegistry, tb).ifPresentOrElse(
terra -> {
LOGGER.debug("{} (vanilla for {}): {}",
vanilla.unwrapKey().orElseThrow().location(),
terra.unwrapKey().orElseThrow().location(),
vanilla.tags().toList());
vanilla.tags()
.forEach(tag -> collect
.computeIfAbsent(tag, t -> new ArrayList<>())
.add(terra));
},
() -> LOGGER.error("No such biome: {}", tb))),
() -> LOGGER.error("No vanilla biome: {}", vb)));
biomeRegistry.resetTags();
biomeRegistry.bindTags(ImmutableMap.copyOf(collect));
} catch(SecurityException | IllegalArgumentException exception) {
throw new RuntimeException(exception);
}
}
}

View File

@@ -1,10 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
import com.dfsek.terra.api.properties.Properties;
public record NMSBiomeInfo(ResourceKey<Biome> biomeKey) implements Properties {
}

View File

@@ -1,83 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
import net.minecraft.core.Holder;
import java.util.stream.Stream;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSpecialEffects;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.bukkit.config.VanillaBiomeProperties;
import static net.minecraft.world.level.biome.Biome.ClimateSettings;
import static net.minecraft.world.level.biome.Biome.Precipitation;
public class NMSBiomeInjector {
public static <T> Optional<Holder<T>> getEntry(Registry<T> registry, ResourceLocation identifier) {
return registry.getOptional(identifier)
.flatMap(registry::getResourceKey)
.flatMap(registry::getHolder);
}
public static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Biome.BiomeBuilder builder = new Biome.BiomeBuilder();
builder
.downfall(vanilla.climateSettings.downfall())
.temperature(vanilla.getBaseTemperature())
.mobSpawnSettings(vanilla.getMobSettings())
.generationSettings(vanilla.getGenerationSettings());
BiomeSpecialEffects.Builder effects = new BiomeSpecialEffects.Builder();
effects.grassColorModifier(vanilla.getSpecialEffects().getGrassColorModifier());
VanillaBiomeProperties vanillaBiomeProperties = biome.getContext().get(VanillaBiomeProperties.class);
effects.fogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getFogColor(), vanilla.getFogColor()))
.waterColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterColor(), vanilla.getWaterColor()))
.waterFogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterFogColor(), vanilla.getWaterFogColor()))
.skyColor(Objects.requireNonNullElse(vanillaBiomeProperties.getSkyColor(), vanilla.getSkyColor()));
if(vanillaBiomeProperties.getFoliageColor() == null) {
vanilla.getSpecialEffects().getFoliageColorOverride().ifPresent(effects::foliageColorOverride);
} else {
effects.foliageColorOverride(vanillaBiomeProperties.getFoliageColor());
}
if(vanillaBiomeProperties.getGrassColor() == null) {
vanilla.getSpecialEffects().getGrassColorOverride().ifPresent(effects::grassColorOverride);
} else {
// grass
effects.grassColorOverride(vanillaBiomeProperties.getGrassColor());
}
vanilla.getAmbientLoop().ifPresent(effects::ambientLoopSound);
vanilla.getAmbientAdditions().ifPresent(effects::ambientAdditionsSound);
vanilla.getAmbientMood().ifPresent(effects::ambientMoodSound);
vanilla.getBackgroundMusic().ifPresent(effects::backgroundMusic);
vanilla.getAmbientParticle().ifPresent(effects::ambientParticle);
builder.specialEffects(effects.build());
return builder.build();
}
public static String createBiomeID(ConfigPack pack, com.dfsek.terra.api.registry.key.RegistryKey biomeID) {
return pack.getID()
.toLowerCase() + "/" + biomeID.getNamespace().toLowerCase(Locale.ROOT) + "/" + biomeID.getID().toLowerCase(Locale.ROOT);
}
}

View File

@@ -1,47 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
import com.mojang.serialization.Codec;
import net.minecraft.core.Holder;
import java.util.stream.Stream;
import net.minecraft.core.Registry;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Climate.Sampler;
import org.jetbrains.annotations.NotNull;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
public class NMSBiomeProvider extends BiomeSource {
private final BiomeProvider delegate;
private final long seed;
private final Registry<Biome> biomeRegistry = RegistryFetcher.biomeRegistry();
public NMSBiomeProvider(BiomeProvider delegate, long seed) {
super();
this.delegate = delegate;
this.seed = seed;
}
@Override
protected Stream<Holder<Biome>> collectPossibleBiomes() {
return delegate.stream()
.map(biome -> RegistryFetcher.biomeRegistry()
.getHolderOrThrow(((BukkitPlatformBiome) biome.getPlatformBiome()).getContext()
.get(NMSBiomeInfo.class)
.biomeKey()));
}
@Override
protected @NotNull Codec<? extends BiomeSource> codec() {
return BiomeSource.CODEC;
}
@Override
public @NotNull Holder<Biome> getNoiseBiome(int x, int y, int z, @NotNull Sampler sampler) {
return biomeRegistry.getHolderOrThrow(((BukkitPlatformBiome) delegate.getBiome(x << 2, y << 2, z << 2, seed)
.getPlatformBiome()).getContext()
.get(NMSBiomeInfo.class)
.biomeKey());
}
}

View File

@@ -1,170 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
import com.mojang.serialization.Codec;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.NoiseColumn;
import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.Beardifier;
import net.minecraft.world.level.levelgen.DensityFunction.SinglePointContext;
import net.minecraft.world.level.levelgen.GenerationStep.Carving;
import net.minecraft.world.level.levelgen.Heightmap.Types;
import net.minecraft.world.level.levelgen.RandomState;
import net.minecraft.world.level.levelgen.blending.Blender;
import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
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.info.WorldProperties;
import com.dfsek.terra.bukkit.config.PreLoadCompatibilityOptions;
import com.dfsek.terra.bukkit.world.BukkitWorldProperties;
import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState;
public class NMSChunkGeneratorDelegate extends ChunkGenerator {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSChunkGeneratorDelegate.class);
private final com.dfsek.terra.api.world.chunk.generation.ChunkGenerator delegate;
private final ChunkGenerator vanilla;
private final ConfigPack pack;
private final long seed;
public NMSChunkGeneratorDelegate(ChunkGenerator vanilla, ConfigPack pack, NMSBiomeProvider biomeProvider, long seed) {
super(biomeProvider);
this.delegate = pack.getGeneratorProvider().newInstance(pack);
this.vanilla = vanilla;
this.pack = pack;
this.seed = seed;
}
@Override
protected @NotNull Codec<? extends ChunkGenerator> codec() {
return ChunkGenerator.CODEC;
}
@Override
public void applyCarvers(@NotNull WorldGenRegion chunkRegion, long seed, @NotNull RandomState noiseConfig, @NotNull BiomeManager world,
@NotNull StructureManager structureAccessor, @NotNull ChunkAccess chunk, @NotNull Carving carverStep) {
// no-op
}
@Override
public void buildSurface(@NotNull WorldGenRegion region, @NotNull StructureManager structures, @NotNull RandomState noiseConfig,
@NotNull ChunkAccess chunk) {
// no-op
}
@Override
public void applyBiomeDecoration(@NotNull WorldGenLevel world, @NotNull ChunkAccess chunk,
@NotNull StructureManager structureAccessor) {
vanilla.applyBiomeDecoration(world, chunk, structureAccessor);
}
@Override
public void spawnOriginalMobs(@NotNull WorldGenRegion region) {
vanilla.spawnOriginalMobs(region);
}
@Override
public int getGenDepth() {
return vanilla.getGenDepth();
}
@Override
public @NotNull CompletableFuture<ChunkAccess> fillFromNoise(@NotNull Executor executor, @NotNull Blender blender,
@NotNull RandomState noiseConfig,
@NotNull StructureManager structureAccessor, @NotNull ChunkAccess chunk) {
return vanilla.fillFromNoise(executor, blender, noiseConfig, structureAccessor, chunk)
.thenApply(c -> {
LevelAccessor level = Reflection.STRUCTURE_MANAGER.getLevel(structureAccessor);
BiomeProvider biomeProvider = pack.getBiomeProvider();
PreLoadCompatibilityOptions compatibilityOptions = pack.getContext().get(PreLoadCompatibilityOptions.class);
if(compatibilityOptions.isBeard()) {
beard(structureAccessor, chunk, new BukkitWorldProperties(level.getMinecraftWorld().getWorld()), biomeProvider, compatibilityOptions);
}
return c;
});
}
private void beard(StructureManager structureAccessor, ChunkAccess chunk, WorldProperties world, BiomeProvider biomeProvider,
PreLoadCompatibilityOptions compatibilityOptions) {
Beardifier structureWeightSampler = Beardifier.forStructuresInChunk(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.compute(new SinglePointContext(x + xi, y, z + zi));
if(noise > threshold) {
chunk.setBlockState(new BlockPos(x, y, z), ((CraftBlockData) ((BukkitBlockState) delegate
.getPalette(x + xi, y, z + zi, world, biomeProvider)
.get(depth, x + xi, y, z + zi, world.getSeed())).getHandle()).getState(), false);
depth++;
} else if(noise < airThreshold) {
chunk.setBlockState(new BlockPos(x, y, z), Blocks.AIR.defaultBlockState(), false);
} else {
depth = 0;
}
}
}
}
}
@Override
public int getSeaLevel() {
return vanilla.getSeaLevel();
}
@Override
public int getMinY() {
return vanilla.getMinY();
}
@Override
public int getBaseHeight(int x, int z, @NotNull Types heightmap, @NotNull LevelHeightAccessor world, @NotNull RandomState noiseConfig) {
WorldProperties properties = new NMSWorldProperties(seed, world);
int y = properties.getMaxHeight();
BiomeProvider biomeProvider = pack.getBiomeProvider();
while(y >= getMinY() && !heightmap.isOpaque().test(
((CraftBlockData) delegate.getBlock(properties, x, y - 1, z, biomeProvider).getHandle()).getState())) {
y--;
}
return y;
}
@Override
public @NotNull NoiseColumn getBaseColumn(int x, int z, @NotNull LevelHeightAccessor world, @NotNull RandomState noiseConfig) {
BlockState[] array = new BlockState[world.getHeight()];
WorldProperties properties = new NMSWorldProperties(seed, world);
BiomeProvider biomeProvider = pack.getBiomeProvider();
for(int y = properties.getMaxHeight() - 1; y >= properties.getMinHeight(); y--) {
array[y - properties.getMinHeight()] = ((CraftBlockData) delegate.getBlock(properties, x, y, z, biomeProvider)
.getHandle()).getState();
}
return new NoiseColumn(getMinY(), array);
}
@Override
public void addDebugScreenInfo(@NotNull List<String> text, @NotNull RandomState noiseConfig, @NotNull BlockPos pos) {
}
}

View File

@@ -1,15 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
import org.bukkit.Bukkit;
import com.dfsek.terra.bukkit.PlatformImpl;
import com.dfsek.terra.bukkit.nms.Initializer;
public class NMSInitializer implements Initializer {
@Override
public void initialize(PlatformImpl platform) {
AwfulBukkitHacks.registerBiomes(platform.getRawConfigRegistry());
Bukkit.getPluginManager().registerEvents(new NMSInjectListener(), platform.getPlugin());
}
}

View File

@@ -1,48 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkGenerator;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_19_R3.CraftWorld;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.bukkit.generator.BukkitChunkGeneratorWrapper;
public class NMSInjectListener implements Listener {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSInjectListener.class);
private static final Set<World> INJECTED = new HashSet<>();
private static final ReentrantLock INJECT_LOCK = new ReentrantLock();
@EventHandler
public void onWorldInit(WorldInitEvent event) {
if(!INJECTED.contains(event.getWorld()) &&
event.getWorld().getGenerator() instanceof BukkitChunkGeneratorWrapper bukkitChunkGeneratorWrapper) {
INJECT_LOCK.lock();
INJECTED.add(event.getWorld());
LOGGER.info("Preparing to take over the world: {}", event.getWorld().getName());
CraftWorld craftWorld = (CraftWorld) event.getWorld();
ServerLevel serverWorld = craftWorld.getHandle();
ConfigPack pack = bukkitChunkGeneratorWrapper.getPack();
ChunkGenerator vanilla = serverWorld.getChunkSource().getGenerator();
NMSBiomeProvider provider = new NMSBiomeProvider(pack.getBiomeProvider(), craftWorld.getSeed());
serverWorld.getChunkSource().chunkMap.generator = new NMSChunkGeneratorDelegate(vanilla, pack, provider, craftWorld.getSeed());
LOGGER.info("Successfully injected into world.");
INJECT_LOCK.unlock();
}
}
}

View File

@@ -1,36 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
import net.minecraft.world.level.LevelHeightAccessor;
import com.dfsek.terra.api.world.info.WorldProperties;
public class NMSWorldProperties implements WorldProperties {
private final long seed;
private final LevelHeightAccessor height;
public NMSWorldProperties(long seed, LevelHeightAccessor height) {
this.seed = seed;
this.height = height;
}
@Override
public Object getHandle() {
return height;
}
@Override
public long getSeed() {
return seed;
}
@Override
public int getMaxHeight() {
return height.getMaxBuildHeight();
}
@Override
public int getMinHeight() {
return height.getMinBuildHeight();
}
}

View File

@@ -1,25 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.levelgen.structure.StructureSet;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_19_R3.CraftServer;
public class RegistryFetcher {
private static <T> Registry<T> getRegistry(ResourceKey<Registry<T>> key) {
CraftServer craftserver = (CraftServer) Bukkit.getServer();
DedicatedServer dedicatedserver = craftserver.getServer();
return dedicatedserver
.registryAccess()
.registryOrThrow(key);
}
public static Registry<Biome> biomeRegistry() {
return getRegistry(Registries.BIOME);
}
}

View File

@@ -1,10 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;
import com.dfsek.terra.api.properties.Properties;
public record NMSBiomeInfo(ResourceKey<Biome> biomeKey) implements Properties {
}

View File

@@ -1,83 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
import net.minecraft.core.Holder;
import java.util.stream.Stream;
import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSpecialEffects;
import java.util.Locale;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.bukkit.config.VanillaBiomeProperties;
import static net.minecraft.world.level.biome.Biome.ClimateSettings;
import static net.minecraft.world.level.biome.Biome.Precipitation;
public class NMSBiomeInjector {
public static <T> Optional<Holder<T>> getEntry(Registry<T> registry, ResourceLocation identifier) {
return registry.getOptional(identifier)
.flatMap(registry::getResourceKey)
.flatMap(registry::getHolder);
}
public static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Biome.BiomeBuilder builder = new Biome.BiomeBuilder();
builder
.downfall(vanilla.climateSettings.downfall())
.temperature(vanilla.getBaseTemperature())
.mobSpawnSettings(vanilla.getMobSettings())
.generationSettings(vanilla.getGenerationSettings());
BiomeSpecialEffects.Builder effects = new BiomeSpecialEffects.Builder();
effects.grassColorModifier(vanilla.getSpecialEffects().getGrassColorModifier());
VanillaBiomeProperties vanillaBiomeProperties = biome.getContext().get(VanillaBiomeProperties.class);
effects.fogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getFogColor(), vanilla.getFogColor()))
.waterColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterColor(), vanilla.getWaterColor()))
.waterFogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterFogColor(), vanilla.getWaterFogColor()))
.skyColor(Objects.requireNonNullElse(vanillaBiomeProperties.getSkyColor(), vanilla.getSkyColor()));
if(vanillaBiomeProperties.getFoliageColor() == null) {
vanilla.getSpecialEffects().getFoliageColorOverride().ifPresent(effects::foliageColorOverride);
} else {
effects.foliageColorOverride(vanillaBiomeProperties.getFoliageColor());
}
if(vanillaBiomeProperties.getGrassColor() == null) {
vanilla.getSpecialEffects().getGrassColorOverride().ifPresent(effects::grassColorOverride);
} else {
// grass
effects.grassColorOverride(vanillaBiomeProperties.getGrassColor());
}
vanilla.getAmbientLoop().ifPresent(effects::ambientLoopSound);
vanilla.getAmbientAdditions().ifPresent(effects::ambientAdditionsSound);
vanilla.getAmbientMood().ifPresent(effects::ambientMoodSound);
vanilla.getBackgroundMusic().ifPresent(effects::backgroundMusic);
vanilla.getAmbientParticle().ifPresent(effects::ambientParticle);
builder.specialEffects(effects.build());
return builder.build();
}
public static String createBiomeID(ConfigPack pack, com.dfsek.terra.api.registry.key.RegistryKey biomeID) {
return pack.getID()
.toLowerCase() + "/" + biomeID.getNamespace().toLowerCase(Locale.ROOT) + "/" + biomeID.getID().toLowerCase(Locale.ROOT);
}
}

View File

@@ -1,15 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
import org.bukkit.Bukkit;
import com.dfsek.terra.bukkit.PlatformImpl;
import com.dfsek.terra.bukkit.nms.Initializer;
public class NMSInitializer implements Initializer {
@Override
public void initialize(PlatformImpl platform) {
AwfulBukkitHacks.registerBiomes(platform.getRawConfigRegistry());
Bukkit.getPluginManager().registerEvents(new NMSInjectListener(), platform.getPlugin());
}
}

View File

@@ -1,48 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkGenerator;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.bukkit.generator.BukkitChunkGeneratorWrapper;
public class NMSInjectListener implements Listener {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSInjectListener.class);
private static final Set<World> INJECTED = new HashSet<>();
private static final ReentrantLock INJECT_LOCK = new ReentrantLock();
@EventHandler
public void onWorldInit(WorldInitEvent event) {
if(!INJECTED.contains(event.getWorld()) &&
event.getWorld().getGenerator() instanceof BukkitChunkGeneratorWrapper bukkitChunkGeneratorWrapper) {
INJECT_LOCK.lock();
INJECTED.add(event.getWorld());
LOGGER.info("Preparing to take over the world: {}", event.getWorld().getName());
CraftWorld craftWorld = (CraftWorld) event.getWorld();
ServerLevel serverWorld = craftWorld.getHandle();
ConfigPack pack = bukkitChunkGeneratorWrapper.getPack();
ChunkGenerator vanilla = serverWorld.getChunkSource().getGenerator();
NMSBiomeProvider provider = new NMSBiomeProvider(pack.getBiomeProvider(), craftWorld.getSeed());
serverWorld.getChunkSource().chunkMap.generator = new NMSChunkGeneratorDelegate(vanilla, pack, provider, craftWorld.getSeed());
LOGGER.info("Successfully injected into world.");
INJECT_LOCK.unlock();
}
}
}

View File

@@ -1,36 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
import net.minecraft.world.level.LevelHeightAccessor;
import com.dfsek.terra.api.world.info.WorldProperties;
public class NMSWorldProperties implements WorldProperties {
private final long seed;
private final LevelHeightAccessor height;
public NMSWorldProperties(long seed, LevelHeightAccessor height) {
this.seed = seed;
this.height = height;
}
@Override
public Object getHandle() {
return height;
}
@Override
public long getSeed() {
return seed;
}
@Override
public int getMaxHeight() {
return height.getMaxBuildHeight();
}
@Override
public int getMinHeight() {
return height.getMinBuildHeight();
}
}

View File

@@ -1,50 +0,0 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
import net.minecraft.core.Holder;
import net.minecraft.core.Holder.Reference;
import net.minecraft.core.MappedRegistry;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.StructureManager;
import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
import xyz.jpenilla.reflectionremapper.proxy.ReflectionProxyFactory;
import xyz.jpenilla.reflectionremapper.proxy.annotation.FieldGetter;
import xyz.jpenilla.reflectionremapper.proxy.annotation.FieldSetter;
import xyz.jpenilla.reflectionremapper.proxy.annotation.MethodName;
import xyz.jpenilla.reflectionremapper.proxy.annotation.Proxies;
public class Reflection {
public static final MappedRegistryProxy MAPPED_REGISTRY;
public static final StructureManagerProxy STRUCTURE_MANAGER;
public static final ReferenceProxy REFERENCE;
static {
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
ReflectionProxyFactory reflectionProxyFactory = ReflectionProxyFactory.create(reflectionRemapper,
Reflection.class.getClassLoader());
MAPPED_REGISTRY = reflectionProxyFactory.reflectionProxy(MappedRegistryProxy.class);
STRUCTURE_MANAGER = reflectionProxyFactory.reflectionProxy(StructureManagerProxy.class);
REFERENCE = reflectionProxyFactory.reflectionProxy(ReferenceProxy.class);
}
@Proxies(MappedRegistry.class)
public interface MappedRegistryProxy {
@FieldSetter("frozen")
void setFrozen(MappedRegistry<?> instance, boolean frozen);
}
@Proxies(StructureManager.class)
public interface StructureManagerProxy {
@FieldGetter("level")
LevelAccessor getLevel(StructureManager instance);
}
@Proxies(Holder.Reference.class)
public interface ReferenceProxy {
@MethodName("bindValue")
<T> void invokeBindValue(Reference<T> instance, T value);
}
}

View File

@@ -1,13 +1,9 @@
apply(plugin = "io.papermc.paperweight.userdev")
repositories {
maven("https://s01.oss.sonatype.org/content/repositories/snapshots/")
}
dependencies {
api(project(":platforms:bukkit:common"))
paperDevBundle(Versions.Bukkit.paperDevBundle)
implementation("xyz.jpenilla", "reflection-remapper", "0.1.0-SNAPSHOT")
implementation("xyz.jpenilla", "reflection-remapper", Versions.Bukkit.reflectionRemapper)
}
tasks {

View File

@@ -1,10 +1,10 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
package com.dfsek.terra.bukkit.nms.v1_21;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.Holder;
import net.minecraft.core.Holder.Reference;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.RegistrationInfo;
import net.minecraft.core.WritableRegistry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
@@ -27,72 +27,73 @@ import com.dfsek.terra.registry.master.ConfigRegistry;
public class AwfulBukkitHacks {
private static final Logger LOGGER = LoggerFactory.getLogger(AwfulBukkitHacks.class);
private static final Map<ResourceLocation, List<ResourceLocation>> terraBiomeMap = new HashMap<>();
public static void registerBiomes(ConfigRegistry configRegistry) {
try {
LOGGER.info("Hacking biome registry...");
WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) RegistryFetcher.biomeRegistry();
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, false);
configRegistry.forEach(pack -> pack.getRegistry(com.dfsek.terra.api.world.biome.Biome.class).forEach((key, biome) -> {
try {
BukkitPlatformBiome platformBiome = (BukkitPlatformBiome) biome.getPlatformBiome();
NamespacedKey vanillaBukkitKey = platformBiome.getHandle().getKey();
ResourceLocation vanillaMinecraftKey = new ResourceLocation(vanillaBukkitKey.getNamespace(), vanillaBukkitKey.getKey());
ResourceLocation vanillaMinecraftKey = ResourceLocation.fromNamespaceAndPath(vanillaBukkitKey.getNamespace(),
vanillaBukkitKey.getKey());
Biome platform = NMSBiomeInjector.createBiome(biome, Objects.requireNonNull(biomeRegistry.get(vanillaMinecraftKey)));
ResourceKey<Biome> delegateKey = ResourceKey.create(
Registries.BIOME,
new ResourceLocation("terra", NMSBiomeInjector.createBiomeID(pack, key))
);
Reference<Biome> holder = biomeRegistry.register(delegateKey, platform, Lifecycle.stable());
Registries.BIOME,
ResourceLocation.fromNamespaceAndPath("terra", NMSBiomeInjector.createBiomeID(pack, key))
);
Reference<Biome> holder = biomeRegistry.register(delegateKey, platform, RegistrationInfo.BUILT_IN);
Reflection.REFERENCE.invokeBindValue(holder, platform); // IMPORTANT: bind holder.
platformBiome.getContext().put(new NMSBiomeInfo(delegateKey));
terraBiomeMap.computeIfAbsent(vanillaMinecraftKey, i -> new ArrayList<>()).add(delegateKey.location());
LOGGER.debug("Registered biome: " + delegateKey);
} catch(NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}));
Reflection.MAPPED_REGISTRY.setFrozen((MappedRegistry<?>) biomeRegistry, true); // freeze registry again :)
LOGGER.info("Doing tag garbage....");
Map<TagKey<Biome>, List<Holder<Biome>>> collect = biomeRegistry
.getTags() // streamKeysAndEntries
.collect(HashMap::new,
(map, pair) ->
map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())),
HashMap::putAll);
.getTags() // streamKeysAndEntries
.collect(HashMap::new,
(map, pair) ->
map.put(pair.getFirst(), new ArrayList<>(pair.getSecond().stream().toList())),
HashMap::putAll);
terraBiomeMap
.forEach((vb, terraBiomes) ->
NMSBiomeInjector.getEntry(biomeRegistry, vb).ifPresentOrElse(
vanilla -> terraBiomes.forEach(
tb -> NMSBiomeInjector.getEntry(biomeRegistry, tb).ifPresentOrElse(
terra -> {
LOGGER.debug("{} (vanilla for {}): {}",
vanilla.unwrapKey().orElseThrow().location(),
terra.unwrapKey().orElseThrow().location(),
vanilla.tags().toList());
vanilla.tags()
.forEach(tag -> collect
.computeIfAbsent(tag, t -> new ArrayList<>())
.add(terra));
},
() -> LOGGER.error("No such biome: {}", tb))),
() -> LOGGER.error("No vanilla biome: {}", vb)));
.forEach((vb, terraBiomes) ->
NMSBiomeInjector.getEntry(biomeRegistry, vb).ifPresentOrElse(
vanilla -> terraBiomes.forEach(
tb -> NMSBiomeInjector.getEntry(biomeRegistry, tb).ifPresentOrElse(
terra -> {
LOGGER.debug("{} (vanilla for {}): {}",
vanilla.unwrapKey().orElseThrow().location(),
terra.unwrapKey().orElseThrow().location(),
vanilla.tags().toList());
vanilla.tags()
.forEach(tag -> collect
.computeIfAbsent(tag, t -> new ArrayList<>())
.add(terra));
},
() -> LOGGER.error("No such biome: {}", tb))),
() -> LOGGER.error("No vanilla biome: {}", vb)));
biomeRegistry.resetTags();
biomeRegistry.bindTags(ImmutableMap.copyOf(collect));
} catch(SecurityException | IllegalArgumentException exception) {
throw new RuntimeException(exception);
}

View File

@@ -1,4 +1,4 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
package com.dfsek.terra.bukkit.nms.v1_21;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.biome.Biome;

View File

@@ -1,4 +1,4 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
package com.dfsek.terra.bukkit.nms.v1_21;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
@@ -18,60 +18,59 @@ public class NMSBiomeInjector {
public static <T> Optional<Holder<T>> getEntry(Registry<T> registry, ResourceLocation identifier) {
return registry.getOptional(identifier)
.flatMap(registry::getResourceKey)
.map(registry::getOrCreateHolderOrThrow);
.flatMap(registry::getResourceKey)
.flatMap(registry::getHolder);
}
public static Biome createBiome(com.dfsek.terra.api.world.biome.Biome biome, Biome vanilla)
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Biome.BiomeBuilder builder = new Biome.BiomeBuilder();
builder
.precipitation(vanilla.getPrecipitation())
.downfall(vanilla.getDownfall())
.temperature(vanilla.getBaseTemperature())
.mobSpawnSettings(vanilla.getMobSettings())
.generationSettings(vanilla.getGenerationSettings());
.downfall(vanilla.climateSettings.downfall())
.temperature(vanilla.getBaseTemperature())
.mobSpawnSettings(vanilla.getMobSettings())
.generationSettings(vanilla.getGenerationSettings());
BiomeSpecialEffects.Builder effects = new BiomeSpecialEffects.Builder();
effects.grassColorModifier(vanilla.getSpecialEffects().getGrassColorModifier());
VanillaBiomeProperties vanillaBiomeProperties = biome.getContext().get(VanillaBiomeProperties.class);
effects.fogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getFogColor(), vanilla.getFogColor()))
.waterColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterColor(), vanilla.getWaterColor()))
.waterFogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterFogColor(), vanilla.getWaterFogColor()))
.skyColor(Objects.requireNonNullElse(vanillaBiomeProperties.getSkyColor(), vanilla.getSkyColor()));
.waterColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterColor(), vanilla.getWaterColor()))
.waterFogColor(Objects.requireNonNullElse(vanillaBiomeProperties.getWaterFogColor(), vanilla.getWaterFogColor()))
.skyColor(Objects.requireNonNullElse(vanillaBiomeProperties.getSkyColor(), vanilla.getSkyColor()));
if(vanillaBiomeProperties.getFoliageColor() == null) {
vanilla.getSpecialEffects().getFoliageColorOverride().ifPresent(effects::foliageColorOverride);
} else {
effects.foliageColorOverride(vanillaBiomeProperties.getFoliageColor());
}
if(vanillaBiomeProperties.getGrassColor() == null) {
vanilla.getSpecialEffects().getGrassColorOverride().ifPresent(effects::grassColorOverride);
} else {
// grass
effects.grassColorOverride(vanillaBiomeProperties.getGrassColor());
}
vanilla.getAmbientLoop().ifPresent(effects::ambientLoopSound);
vanilla.getAmbientAdditions().ifPresent(effects::ambientAdditionsSound);
vanilla.getAmbientMood().ifPresent(effects::ambientMoodSound);
vanilla.getBackgroundMusic().ifPresent(effects::backgroundMusic);
vanilla.getAmbientParticle().ifPresent(effects::ambientParticle);
builder.specialEffects(effects.build());
return builder.build();
}
public static String createBiomeID(ConfigPack pack, com.dfsek.terra.api.registry.key.RegistryKey biomeID) {
return pack.getID()
.toLowerCase() + "/" + biomeID.getNamespace().toLowerCase(Locale.ROOT) + "/" + biomeID.getID().toLowerCase(Locale.ROOT);

View File

@@ -1,14 +1,15 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
package com.dfsek.terra.bukkit.nms.v1_21;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.Holder;
import java.util.stream.Stream;
import net.minecraft.core.Registry;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.Climate.Sampler;
import org.jetbrains.annotations.NotNull;
import java.util.stream.Stream;
import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
import com.dfsek.terra.bukkit.world.BukkitPlatformBiome;
@@ -23,25 +24,30 @@ public class NMSBiomeProvider extends BiomeSource {
this.delegate = delegate;
this.seed = seed;
}
@Override
protected Stream<Holder<Biome>> collectPossibleBiomes() {
return delegate.stream()
.map(biome -> RegistryFetcher.biomeRegistry()
.getHolderOrThrow(((BukkitPlatformBiome) biome.getPlatformBiome()).getContext()
.get(NMSBiomeInfo.class)
.biomeKey()));
return delegate.stream()
.map(biome -> RegistryFetcher.biomeRegistry()
.getHolderOrThrow(((BukkitPlatformBiome) biome.getPlatformBiome()).getContext()
.get(NMSBiomeInfo.class)
.biomeKey()));
}
@Override
protected @NotNull Codec<? extends BiomeSource> codec() {
return BiomeSource.CODEC;
protected @NotNull MapCodec<? extends BiomeSource> codec() {
return MapCodec.assumeMapUnsafe(BiomeSource.CODEC);
// return MapCodec.unit(null);
// BuiltInRegistries.BIOME_SOURCE.byNameCodec().dispatchMap(this::codec, Function.identity());
// BuiltInRegistries.BIOME_SOURCE.byNameCodec().dispatchStable(BiomeSource::codec, Function.identity());
// return BiomeSource.CODEC;
}
@Override
public @NotNull Holder<Biome> getNoiseBiome(int x, int y, int z, @NotNull Sampler sampler) {
return biomeRegistry.getHolderOrThrow(((BukkitPlatformBiome) delegate.getBiome(x << 2, y << 2, z << 2, seed)
.getPlatformBiome()).getContext()
.get(NMSBiomeInfo.class)
.biomeKey());
.getPlatformBiome()).getContext()
.get(NMSBiomeInfo.class)
.biomeKey());
}
}

View File

@@ -1,6 +1,6 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
package com.dfsek.terra.bukkit.nms.v1_21;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.LevelAccessor;
@@ -19,14 +19,13 @@ import net.minecraft.world.level.levelgen.GenerationStep.Carving;
import net.minecraft.world.level.levelgen.Heightmap.Types;
import net.minecraft.world.level.levelgen.RandomState;
import net.minecraft.world.level.levelgen.blending.Blender;
import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
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;
@@ -39,12 +38,12 @@ import com.dfsek.terra.bukkit.world.block.data.BukkitBlockState;
public class NMSChunkGeneratorDelegate extends ChunkGenerator {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSChunkGeneratorDelegate.class);
private final com.dfsek.terra.api.world.chunk.generation.ChunkGenerator delegate;
private final ChunkGenerator vanilla;
private final ConfigPack pack;
private final long seed;
public NMSChunkGeneratorDelegate(ChunkGenerator vanilla, ConfigPack pack, NMSBiomeProvider biomeProvider, long seed) {
super(biomeProvider);
this.delegate = pack.getGeneratorProvider().newInstance(pack);
@@ -52,56 +51,57 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator {
this.pack = pack;
this.seed = seed;
}
@Override
protected @NotNull Codec<? extends ChunkGenerator> codec() {
return ChunkGenerator.CODEC;
protected @NotNull MapCodec<? extends ChunkGenerator> codec() {
return MapCodec.assumeMapUnsafe(ChunkGenerator.CODEC);
}
@Override
public void applyCarvers(@NotNull WorldGenRegion chunkRegion, long seed, @NotNull RandomState noiseConfig, @NotNull BiomeManager world,
@NotNull StructureManager structureAccessor, @NotNull ChunkAccess chunk, @NotNull Carving carverStep) {
// no-op
}
@Override
public void buildSurface(@NotNull WorldGenRegion region, @NotNull StructureManager structures, @NotNull RandomState noiseConfig,
@NotNull ChunkAccess chunk) {
// no-op
}
@Override
public void applyBiomeDecoration(@NotNull WorldGenLevel world, @NotNull ChunkAccess chunk,
@NotNull StructureManager structureAccessor) {
vanilla.applyBiomeDecoration(world, chunk, structureAccessor);
}
@Override
public void spawnOriginalMobs(@NotNull WorldGenRegion region) {
vanilla.spawnOriginalMobs(region);
}
@Override
public int getGenDepth() {
return vanilla.getGenDepth();
}
@Override
public @NotNull CompletableFuture<ChunkAccess> fillFromNoise(@NotNull Executor executor, @NotNull Blender blender,
@NotNull RandomState noiseConfig,
@NotNull StructureManager structureAccessor, @NotNull ChunkAccess chunk) {
return vanilla.fillFromNoise(executor, blender, noiseConfig, structureAccessor, chunk)
.thenApply(c -> {
LevelAccessor level = Reflection.STRUCTURE_MANAGER.getLevel(structureAccessor);
BiomeProvider biomeProvider = pack.getBiomeProvider();
PreLoadCompatibilityOptions compatibilityOptions = pack.getContext().get(PreLoadCompatibilityOptions.class);
if(compatibilityOptions.isBeard()) {
beard(structureAccessor, chunk, new BukkitWorldProperties(level.getMinecraftWorld().getWorld()), biomeProvider, compatibilityOptions);
}
return c;
});
public CompletableFuture<ChunkAccess> fillFromNoise(@NotNull Blender blender,
@NotNull RandomState noiseConfig,
@NotNull StructureManager structureAccessor, @NotNull ChunkAccess chunk) {
return vanilla.fillFromNoise(blender, noiseConfig, structureAccessor, chunk)
.thenApply(c -> {
LevelAccessor level = Reflection.STRUCTURE_MANAGER.getLevel(structureAccessor);
BiomeProvider biomeProvider = pack.getBiomeProvider();
PreLoadCompatibilityOptions compatibilityOptions = pack.getContext().get(PreLoadCompatibilityOptions.class);
if(compatibilityOptions.isBeard()) {
beard(structureAccessor, chunk, new BukkitWorldProperties(level.getMinecraftWorld().getWorld()),
biomeProvider, compatibilityOptions);
}
return c;
});
}
private void beard(StructureManager structureAccessor, ChunkAccess chunk, WorldProperties world, BiomeProvider biomeProvider,
PreLoadCompatibilityOptions compatibilityOptions) {
Beardifier structureWeightSampler = Beardifier.forStructuresInChunk(structureAccessor, chunk.getPos());
@@ -116,8 +116,8 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator {
double noise = structureWeightSampler.compute(new SinglePointContext(x + xi, y, z + zi));
if(noise > threshold) {
chunk.setBlockState(new BlockPos(x, y, z), ((CraftBlockData) ((BukkitBlockState) delegate
.getPalette(x + xi, y, z + zi, world, biomeProvider)
.get(depth, x + xi, y, z + zi, world.getSeed())).getHandle()).getState(), false);
.getPalette(x + xi, y, z + zi, world, biomeProvider)
.get(depth, x + xi, y, z + zi, world.getSeed())).getHandle()).getState(), false);
depth++;
} else if(noise < airThreshold) {
chunk.setBlockState(new BlockPos(x, y, z), Blocks.AIR.defaultBlockState(), false);
@@ -128,29 +128,29 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator {
}
}
}
@Override
public int getSeaLevel() {
return vanilla.getSeaLevel();
}
@Override
public int getMinY() {
return vanilla.getMinY();
}
@Override
public int getBaseHeight(int x, int z, @NotNull Types heightmap, @NotNull LevelHeightAccessor world, @NotNull RandomState noiseConfig) {
WorldProperties properties = new NMSWorldProperties(seed, world);
int y = properties.getMaxHeight();
BiomeProvider biomeProvider = pack.getBiomeProvider();
while(y >= getMinY() && !heightmap.isOpaque().test(
((CraftBlockData) delegate.getBlock(properties, x, y - 1, z, biomeProvider).getHandle()).getState())) {
((CraftBlockData) delegate.getBlock(properties, x, y - 1, z, biomeProvider).getHandle()).getState())) {
y--;
}
return y;
}
@Override
public @NotNull NoiseColumn getBaseColumn(int x, int z, @NotNull LevelHeightAccessor world, @NotNull RandomState noiseConfig) {
BlockState[] array = new BlockState[world.getHeight()];
@@ -158,7 +158,7 @@ public class NMSChunkGeneratorDelegate extends ChunkGenerator {
BiomeProvider biomeProvider = pack.getBiomeProvider();
for(int y = properties.getMaxHeight() - 1; y >= properties.getMinHeight(); y--) {
array[y - properties.getMinHeight()] = ((CraftBlockData) delegate.getBlock(properties, x, y, z, biomeProvider)
.getHandle()).getState();
.getHandle()).getState();
}
return new NoiseColumn(getMinY(), array);
}

View File

@@ -1,4 +1,4 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
package com.dfsek.terra.bukkit.nms.v1_21;
import org.bukkit.Bukkit;

View File

@@ -1,9 +1,11 @@
package com.dfsek.terra.bukkit.nms.v1_19_R2;
package com.dfsek.terra.bukkit.nms.v1_21;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.chunk.status.WorldGenContext;
import org.bukkit.World;
import org.bukkit.craftbukkit.v1_19_R2.CraftWorld;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.world.WorldInitEvent;
@@ -15,6 +17,7 @@ import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;
import com.dfsek.terra.api.config.ConfigPack;
import com.dfsek.terra.api.util.reflection.ReflectionUtil;
import com.dfsek.terra.bukkit.generator.BukkitChunkGeneratorWrapper;
@@ -22,7 +25,7 @@ public class NMSInjectListener implements Listener {
private static final Logger LOGGER = LoggerFactory.getLogger(NMSInjectListener.class);
private static final Set<World> INJECTED = new HashSet<>();
private static final ReentrantLock INJECT_LOCK = new ReentrantLock();
@EventHandler
public void onWorldInit(WorldInitEvent event) {
if(!INJECTED.contains(event.getWorld()) &&
@@ -32,16 +35,23 @@ public class NMSInjectListener implements Listener {
LOGGER.info("Preparing to take over the world: {}", event.getWorld().getName());
CraftWorld craftWorld = (CraftWorld) event.getWorld();
ServerLevel serverWorld = craftWorld.getHandle();
ConfigPack pack = bukkitChunkGeneratorWrapper.getPack();
ChunkGenerator vanilla = serverWorld.getChunkSource().getGenerator();
NMSBiomeProvider provider = new NMSBiomeProvider(pack.getBiomeProvider(), craftWorld.getSeed());
serverWorld.getChunkSource().chunkMap.generator = new NMSChunkGeneratorDelegate(vanilla, pack, provider, craftWorld.getSeed());
ChunkMap chunkMap = serverWorld.getChunkSource().chunkMap;
WorldGenContext worldGenContext = chunkMap.worldGenContext;
Reflection.CHUNKMAP.setWorldGenContext(chunkMap, new WorldGenContext(
worldGenContext.level(),
new NMSChunkGeneratorDelegate(vanilla, pack, provider, craftWorld.getSeed()),
worldGenContext.structureManager(),
worldGenContext.lightEngine(),
worldGenContext.mainThreadMailBox()
));
LOGGER.info("Successfully injected into world.");
INJECT_LOCK.unlock();
}
}

View File

@@ -1,4 +1,4 @@
package com.dfsek.terra.bukkit.nms.v1_19_R1;
package com.dfsek.terra.bukkit.nms.v1_21;
import net.minecraft.world.level.LevelHeightAccessor;
@@ -8,27 +8,27 @@ import com.dfsek.terra.api.world.info.WorldProperties;
public class NMSWorldProperties implements WorldProperties {
private final long seed;
private final LevelHeightAccessor height;
public NMSWorldProperties(long seed, LevelHeightAccessor height) {
this.seed = seed;
this.height = height;
}
@Override
public Object getHandle() {
return height;
}
@Override
public long getSeed() {
return seed;
}
@Override
public int getMaxHeight() {
return height.getMaxBuildHeight();
}
@Override
public int getMinHeight() {
return height.getMinBuildHeight();

View File

@@ -1,10 +1,12 @@
package com.dfsek.terra.bukkit.nms.v1_19_R3;
package com.dfsek.terra.bukkit.nms.v1_21;
import net.minecraft.core.Holder;
import net.minecraft.core.Holder.Reference;
import net.minecraft.core.MappedRegistry;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.chunk.status.WorldGenContext;
import xyz.jpenilla.reflectionremapper.ReflectionRemapper;
import xyz.jpenilla.reflectionremapper.proxy.ReflectionProxyFactory;
import xyz.jpenilla.reflectionremapper.proxy.annotation.FieldGetter;
@@ -12,41 +14,50 @@ import xyz.jpenilla.reflectionremapper.proxy.annotation.FieldSetter;
import xyz.jpenilla.reflectionremapper.proxy.annotation.MethodName;
import xyz.jpenilla.reflectionremapper.proxy.annotation.Proxies;
import java.util.Objects;
public class Reflection {
public static final MappedRegistryProxy MAPPED_REGISTRY;
public static final StructureManagerProxy STRUCTURE_MANAGER;
public static final ReferenceProxy REFERENCE;
public static final ChunkMapProxy CHUNKMAP;
static {
ReflectionRemapper reflectionRemapper = ReflectionRemapper.forReobfMappingsInPaperJar();
ReflectionProxyFactory reflectionProxyFactory = ReflectionProxyFactory.create(reflectionRemapper,
Reflection.class.getClassLoader());
Reflection.class.getClassLoader());
MAPPED_REGISTRY = reflectionProxyFactory.reflectionProxy(MappedRegistryProxy.class);
STRUCTURE_MANAGER = reflectionProxyFactory.reflectionProxy(StructureManagerProxy.class);
REFERENCE = reflectionProxyFactory.reflectionProxy(ReferenceProxy.class);
CHUNKMAP = reflectionProxyFactory.reflectionProxy(ChunkMapProxy.class);
}
@Proxies(MappedRegistry.class)
public interface MappedRegistryProxy {
@FieldSetter("frozen")
void setFrozen(MappedRegistry<?> instance, boolean frozen);
}
@Proxies(StructureManager.class)
public interface StructureManagerProxy {
@FieldGetter("level")
LevelAccessor getLevel(StructureManager instance);
}
@Proxies(Holder.Reference.class)
public interface ReferenceProxy {
@MethodName("bindValue")
<T> void invokeBindValue(Reference<T> instance, T value);
}
@Proxies(ChunkMap.class)
public interface ChunkMapProxy {
@FieldSetter("worldGenContext")
void setWorldGenContext(ChunkMap instance, WorldGenContext worldGenContext);
}
}

View File

@@ -1,4 +1,4 @@
package com.dfsek.terra.bukkit.nms.v1_20_R1;
package com.dfsek.terra.bukkit.nms.v1_21;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
@@ -6,7 +6,7 @@ import net.minecraft.resources.ResourceKey;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.level.biome.Biome;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
import org.bukkit.craftbukkit.CraftServer;
public class RegistryFetcher {
@@ -14,10 +14,10 @@ public class RegistryFetcher {
CraftServer craftserver = (CraftServer) Bukkit.getServer();
DedicatedServer dedicatedserver = craftserver.getServer();
return dedicatedserver
.registryAccess()
.registryOrThrow(key);
.registryAccess()
.registryOrThrow(key);
}
public static Registry<Biome> biomeRegistry() {
return getRegistry(Registries.BIOME);
}

View File

@@ -6,15 +6,15 @@ val javaMainClass = "com.dfsek.terra.cli.TerraCLI"
dependencies {
shadedApi(project(":common:implementation:base"))
shadedApi("commons-io:commons-io:${Versions.CLI.commonsIO}")
shadedApi("com.github.Querz:NBT:${Versions.CLI.nbt}")
shadedImplementation("com.google.guava:guava:${Versions.CLI.guava}")
shadedImplementation("ch.qos.logback:logback-classic:${Versions.CLI.logback}")
implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
shadedApi("commons-io", "commons-io", Versions.Libraries.Internal.apacheIO)
shadedApi("com.github.Querz", "NBT", Versions.CLI.nbt)
shadedImplementation("com.google.guava", "guava", Versions.Libraries.Internal.guava)
shadedImplementation("ch.qos.logback", "logback-classic", Versions.CLI.logback)
}
tasks.withType<Jar> {
@@ -22,7 +22,7 @@ tasks.withType<Jar> {
manifest {
attributes(
"Main-Class" to javaMainClass,
)
)
}
}

View File

@@ -18,41 +18,41 @@ import com.dfsek.terra.cli.handle.CLIWorldHandle;
public class CLIPlatform extends AbstractPlatform {
private static final Logger LOGGER = LoggerFactory.getLogger(CLIPlatform.class);
private final CLIWorldHandle worldHandle = new CLIWorldHandle();
private final CLIItemHandle itemHandle = new CLIItemHandle();
public CLIPlatform() {
LOGGER.info("Root directory: {}", getDataFolder().getAbsoluteFile());
load();
LOGGER.info("Initialized Terra platform.");
}
@Override
public boolean reload() {
return false;
}
@Override
public @NotNull String platformName() {
return "CLI";
}
@Override
public @NotNull WorldHandle getWorldHandle() {
return worldHandle;
}
@Override
public @NotNull File getDataFolder() {
return new File("./");
}
@Override
public @NotNull ItemHandle getItemHandle() {
return itemHandle;
}
@Override
public void register(TypeRegistry registry) {
super.register(registry);

View File

@@ -14,24 +14,24 @@ import com.dfsek.terra.cli.world.CLIWorld;
public final class TerraCLI {
private static final Logger LOGGER = LoggerFactory.getLogger(TerraCLI.class);
public static void main(String... args) {
LOGGER.info("Starting Terra CLI...");
CLIPlatform platform = new CLIPlatform();
platform.getEventManager().callEvent(new PlatformInitializationEvent());
ConfigPack generate = platform.getConfigRegistry().getByID("OVERWORLD").orElseThrow(); // TODO: make this a cli argument
CLIWorld world = new CLIWorld(2, 2, 384, -64, generate);
world.generate();
world.serialize().parallel().forEach(mcaFile -> {
Vector2Int pos = mcaFile.getLeft();
String name = MCAUtil.createNameFromRegionLocation(pos.getX(), pos.getZ());
LOGGER.info("Writing region ({}, {}) to {}", pos.getX(), pos.getZ(), name);
try {
MCAUtil.write(mcaFile.getRight(), name);
} catch(IOException e) {

View File

@@ -12,7 +12,7 @@ public class CLIBlockState implements BlockState {
private final CLIBlockType type;
private final boolean isAir;
private final CompoundTag nbt;
public CLIBlockState(String value) {
this.value = value;
if(value.contains("[")) {
@@ -30,54 +30,54 @@ public class CLIBlockState implements BlockState {
for(String property : props) {
String name = property.substring(0, property.indexOf('='));
String val = property.substring(property.indexOf('=') + 1);
pTag.putString(name, val);
}
this.nbt.put("Properties", pTag);
} else this.type = new CLIBlockType(value);
this.nbt.putString("Name", type.getHandle());
}
@Override
public Object getHandle() {
return value;
}
@Override
public boolean matches(BlockState other) {
return false;
}
@Override
public <T extends Comparable<T>> boolean has(Property<T> property) {
return false;
}
@Override
public <T extends Comparable<T>> T get(Property<T> property) {
return null;
}
@Override
public <T extends Comparable<T>> BlockState set(Property<T> property, T value) {
return null;
}
@Override
public BlockType getBlockType() {
return type;
}
@Override
public String getAsString(boolean properties) {
return value;
}
@Override
public boolean isAir() {
return isAir;
}
public CompoundTag getNbt() {
return nbt;
}

View File

@@ -10,7 +10,7 @@ public class CLIBlockType implements BlockType {
private final boolean solid;
private final boolean water;
private final Lazy<CLIBlockState> defaultState;
public CLIBlockType(String value) {
if(value.contains("[")) throw new IllegalArgumentException("Block Type must not contain properties");
this.value = value;
@@ -18,22 +18,22 @@ public class CLIBlockType implements BlockType {
this.water = value.equals("minecraft:water");
this.defaultState = Lazy.lazy(() -> new CLIBlockState(value));
}
@Override
public String getHandle() {
return value;
}
@Override
public BlockState getDefaultState() {
return defaultState.value();
}
@Override
public boolean isSolid() {
return solid;
}
@Override
public boolean isWater() {
return water;

Some files were not shown because too many files have changed in this diff Show More