Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix 1.18 issues #98

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Directories #
build/
/bin/
bin/
target/

# OS Files #
Expand Down Expand Up @@ -70,10 +70,12 @@ todolist.txt
.idea/*

#Gradle
/.gradle/
.gradle/*
.gradle/
!gradle-wrapper.jar

# WorldEdit Builds
Support-WorldEdit-7/build/tmp*
Support-WorldEdit-6/build/tmp*
Support-WorldEdit-6/build/tmp*

# run-paper
/run/
6 changes: 3 additions & 3 deletions Support-WorldEdit-6/build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
dependencies {
shadow 'org.spigotmc:spigot-api:1.8.8-R0.1-SNAPSHOT'
shadow 'com.sk89q.worldedit:worldedit-bukkit:6.1.5'
shadow 'com.sk89q.worldedit:worldedit-core:6.1.4-SNAPSHOT'
compileOnly 'org.spigotmc:spigot-api:1.8.8-R0.1-SNAPSHOT'
compileOnly 'com.sk89q.worldedit:worldedit-bukkit:6.1.5'
compileOnly 'com.sk89q.worldedit:worldedit-core:6.1.4-SNAPSHOT'
}
4 changes: 2 additions & 2 deletions Support-WorldEdit-7/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
dependencies {
shadow 'org.spigotmc:spigot-api:1.13.2-R0.1-SNAPSHOT'
shadow 'com.sk89q.worldedit:worldedit-bukkit:7.1.0-SNAPSHOT'
compileOnly 'org.spigotmc:spigot-api:1.13.2-R0.1-SNAPSHOT'
compileOnly 'com.sk89q.worldedit:worldedit-bukkit:7.1.0-SNAPSHOT'
}
16 changes: 16 additions & 0 deletions adapters/1_18_R1/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
plugins {
id "io.papermc.paperweight.userdev" version "1.3.5"
}

dependencies {
api project(":adapters")
paperweightDevelopmentBundle "io.papermc.paper:dev-bundle:1.18.1-R0.1-SNAPSHOT"
}

// Reobfuscate JAR with paperweight on build
tasks.named("assemble") {
dependsOn tasks.named("reobfJar")
}

// Minecraft 1.18 requires Java 17
java.toolchain.languageVersion = JavaLanguageVersion.of(17)
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.gmail.val59000mc.adapters.impl.v1_18_R1;

import java.util.function.Consumer;

import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_18_R1.CraftServer;

import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.WritableRegistry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.dedicated.DedicatedServer;

/**
* Utility class for dealing with the NMS registry.
*/
public abstract class RegistryUtils {

private static final RegistryAccess registryAccess = getRegistryAccess();

private static RegistryAccess getRegistryAccess() {
final DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer();
return server.registryAccess();
}

/**
* Obtains write access to a given registry and runs an operation on it.
*
* @param <T> the type of registry
* @param registryKey the key for the registry
* @param writeOperation the operation to run with write access
*/
public static <T> void obtainWriteAccess(ResourceKey<Registry<T>> registryKey, Consumer<WritableRegistry<T>> writeOperation) {
final MappedRegistry<T> registry = (MappedRegistry<T>) registryAccess.ownedRegistryOrThrow(registryKey);
writeOperation.accept(registry);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.gmail.val59000mc.adapters.impl.v1_18_R1;

import java.util.OptionalInt;

import com.gmail.val59000mc.adapters.VersionAdapter;
import com.mojang.serialization.Lifecycle;

import net.minecraft.core.Registry;
import net.minecraft.world.level.levelgen.Noises;
import net.minecraft.world.level.levelgen.synth.NormalNoise.NoiseParameters;

public class VersionAdapterImpl extends VersionAdapter {

@Override
public void removeOceans() {
// Setting the continentalness noise to a constant 0 will stop ocean generation.
// It may also reduce the quality of the terrain generation, but without
// noise routers (introduced in 1.18.2), this seems like the best solution.
final NoiseParameters continentalnessWithoutOceans = new NoiseParameters(0, 0);
RegistryUtils.obtainWriteAccess(Registry.NOISE_REGISTRY, noiseRegistry -> {
noiseRegistry.registerOrOverride(OptionalInt.empty(), Noises.CONTINENTALNESS, continentalnessWithoutOceans, Lifecycle.stable());
});
}

}
16 changes: 16 additions & 0 deletions adapters/1_18_R2/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
plugins {
id "io.papermc.paperweight.userdev" version "1.3.5"
}

dependencies {
api project(":adapters")
paperweightDevelopmentBundle "io.papermc.paper:dev-bundle:1.18.2-R0.1-SNAPSHOT"
}

// Reobfuscate JAR with paperweight on build
tasks.named("assemble") {
dependsOn tasks.named("reobfJar")
}

// Minecraft 1.18 requires Java 17
java.toolchain.languageVersion = JavaLanguageVersion.of(17)
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.gmail.val59000mc.adapters.impl.v1_18_R2;

import java.lang.reflect.Field;
import java.util.function.Consumer;

import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.v1_18_R2.CraftServer;

import net.minecraft.core.MappedRegistry;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.WritableRegistry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.dedicated.DedicatedServer;

/**
* Utility class for dealing with the NMS registry.
*/
public abstract class RegistryUtils {

private static final RegistryAccess registryAccess = getRegistryAccess();

private static RegistryAccess getRegistryAccess() {
final DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer();
return server.registryAccess();
}

/**
* Obtains write access to a given registry and runs an operation on it.
*
* @param <T> the type of registry
* @param registryKey the key for the registry
* @param writeOperation the operation to run with write access
*/
public static <T> void obtainWriteAccess(ResourceKey<Registry<T>> registryKey, Consumer<WritableRegistry<T>> writeOperation) {
final MappedRegistry<T> registry = (MappedRegistry<T>) registryAccess.ownedRegistryOrThrow(registryKey);
try {
// Starting from 1.18.2, registries are frozen after initialization,
// which happens before any plugins are loaded. This is a workaround
// to allow writing to the registry by temporarily unfreezing it again.
final Field frozen = MappedRegistry.class.getDeclaredField("bL");
frozen.setAccessible(true);
frozen.set(registry, false);
writeOperation.accept(registry);
frozen.set(registry, true);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new RuntimeException("Unable to get registry write access", e);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.gmail.val59000mc.adapters.impl.v1_18_R2;

import java.util.OptionalInt;

import com.gmail.val59000mc.adapters.VersionAdapter;
import com.mojang.serialization.Lifecycle;

import net.minecraft.core.Registry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.levelgen.DensityFunction;
import net.minecraft.world.level.levelgen.DensityFunctions;
import net.minecraft.world.level.levelgen.DensityFunctions.MarkerOrMarked;
import net.minecraft.world.level.levelgen.NoiseRouterData;

public class VersionAdapterImpl extends VersionAdapter {

/**
* See {@link NoiseRouterData#CONTINENTS}.
*/
private final ResourceKey<DensityFunction> continentsKey = ResourceKey.create(Registry.DENSITY_FUNCTION_REGISTRY, new ResourceLocation("overworld/continents"));

@Override
public void removeOceans() {
RegistryUtils.obtainWriteAccess(Registry.DENSITY_FUNCTION_REGISTRY, dfRegistry -> {
// The continents noise function is wrapped in a flatCache, see NoiseRouterData#bootstrap().
final MarkerOrMarked continents = (MarkerOrMarked) dfRegistry.getOrThrow(continentsKey);
// We keep the flatCache for performance, but take the absolute value of the noise function.
// This stops ocean generation, but keeps the qualities of the original noise.
final DensityFunction continentsWithoutOceans = DensityFunctions.flatCache(continents.wrapped().abs());
dfRegistry.registerOrOverride(OptionalInt.empty(), continentsKey, continentsWithoutOceans, Lifecycle.stable());
});
}

}
5 changes: 5 additions & 0 deletions adapters/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dependencies {
implementation "io.papermc:paperlib:1.0.7"
implementation ":BiomeMapping-1.3"
compileOnly "org.spigotmc:spigot-api:1.8.8-R0.1-SNAPSHOT"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package com.gmail.val59000mc.adapters;

import com.gmail.val59000mc.adapters.impl.DefaultVersionAdapterImpl;

import org.bukkit.Bukkit;

/**
* Utility class exposing an abstraction layer for functionality where a
* custom implementation needs to be used depending on the runtime server version.
*/
public abstract class VersionAdapter {

/**
* Loads and instantiates a {@link VersionAdapter} for the running server version.
*
* @return the adapter instance
* @throws InstantiationException if the adapter couldn't be instantiated
*/
public static VersionAdapter instantiate() throws InstantiationException {
try {
final Class<? extends VersionAdapter> loadedClass = loadAdapterImplClass();
return loadedClass.getConstructor().newInstance();
} catch (ClassNotFoundException ignored) {
return new DefaultVersionAdapterImpl();
} catch (Exception e) {
throw new InstantiationException(e);
}
}

public static class InstantiationException extends Exception {
public InstantiationException(Throwable cause) {
super("Unable to instantiate version adapter", cause);
}
}

/**
* Gets the NMS package name of the running server, such as {@code v1_18_R2}.
*
* @return the NMS package name
*/
private static String getNmsPackageName() {
final String nmsPackageName = Bukkit.getServer().getClass().getPackage().getName();
return nmsPackageName.substring(nmsPackageName.lastIndexOf('.') + 1);
}

/**
* Loads and returns the adapter implementation class for the running server version.
*
* @return the adapter implementation class
* @throws ClassNotFoundException if the class cannot be loaded
*/
@SuppressWarnings("unchecked")
private static Class<? extends VersionAdapter> loadAdapterImplClass() throws ClassNotFoundException {
final String implPackageName = DefaultVersionAdapterImpl.class.getPackage().getName();
final String nmsImplPackageName = implPackageName + '.' + getNmsPackageName();
final String implClassName = VersionAdapter.class.getSimpleName() + "Impl";
return (Class<? extends VersionAdapter>) Class.forName(nmsImplPackageName + '.' + implClassName);
}

/**
* Removes oceans from the world generation.
* <p>
* This method should be called before the world is generated.
*
* @throws UnsupportedOperationException if not supported by this adapter
*/
public abstract void removeOceans();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.gmail.val59000mc.adapters.impl;

import com.gmail.val59000mc.adapters.VersionAdapter;
import com.pieterdebot.biomemapping.Biome;
import com.pieterdebot.biomemapping.BiomeMappingAPI;

import io.papermc.lib.PaperLib;

/**
* A default {@link VersionAdapter} implementation, used as a fallback.
*/
public class DefaultVersionAdapterImpl extends VersionAdapter {

@Override
public void removeOceans() {
final int version = PaperLib.getMinecraftVersion();
if (8 <= version && version <= 17) {
removeOceansUsingBiomeMapping();
} else {
throw new UnsupportedOperationException();
}
}

private void removeOceansUsingBiomeMapping() {
final BiomeMappingAPI biomeMapping = new BiomeMappingAPI();
Biome replacementBiome = Biome.PLAINS;

for (Biome biome : Biome.values()) {
if (biome.isOcean() && biomeMapping.biomeSupported(biome)) {
try {
biomeMapping.replaceBiomes(biome, replacementBiome);
} catch (Exception ex) {
ex.printStackTrace();
}

replacementBiome = replacementBiome == Biome.PLAINS ? Biome.FOREST : Biome.PLAINS;
}
}
}

}
Loading