feat: add support for meta pack

This commit is contained in:
daoge_cmd
2025-10-10 00:30:38 +08:00
parent d640b49ded
commit d1ad3d04e1
12 changed files with 224 additions and 79 deletions

View File

@@ -2,7 +2,7 @@
## Resource files
Current mapping version: je 1.21.7 to be 1.21.93
Current mapping version: je 1.21.7 to be 1.21.111
- `mapping/biomes.json` and `mapping/items.json` are obtained from [GeyserMC/mappings](https://github.com/GeyserMC/mappings).
- `mapping/blocks.json` is obtained from [GeyserMC/mappings-generator](https://github.com/GeyserMC/mappings-generator) (path: `https://github.com/GeyserMC/mappings-generator/blob/master/new_generator_blocks.json`).

View File

@@ -28,7 +28,7 @@ dependencies {
geyserMappings("GeyserMC.mappings", "items", Versions.Allay.mappings, ext = "json")
geyserMappings("GeyserMC.mappings", "biomes", Versions.Allay.mappings, ext = "json")
geyserMappings("GeyserMC.mappings-generator", "new_generator_blocks", Versions.Allay.mappingsGenerator, ext = "json")
geyserMappings("GeyserMC.mappings-generator", "generator_blocks", Versions.Allay.mappingsGenerator, ext = "json")
mcmeta("misode.mcmeta", "blocks/data", Versions.Allay.mcmeta, ext = "json")
}
@@ -38,7 +38,7 @@ tasks.processResources {
into("mapping")
// rather jank, but whatever
rename("(?:new_generator_)?([^-]+)-(.*)\\.json", "$1.json")
rename("(?:generator_)?([^-]+)-(.*)\\.json", "$1.json")
}
from(mcmeta) {
rename("data-(.*)\\.json", "je_blocks.json")

View File

@@ -45,7 +45,7 @@ public class AllayPlatform extends AbstractPlatform {
getConfigRegistry().get(wrapper.getConfigPack().getRegistryKey()).ifPresent(pack -> {
wrapper.setConfigPack(pack);
var dimension = wrapper.getAllayWorldGenerator().getDimension();
TerraAllayPlugin.INSTANCE.getPluginLogger().info(
TerraAllayPlugin.instance.getPluginLogger().info(
"Replaced pack in chunk generator for world {}",
dimension.getWorld().getWorldData().getDisplayName() + ":" + dimension.getDimensionInfo().dimensionId()
);
@@ -72,7 +72,7 @@ public class AllayPlatform extends AbstractPlatform {
@Override
public @NotNull File getDataFolder() {
return TerraAllayPlugin.INSTANCE.getPluginContainer().dataFolder().toFile();
return TerraAllayPlugin.instance.getPluginContainer().dataFolder().toFile();
}
@Override

View File

@@ -10,12 +10,25 @@ import java.util.TreeMap;
* @author daoge_cmd
*/
public class JeBlockState {
protected final String identifier;
protected final TreeMap<String, String> properties;
protected int hash = Integer.MAX_VALUE;
private JeBlockState(String data) {
String[] strings = data.replace("[", ",").replace("]", ",").replace(" ", "").split(",");
// TODO: support block state with nbt (identifier[properties]{nbt}), for now we just ignore it
int braceIndex = data.indexOf('{');
if (braceIndex != -1) {
data = data.substring(0, braceIndex);
}
String[] strings = data
.replace("[", ",")
.replace("]", ",")
.replace(" ", "")
.split(",");
this.identifier = strings[0];
this.properties = new TreeMap<>();
if(strings.length > 1) {

View File

@@ -13,6 +13,7 @@ import org.allaymc.api.block.type.BlockStateGetter;
import org.allaymc.api.block.type.BlockTypes;
import org.allaymc.api.item.type.ItemType;
import org.allaymc.api.item.type.ItemTypeGetter;
import org.allaymc.api.world.data.DimensionInfo;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
@@ -57,7 +58,7 @@ public final class Mapping {
public static BlockState blockStateJeToBe(JeBlockState jeBlockState) {
BlockState result = JE_BLOCK_STATE_HASH_TO_BE.get(jeBlockState.getHash());
if(result == null) {
TerraAllayPlugin.INSTANCE.getPluginLogger().warn("Failed to find be block state for {}", jeBlockState);
TerraAllayPlugin.instance.getPluginLogger().warn("Failed to find be block state for {}", jeBlockState);
return BE_AIR_STATE;
}
return result;
@@ -81,10 +82,19 @@ public final class Mapping {
return JE_BIOME_ID_TO_BE.get(jeBiomeId);
}
public static String dimensionIdBeToJe(String beDimensionId) {
return switch (beDimensionId) {
case "overworld" -> "minecraft:overworld";
case "nether" -> "minecraft:the_nether";
case "the_end" -> "minecraft:the_end";
default -> beDimensionId;
};
}
public static Map<String, String> getJeBlockDefaultProperties(String jeBlockIdentifier) {
var defaultProperties = JE_BLOCK_DEFAULT_PROPERTIES.get(jeBlockIdentifier);
if(defaultProperties == null) {
TerraAllayPlugin.INSTANCE.getPluginLogger().warn("Failed to find default properties for {}", jeBlockIdentifier);
TerraAllayPlugin.instance.getPluginLogger().warn("Failed to find default properties for {}", jeBlockIdentifier);
return Map.of();
}
@@ -98,7 +108,7 @@ public final class Mapping {
private static boolean initBiomeMapping() {
try(InputStream stream = Mapping.class.getClassLoader().getResourceAsStream("mapping/biomes.json")) {
if(stream == null) {
TerraAllayPlugin.INSTANCE.getPluginLogger().error("biomes mapping not found");
TerraAllayPlugin.instance.getPluginLogger().error("biomes mapping not found");
return false;
}
@@ -106,7 +116,7 @@ public final class Mapping {
});
mappings.forEach((javaId, mapping) -> JE_BIOME_ID_TO_BE.put(javaId, mapping.bedrockId()));
} catch(IOException e) {
TerraAllayPlugin.INSTANCE.getPluginLogger().error("Failed to load biomes mapping", e);
TerraAllayPlugin.instance.getPluginLogger().error("Failed to load biomes mapping", e);
return false;
}
return true;
@@ -115,7 +125,7 @@ public final class Mapping {
private static boolean initItemMapping() {
try(InputStream stream = Mapping.class.getClassLoader().getResourceAsStream("mapping/items.json")) {
if(stream == null) {
TerraAllayPlugin.INSTANCE.getPluginLogger().error("items mapping not found");
TerraAllayPlugin.instance.getPluginLogger().error("items mapping not found");
return false;
}
@@ -129,7 +139,7 @@ public final class Mapping {
JE_ITEM_ID_TO_BE.put(javaId, itemType);
});
} catch(IOException e) {
TerraAllayPlugin.INSTANCE.getPluginLogger().error("Failed to load items mapping", e);
TerraAllayPlugin.instance.getPluginLogger().error("Failed to load items mapping", e);
return false;
}
return true;
@@ -138,7 +148,7 @@ public final class Mapping {
private static boolean initBlockStateMapping() {
try(InputStream stream = Mapping.class.getClassLoader().getResourceAsStream("mapping/blocks.json")) {
if(stream == null) {
TerraAllayPlugin.INSTANCE.getPluginLogger().error("blocks mapping not found");
TerraAllayPlugin.instance.getPluginLogger().error("blocks mapping not found");
return false;
}
@@ -152,7 +162,7 @@ public final class Mapping {
JE_BLOCK_STATE_HASH_TO_BE.put(jeState.getHash(), beState);
});
} catch(IOException e) {
TerraAllayPlugin.INSTANCE.getPluginLogger().error("Failed to load blocks mapping", e);
TerraAllayPlugin.instance.getPluginLogger().error("Failed to load blocks mapping", e);
return false;
}
return true;
@@ -162,7 +172,7 @@ public final class Mapping {
private static boolean initJeBlockDefaultProperties() {
try(InputStream stream = Mapping.class.getClassLoader().getResourceAsStream("je_blocks.json")) {
if(stream == null) {
TerraAllayPlugin.INSTANCE.getPluginLogger().error("je_block_default_states.json not found");
TerraAllayPlugin.instance.getPluginLogger().error("je_block_default_states.json not found");
return false;
}

View File

@@ -15,38 +15,38 @@ import com.dfsek.terra.api.event.events.platform.PlatformInitializationEvent;
*/
public class TerraAllayPlugin extends Plugin {
public static TerraAllayPlugin INSTANCE;
public static AllayPlatform PLATFORM;
public static TerraAllayPlugin instance;
public static AllayPlatform platform;
{
INSTANCE = this;
TerraAllayPlugin.instance = this;
}
@Override
public void onLoad() {
pluginLogger.info("Starting Terra...");
this.pluginLogger.info("Starting Terra...");
pluginLogger.info("Loading mapping...");
this.pluginLogger.info("Loading mapping...");
Mapping.init();
pluginLogger.info("Initializing allay platform...");
PLATFORM = new AllayPlatform();
PLATFORM.getEventManager().callEvent(new PlatformInitializationEvent());
this.pluginLogger.info("Initializing allay platform...");
TerraAllayPlugin.platform = new AllayPlatform();
TerraAllayPlugin.platform.getEventManager().callEvent(new PlatformInitializationEvent());
// TODO: adapt command manager
pluginLogger.info("Registering generator...");
this.pluginLogger.info("Registering generator...");
Registries.WORLD_GENERATOR_FACTORIES.register("TERRA", preset -> {
try {
AllayGeneratorWrapper wrapper = new AllayGeneratorWrapper(preset);
AllayPlatform.GENERATOR_WRAPPERS.add(wrapper);
return wrapper.getAllayWorldGenerator();
} catch(IllegalArgumentException e) {
TerraAllayPlugin.INSTANCE.getPluginLogger().error("Fail to create world generator with preset: {}", preset, e);
TerraAllayPlugin.instance.getPluginLogger().error("Fail to create world generator with preset: {}", preset, e);
return Registries.WORLD_GENERATOR_FACTORIES.get("FLAT").apply("");
}
});
pluginLogger.info("Terra started");
this.pluginLogger.info("Terra started");
}
@Override
@@ -61,10 +61,10 @@ public class TerraAllayPlugin extends Plugin {
@Override
public void reload() {
if(PLATFORM.reload()) {
pluginLogger.info("Terra reloaded successfully.");
if(TerraAllayPlugin.platform.reload()) {
this.pluginLogger.info("Terra reloaded successfully.");
} else {
pluginLogger.error("Terra failed to reload.");
this.pluginLogger.error("Terra failed to reload.");
}
}

View File

@@ -0,0 +1,52 @@
package com.dfsek.terra.allay.delegate;
import com.dfsek.seismic.type.vector.Vector3;
import com.dfsek.terra.allay.Mapping;
import com.dfsek.terra.api.block.state.BlockState;
import org.allaymc.api.blockentity.BlockEntity;
/**
* @author daoge_cmd
*/
public record AllayBlockEntity(BlockEntity allayBlockEntity) implements com.dfsek.terra.api.block.entity.BlockEntity {
@Override
public boolean update(boolean applyPhysics) {
return false;
}
@Override
public Vector3 getPosition() {
var pos = this.allayBlockEntity.getPosition();
return Vector3.of(pos.x(), pos.y(), pos.z());
}
@Override
public int getX() {
return this.allayBlockEntity.getPosition().x();
}
@Override
public int getY() {
return this.allayBlockEntity.getPosition().y();
}
@Override
public int getZ() {
return this.allayBlockEntity.getPosition().z();
}
@Override
public BlockState getBlockState() {
var allayBlockState = this.allayBlockEntity.getBlockState();
return new AllayBlockState(allayBlockState, Mapping.blockStateBeToJe(this.allayBlockEntity.getBlockState()));
}
@Override
public Object getHandle() {
return this.allayBlockEntity;
}
}

View File

@@ -63,7 +63,24 @@ public record AllayProtoWorld(AllayServerWorld allayServerWorld, OtherChunkAcces
@Override
public BlockEntity getBlockEntity(int x, int y, int z) {
return null;
return new AllayBlockEntity(getBlockEntity(context, x, y, z));
}
// TODO: add this method to allay-api
private static org.allaymc.api.blockentity.BlockEntity getBlockEntity(OtherChunkAccessibleContext context, int x, int y, int z) {
var currentChunk = context.getCurrentChunk();
var currentChunkX = currentChunk.getX();
var currentChunkZ = currentChunk.getZ();
var dimInfo = currentChunk.getDimensionInfo();
if (x >= currentChunkX * 16 && x < currentChunkX * 16 + 16 &&
z >= currentChunkZ * 16 && z < currentChunkZ * 16 + 16 &&
y >= dimInfo.minHeight() && y <= dimInfo.maxHeight()) {
return currentChunk.getBlockEntity(x & 15, y, z & 15);
} else {
var chunk = context.getChunkSource().getChunk(x >> 4, z >> 4);
return chunk == null ? null : chunk.getBlockEntity(x & 15, y, z & 15);
}
}
@Override

View File

@@ -44,7 +44,7 @@ public record AllayServerWorld(AllayGeneratorWrapper allayGeneratorWrapper, Dime
@Override
public BlockEntity getBlockEntity(int x, int y, int z) {
return null;
return new AllayBlockEntity(allayDimension.getBlockEntity(x, y, z));
}
@Override

View File

@@ -0,0 +1,42 @@
package com.dfsek.terra.allay.delegate;
import com.dfsek.terra.api.world.info.WorldProperties;
import org.allaymc.api.world.data.DimensionInfo;
/**
* @author daoge_cmd
*/
public class AllayWorldProperties implements WorldProperties {
private final Object fakeHandle;
private final long seed;
private final DimensionInfo dimensionInfo;
public AllayWorldProperties(long seed, DimensionInfo dimensionInfo) {
this.fakeHandle = new Object();
this.seed = seed;
this.dimensionInfo = dimensionInfo;
}
@Override
public long getSeed() {
return this.seed;
}
@Override
public int getMaxHeight() {
return dimensionInfo.maxHeight();
}
@Override
public int getMinHeight() {
return dimensionInfo.minHeight();
}
@Override
public Object getHandle() {
return fakeHandle;
}
}

View File

@@ -1,18 +1,19 @@
package com.dfsek.terra.allay.generator;
import com.dfsek.terra.allay.Mapping;
import com.dfsek.terra.allay.delegate.AllayWorldProperties;
import com.google.common.base.Preconditions;
import org.allaymc.api.utils.AllayStringUtils;
import org.allaymc.api.world.biome.BiomeType;
import org.allaymc.api.world.chunk.UnsafeChunk;
import org.allaymc.api.world.data.DimensionInfo;
import org.allaymc.api.world.generator.WorldGenerator;
import org.allaymc.api.world.generator.context.NoiseContext;
import org.allaymc.api.world.generator.context.PopulateContext;
import org.allaymc.api.world.generator.function.Noiser;
import org.allaymc.api.world.generator.function.Populator;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import com.dfsek.terra.allay.TerraAllayPlugin;
import com.dfsek.terra.allay.delegate.AllayProtoChunk;
import com.dfsek.terra.allay.delegate.AllayProtoWorld;
@@ -30,27 +31,23 @@ import com.dfsek.terra.api.world.info.WorldProperties;
*/
public class AllayGeneratorWrapper implements GeneratorWrapper {
protected static final String OPTION_META_PACK_NAME = "meta-pack";
protected static final String OPTION_PACK_NAME = "pack";
protected static final String OPTION_SEED = "seed";
protected final BiomeProvider biomeProvider;
protected final long seed;
protected final WorldGenerator allayWorldGenerator;
protected ChunkGenerator chunkGenerator;
protected ConfigPack configPack;
protected ChunkGenerator chunkGenerator;
protected BiomeProvider biomeProvider;
protected WorldProperties worldProperties;
protected AllayServerWorld allayServerWorld;
public AllayGeneratorWrapper(String preset) {
Map<String, String> options = AllayStringUtils.parseOptions(preset);
String packName = options.get(OPTION_PACK_NAME);
if(packName == null) {
throw new IllegalArgumentException("Missing config pack name");
}
this.seed = Long.parseLong(options.getOrDefault(OPTION_SEED, "0"));
this.configPack = getConfigPack(packName);
this.chunkGenerator = createGenerator(this.configPack);
this.biomeProvider = this.configPack.getBiomeProvider();
var options = AllayStringUtils.parseOptions(preset);
this.seed = parseSeed(options.get(OPTION_SEED));
this.allayWorldGenerator = WorldGenerator
.builder()
.name("TERRA")
@@ -59,40 +56,52 @@ public class AllayGeneratorWrapper implements GeneratorWrapper {
.populators(new AllayPopulator())
.onDimensionSet(dimension -> {
this.allayServerWorld = new AllayServerWorld(this, dimension);
this.worldProperties = new WorldProperties() {
this.worldProperties = new AllayWorldProperties(this.seed, dimension.getDimensionInfo());
private final Object fakeHandle = new Object();
var metaPackName = options.get(OPTION_META_PACK_NAME);
if (metaPackName != null) {
setConfigPack(getConfigPackByMeta(metaPackName, dimension.getDimensionInfo()));
return;
}
@Override
public long getSeed() {
return seed;
}
var packName = options.get(OPTION_PACK_NAME);
if(packName != null) {
setConfigPack(getConfigPackById(packName));
return;
}
@Override
public int getMaxHeight() {
return dimension.getDimensionInfo().maxHeight();
}
@Override
public int getMinHeight() {
return dimension.getDimensionInfo().minHeight();
}
@Override
public Object getHandle() {
return fakeHandle;
}
};
throw new IllegalArgumentException("Either 'pack' or 'meta-pack' option should be specified in the generator preset!");
})
.build();
}
protected static ConfigPack getConfigPack(String packName) {
Optional<ConfigPack> byId = TerraAllayPlugin.PLATFORM.getConfigRegistry().getByID(packName);
return byId.orElseGet(
() -> TerraAllayPlugin.PLATFORM.getConfigRegistry().getByID(packName.toUpperCase(Locale.ENGLISH))
.orElseThrow(() -> new IllegalArgumentException("Cant find terra config pack named " + packName))
);
protected static long parseSeed(String str) {
if(str == null) {
return 0;
}
try {
return Long.parseLong(str);
} catch(NumberFormatException e) {
// Return the hashcode of the string if it cannot be parsed to a long value directly
return str.hashCode();
}
}
protected static ConfigPack getConfigPackById(String packId) {
return TerraAllayPlugin.platform
.getConfigRegistry()
.getByID(packId)
.orElseThrow(() -> new IllegalArgumentException("Cant find terra config pack named " + packId));
}
protected static ConfigPack getConfigPackByMeta(String metaPackId, DimensionInfo dimensionInfo) {
return TerraAllayPlugin.platform
.getMetaConfigRegistry()
.getByID(metaPackId)
.orElseThrow(() -> new IllegalArgumentException("Cant find terra meta pack named " + metaPackId))
.packs()
.get(Mapping.dimensionIdBeToJe(dimensionInfo.toString()));
}
protected static ChunkGenerator createGenerator(ConfigPack configPack) {
@@ -101,7 +110,7 @@ public class AllayGeneratorWrapper implements GeneratorWrapper {
@Override
public ChunkGenerator getHandle() {
return chunkGenerator;
return this.chunkGenerator;
}
public BiomeProvider getBiomeProvider() {
@@ -113,8 +122,10 @@ public class AllayGeneratorWrapper implements GeneratorWrapper {
}
public void setConfigPack(ConfigPack configPack) {
Preconditions.checkNotNull(configPack, "Config pack cannot be null!");
this.configPack = configPack;
this.chunkGenerator = createGenerator(this.configPack);
this.biomeProvider = this.configPack.getBiomeProvider();
}
public long getSeed() {
@@ -165,7 +176,7 @@ public class AllayGeneratorWrapper implements GeneratorWrapper {
generationStage.populate(tmp);
}
} catch(Exception e) {
TerraAllayPlugin.INSTANCE.getPluginLogger().error("Error while populating chunk", e);
TerraAllayPlugin.instance.getPluginLogger().error("Error while populating chunk", e);
}
return true;
}