Bleh POckets

This commit is contained in:
Waterpicker 2023-05-06 08:40:47 -05:00
parent 113eb04e0d
commit 642b5582fb
67 changed files with 4004 additions and 308 deletions

View file

@ -4,11 +4,17 @@ import dev.architectury.utils.GameInstance;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import org.dimdev.dimdoors.api.DimensionalDoorsApi;
import java.util.List;
public class DimensionalDoors {
public static final String MOD_ID = "dimdoors";
public static ResourceLocation id(String id) {
public static List<DimensionalDoorsApi> apiSubscribers;
public static ResourceLocation id(String id) {
return new ResourceLocation(MOD_ID, id);
}
@ -16,7 +22,7 @@ public class DimensionalDoors {
return GameInstance.getServer();
}
public static Level getWorld(ResourceKey<Level> world) {
public static ServerLevel getWorld(ResourceKey<Level> world) {
return getServer().getLevel(world);
}
}

View file

@ -14,18 +14,10 @@ import org.dimdev.dimdoors.world.pocket.type.addon.PocketAddon;
// TODO: javadocs for everything, refactoring
public interface DimensionalDoorsApi {
default void registerVirtualTargetTypes(Registry<VirtualTarget.VirtualTargetType<?>> registry) {
}
default void registerVirtualSingularPocketTypes(Registry<ImplementedVirtualPocket.VirtualPocketType<?>> registry) {
}
default void registerModifierTypes(Registry<Modifier.ModifierType<?>> registry) {
}
default void registerPocketGeneratorTypes(Registry<PocketGenerator.PocketGeneratorType<?>> registry) {
}
default void registerAbstractPocketTypes(Registry<AbstractPocket.AbstractPocketType<?>> registry) {
}

View file

@ -2,12 +2,14 @@ package org.dimdev.dimdoors.api.util;
import java.util.Map;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtList;
import net.minecraft.nbt.ListTag;
import net.fabricmc.fabric.api.util.NbtType;
@ -41,7 +43,7 @@ public class NbtEquations {
} else if (nbt.getType(key) == NbtType.COMPOUND) {
solved.put(key, solveNbtCompoundEquations(nbt.getCompound(key), variableMap));
} else if (nbt.getType(key) == NbtType.LIST) {
solved.put(key, solveNbtListEquations((NbtList) nbt.get(key), variableMap));
solved.put(key, solveListTagEquations((ListTag) nbt.get(key), variableMap));
} else {
solved.put(key, nbt.get(key));
}
@ -49,12 +51,12 @@ public class NbtEquations {
return solved;
}
public static NbtList solveNbtListEquations(NbtList nbtList, Map<String, Double> variableMap) {
NbtList solved = new NbtList();
for (NbtElement nbt : nbtList) {
if (nbt.getType() == NbtType.LIST) {
solved.add(solveNbtListEquations((NbtList) nbt, variableMap));
} else if (nbt.getType() == NbtType.COMPOUND) {
public static ListTag solveListTagEquations(ListTag ListTag, Map<String, Double> variableMap) {
ListTag solved = new ListTag();
for (Tag nbt : ListTag) {
if (nbt.getId() == Tag.TAG_LIST) {
solved.add(solveListTagEquations((ListTag) nbt, variableMap));
} else if (nbt.getId() == Tag.TAG_COMPOUND) {
solved.add(solveNbtCompoundEquations((NbtCompound) nbt, variableMap));
} else {
solved.add(nbt);

View file

@ -2,11 +2,13 @@ package org.dimdev.dimdoors.api.util;
import com.mojang.serialization.Codec;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtOps;
import net.fabricmc.fabric.api.util.NbtType;
import net.minecraft.nbt.Tag;
public class NbtUtil {
public static <T> T deserialize(NbtElement data, Codec<T> codec) {
@ -19,9 +21,9 @@ public class NbtUtil {
});
}
public static NbtCompound asNbtCompound(NbtElement nbt, String error) {
if (nbt == null || nbt.getType() == NbtType.COMPOUND) {
return (NbtCompound) nbt;
public static CompoundTag asNbtCompound(Tag nbt, String error) {
if (nbt == null || nbt.getId() == Tag.TAG_COMPOUND) {
return (CompoundTag) nbt;
}
throw new RuntimeException(error);

View file

@ -1,5 +1,21 @@
package org.dimdev.dimdoors.api.util;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.mojang.serialization.JsonOps;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.Resource;
import net.minecraft.server.packs.resources.ResourceManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@ -11,36 +27,19 @@ import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.mojang.serialization.JsonOps;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtIo;
import net.minecraft.nbt.NbtOps;
import net.minecraft.resource.Resource;
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier;
public class ResourceUtil {
private static final Logger LOGGER = LogManager.getLogger();
private static final Gson GSON = new GsonBuilder().setLenient().setPrettyPrinting().create();
public static final BiFunction<String, Identifier, Path<String>> PATH_KEY_PROVIDER = (startingPath, id) -> Path.stringPath(id.getNamespace() + ":" + id.getPath().substring(0, id.getPath().lastIndexOf(".")).substring(startingPath.length() + (startingPath.endsWith("/") ? 0 : 1)));
public static final BiFunction<String, ResourceLocation, Path<String>> PATH_KEY_PROVIDER = (startingPath, id) -> Path.stringPath(id.getNamespace() + ":" + id.getPath().substring(0, id.getPath().lastIndexOf(".")).substring(startingPath.length() + (startingPath.endsWith("/") ? 0 : 1)));
public static final ComposableFunction<JsonElement, NbtElement> JSON_TO_NBT = json -> JsonOps.INSTANCE.convertTo(NbtOps.INSTANCE, json);
public static final ComposableFunction<JsonElement, Tag> JSON_TO_NBT = json -> JsonOps.INSTANCE.convertTo(NbtOps.INSTANCE, json);
public static final ComposableFunction<NbtElement, JsonElement> NBT_TO_JSON = json -> NbtOps.INSTANCE.convertTo(JsonOps.INSTANCE, json);
public static final ComposableFunction<Tag, JsonElement> NBT_TO_JSON = json -> NbtOps.INSTANCE.convertTo(JsonOps.INSTANCE, json);
public static final ComposableFunction<InputStream, JsonElement> JSON_READER = inputStream -> GSON.fromJson(new InputStreamReader(inputStream), JsonElement.class);
public static final ComposableFunction<InputStream, NbtElement> NBT_READER = JSON_READER.andThenComposable(JSON_TO_NBT);
public static final ComposableFunction<InputStream, NbtCompound> COMPRESSED_NBT_READER = inputStream -> {
public static final ComposableFunction<InputStream, Tag> NBT_READER = JSON_READER.andThenComposable(JSON_TO_NBT);
public static final ComposableFunction<InputStream, CompoundTag> COMPRESSED_NBT_READER = inputStream -> {
try {
return NbtIo.readCompressed(inputStream);
} catch (IOException e) {
@ -67,28 +66,28 @@ public class ResourceUtil {
String identifier = splitResourceKey[splitResourceKey.length - 1];
int identifierSplitIndex = identifier.indexOf(':');
R resource = loadResource(manager, new Identifier(identifier.substring(0, identifierSplitIndex), startingPath + identifier.substring(identifierSplitIndex + 1)), reader);
R resource = loadResource(manager, new ResourceLocation(identifier.substring(0, identifierSplitIndex), startingPath + identifier.substring(identifierSplitIndex + 1)), reader);
resource.processFlags(flags);
return resource;
}
public static <R> R loadResource(ResourceManager manager, Identifier resourceKey, Function<InputStream, R> reader) {
public static <R> R loadResource(ResourceManager manager, ResourceLocation resourceKey, Function<InputStream, R> reader) {
try {
return reader.apply(manager.getResource(resourceKey).get().getInputStream());
return reader.apply(manager.getResource(resourceKey).get().open());
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
public static <K, T, M extends Map<K, T>> CompletableFuture<M> loadResourcePathToMap(ResourceManager manager, String startingPath, String extension, M map, BiFunction<InputStream, K, T> reader, BiFunction<String, Identifier, K> keyProvider) {
Map<Identifier, Resource> ids = manager.findResources(startingPath, str -> str.getPath().endsWith(extension));
public static <K, T, M extends Map<K, T>> CompletableFuture<M> loadResourcePathToMap(ResourceManager manager, String startingPath, String extension, M map, BiFunction<InputStream, K, T> reader, BiFunction<String, ResourceLocation, K> keyProvider) {
Map<ResourceLocation, Resource> ids = manager.listResources(startingPath, str -> str.getPath().endsWith(extension));
return CompletableFuture.supplyAsync(() -> {
map.putAll(ids.entrySet().parallelStream().unordered().collect(new ExceptionHandlingCollector<>(Collectors.toConcurrentMap(
id -> keyProvider.apply(startingPath, id.getKey()),
id -> {
try {
return reader.apply(id.getValue().getInputStream(), keyProvider.apply(startingPath, id.getKey()));
return reader.apply(id.getValue().open(), keyProvider.apply(startingPath, id.getKey()));
} catch (IOException | RuntimeException e) {
throw new RuntimeException(e);
}
@ -98,12 +97,12 @@ public class ResourceUtil {
});
}
public static <T, M extends Collection<T>> CompletableFuture<M> loadResourcePathToCollection(ResourceManager manager, String startingPath, String extension, M collection, BiFunction<InputStream, Identifier, T> reader) {
Map<Identifier, Resource> ids = manager.findResources(startingPath, str -> str.getPath().endsWith(extension));
public static <T, M extends Collection<T>> CompletableFuture<M> loadResourcePathToCollection(ResourceManager manager, String startingPath, String extension, M collection, BiFunction<InputStream, ResourceLocation, T> reader) {
Map<ResourceLocation, Resource> ids = manager.listResources(startingPath, str -> str.getPath().endsWith(extension));
return CompletableFuture.supplyAsync(() -> {
collection.addAll(ids.entrySet().parallelStream().unordered().map(id -> {
try {
return reader.apply(id.getValue().getInputStream(), id.getKey());
return reader.apply(id.getValue().open(), id.getKey());
} catch (Exception e) {
LOGGER.error("Error loading resource: " + id, e);
return null;

View file

@ -9,6 +9,7 @@ import com.mojang.serialization.Lifecycle;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.SimpleRegistry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Identifier;
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
@ -32,7 +33,7 @@ public interface Condition {
ConditionType<?> getType();
static Condition fromJson(JsonObject json) {
Identifier type = new Identifier(json.getAsJsonPrimitive("type").getAsString());
ResourceLocation type = new ResourceLocation(json.getAsJsonPrimitive("type").getAsString());
return Objects.requireNonNull(REGISTRY.get(type)).fromJson(json);
}

View file

@ -10,8 +10,8 @@ import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FluidState;
import org.dimdev.dimdoors.api.block.CustomBreakBlock;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
@ -23,26 +23,31 @@ import java.util.function.Consumer;
@Mixin(Level.class)
public abstract class WorldMixin {
@Shadow public abstract FluidState getFluidState(BlockPos arg);
/*
I thought about redirecting the entire break method to be handled by the block itself,
but I am not quite sure what that would mean for compatibility with other mixins,
since then a large part of the method would need to be canceled. This is rather hacky, but it should fulfill the purpose best
~CreepyCre
*/
I thought about redirecting the entire break method to be handled by the block itself,
but I am not quite sure what that would mean for compatibility with other mixins,
since then a large part of the method would need to be canceled. This is rather hacky, but it should fulfill the purpose best
~CreepyCre
*/
/*
Original mixin had a breakingEntity. Mixins are being a but so removed to get working.
- Waterpicker
*/
@Redirect(method = "destroyBlock",
at = @At(value = "INVOKE_ASSIGN",
target = "Lnet/minecraft/world/level/Level;getFluidState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/material/FluidState;",
ordinal = 0))
private FluidState replaceFluidStateWithCustomHackyFluidState(FluidState original, BlockPos pos, boolean drop, @Nullable Entity breakingEntity, int maxUpdateDepth) { //TODO: Fix
Level world = (Level) (Object) this;
private FluidState replaceFluidStateWithCustomHackyFluidState(Level world, BlockPos pos) { //TODO: Fix
BlockState blockState = world.getBlockState(pos);
Block block = blockState.getBlock();
if (!(block instanceof CustomBreakBlock)) {
return original;
return world.getFluidState(pos);
}
InteractionResultHolder<Pair<BlockState, Consumer<BlockEntity>>> result = ((CustomBreakBlock) block).customBreakBlock(world, pos, blockState, breakingEntity);
InteractionResultHolder<Pair<BlockState, Consumer<BlockEntity>>> result = ((CustomBreakBlock) block).customBreakBlock(world, pos, blockState, null);
if (!result.getResult().consumesAction()) {
return original;
return getFluidState(pos);
}
Pair<BlockState, Consumer<BlockEntity>> pair = result.getObject();
return new CustomBreakBlock.HackyFluidState(pair.getFirst(), pair.getSecond());

View file

@ -2,6 +2,7 @@ package org.dimdev.dimdoors.pockets;
import java.util.Map;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.world.ServerWorld;
import org.dimdev.dimdoors.DimensionalDoors;
@ -9,7 +10,7 @@ import org.dimdev.dimdoors.rift.registry.LinkProperties;
import org.dimdev.dimdoors.rift.targets.VirtualTarget;
import org.dimdev.dimdoors.world.pocket.VirtualLocation;
public record PocketGenerationContext(ServerWorld world, VirtualLocation sourceVirtualLocation, VirtualTarget linkTo, LinkProperties linkProperties) {
public record PocketGenerationContext(ServerLevel world, VirtualLocation sourceVirtualLocation, VirtualTarget linkTo, LinkProperties linkProperties) {
public Map<String, Double> toVariableMap(Map<String, Double> stringDoubleMap) {
stringDoubleMap.put("depth", (double) this.sourceVirtualLocation.getDepth());
stringDoubleMap.put("public_size", (double) DimensionalDoors.getConfig().getPocketsConfig().publicPocketSize);

View file

@ -1,43 +1,36 @@
package org.dimdev.dimdoors.pockets.generator;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.core.Vec3i;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.biome.Biome;
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.ChunkStatus;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.levelgen.GenerationStep;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
import net.minecraft.world.level.levelgen.RandomState;
import net.minecraft.world.level.levelgen.blending.Blender;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.phys.AABB;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.fluid.FluidState;
import net.minecraft.fluid.Fluids;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.resource.ResourceManager;
import net.minecraft.server.world.ServerLightingProvider;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Box;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.ChunkRegion;
import net.minecraft.world.HeightLimitView;
import net.minecraft.world.Heightmap;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.ChunkStatus;
import net.minecraft.world.chunk.ProtoChunk;
import net.minecraft.world.chunk.UpgradeData;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.chunk.Blender;
import net.minecraft.world.gen.chunk.ChunkGeneratorSettings;
import net.minecraft.world.gen.noise.NoiseConfig;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.block.ModBlocks;
import org.dimdev.dimdoors.block.entity.DetachedRiftBlockEntity;
@ -48,11 +41,16 @@ import org.dimdev.dimdoors.world.level.registry.DimensionalRegistry;
import org.dimdev.dimdoors.world.pocket.VirtualLocation;
import org.dimdev.dimdoors.world.pocket.type.Pocket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
public class ChunkGenerator extends PocketGenerator {
private static final Logger LOGGER = LogManager.getLogger();
public static final String KEY = "chunk";
private Identifier dimensionID;
private ResourceLocation dimensionID;
private Vec3i size; // TODO: equation-ify
private int virtualYOffset; // TODO: equation-ify
@ -60,10 +58,10 @@ public class ChunkGenerator extends PocketGenerator {
}
@Override
public PocketGenerator fromNbt(NbtCompound nbt, ResourceManager manager) {
public PocketGenerator fromNbt(CompoundTag nbt, ResourceManager manager) {
super.fromNbt(nbt, manager);
this.dimensionID = new Identifier(nbt.getString("dimension_id"));
this.dimensionID = new ResourceLocation(nbt.getString("dimension_id"));
int[] temp = nbt.getIntArray("size");
this.size = new Vec3i(temp[0], temp[1], temp[2]);
@ -73,7 +71,7 @@ public class ChunkGenerator extends PocketGenerator {
}
@Override
public NbtCompound toNbtInternal(NbtCompound nbt, boolean allowReference) {
public CompoundTag toNbtInternal(CompoundTag nbt, boolean allowReference) {
super.toNbtInternal(nbt, allowReference);
nbt.putString("dimension_id", dimensionID.toString());
@ -84,74 +82,74 @@ public class ChunkGenerator extends PocketGenerator {
@Override
public Pocket prepareAndPlacePocket(PocketGenerationContext parameters, Pocket.PocketBuilder<?, ?> builder) {
ServerWorld world = parameters.world();
ServerLevel world = parameters.world();
VirtualLocation sourceVirtualLocation = parameters.sourceVirtualLocation();
int chunkSizeX = ((this.size.getX() >> 4) + (this.size.getX() % 16 == 0 ? 0 : 1));
int chunkSizeZ = ((this.size.getZ() >> 4) + (this.size.getZ() % 16 == 0 ? 0 : 1));
Pocket pocket = DimensionalRegistry.getPocketDirectory(world.getRegistryKey()).newPocket(builder);
Pocket pocket = DimensionalRegistry.getPocketDirectory(world.dimension()).newPocket(builder);
LOGGER.info("Generating chunk pocket at location " + pocket.getOrigin());
ServerWorld genWorld = DimensionalDoors.getWorld(RegistryKey.of(RegistryKeys.WORLD, dimensionID));
net.minecraft.world.gen.chunk.ChunkGenerator genWorldChunkGenerator = genWorld.getChunkManager().getChunkGenerator();
ServerLevel genWorld = DimensionalDoors.getWorld(ResourceKey.create(Registries.DIMENSION, dimensionID));
net.minecraft.world.level.chunk.ChunkGenerator genWorldChunkGenerator = genWorld.getChunkSource().getGenerator();
NoiseConfig config = NoiseConfig.create(ChunkGeneratorSettings.createMissingSettings(), world.getRegistryManager().get(RegistryKeys.NOISE_PARAMETERS).getReadOnlyWrapper(), world.getSeed());
RandomState config = RandomState.create(NoiseGeneratorSettings.dummy(), world.registryAccess().registryOrThrow(Registries.NOISE).asLookup(), world.getSeed());
ArrayList<Chunk> protoChunks = new ArrayList<>();
ArrayList<ChunkAccess> protoChunks = new ArrayList<>();
for (int z = 0; z < chunkSizeZ; z++) {
for (int x = 0; x < chunkSizeX; x++) {
ProtoChunk protoChunk = new ProtoChunk(new ChunkPos(pocket.getOrigin().add(x * 16, 0, z * 16)), UpgradeData.NO_UPGRADE_DATA, world, genWorld.getRegistryManager().get(RegistryKeys.BIOME), null);
protoChunk.setLightingProvider(genWorld.getLightingProvider());
ProtoChunk protoChunk = new ProtoChunk(new ChunkPos(pocket.getOrigin().offset(x * 16, 0, z * 16)), UpgradeData.EMPTY, world, genWorld.registryAccess().registryOrThrow(Registries.BIOME), null);
protoChunk.setLightEngine(genWorld.getLightEngine());
protoChunks.add(protoChunk);
}
}
ChunkRegion protoRegion = new ChunkRegionHack(genWorld, protoChunks);//TODO Redo?
for (Chunk protoChunk : protoChunks) { // TODO: check wether structures are even activated
genWorldChunkGenerator.setStructureStarts(genWorld.getRegistryManager(), genWorld.getChunkManager().getStructurePlacementCalculator(), genWorld.getStructureAccessor(), protoChunk, genWorld.getStructureTemplateManager());
WorldGenRegion protoRegion = new ChunkRegionHack(genWorld, protoChunks);//TODO Redo?
for (ChunkAccess protoChunk : protoChunks) { // TODO: check wether structures are even activated
genWorldChunkGenerator.createStructures(genWorld.registryAccess(), genWorld.getChunkSource().getGeneratorState(), genWorld.structureManager(), protoChunk, genWorld.getStructureManager());
((ProtoChunk) protoChunk).setStatus(ChunkStatus.STRUCTURE_STARTS);
}
for (Chunk protoChunk : protoChunks) {
genWorldChunkGenerator.addStructureReferences(protoRegion, genWorld.getStructureAccessor().forRegion(protoRegion), protoChunk);
for (ChunkAccess protoChunk : protoChunks) {
genWorldChunkGenerator.createReferences(protoRegion, genWorld.structureManager().forWorldGenRegion(protoRegion), protoChunk);
((ProtoChunk) protoChunk).setStatus(ChunkStatus.STRUCTURE_REFERENCES);
}
for (Chunk protoChunk : protoChunks) {
genWorldChunkGenerator.populateBiomes(Util.getMainWorkerExecutor(), config, Blender.getNoBlending(), genWorld.getStructureAccessor(), protoChunk);
for (ChunkAccess protoChunk : protoChunks) {
genWorldChunkGenerator.createBiomes(Util.backgroundExecutor(), config, Blender.empty(), genWorld.structureManager(), protoChunk);
((ProtoChunk) protoChunk).setStatus(ChunkStatus.BIOMES);
}
for (Chunk protoChunk : protoChunks) {
for (ChunkAccess protoChunk : protoChunks) {
try {
genWorldChunkGenerator.populateNoise(net.minecraft.util.Util.getMainWorkerExecutor(), Blender.getNoBlending(), config, genWorld.getStructureAccessor().forRegion(protoRegion), protoChunk).get();
genWorldChunkGenerator.fillFromNoise(Util.backgroundExecutor(), Blender.empty(), config, genWorld.structureManager().forWorldGenRegion(protoRegion), protoChunk).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
((ProtoChunk) protoChunk).setStatus(ChunkStatus.NOISE);
}
for (Chunk protoChunk : protoChunks) {
genWorldChunkGenerator.buildSurface(protoRegion, genWorld.getStructureAccessor(), config, protoChunk);
for (ChunkAccess protoChunk : protoChunks) {
genWorldChunkGenerator.buildSurface(protoRegion, genWorld.structureManager(), config, protoChunk);
((ProtoChunk) protoChunk).setStatus(ChunkStatus.SURFACE);
}
for (GenerationStep.Carver carver : GenerationStep.Carver.values()) {
for (Chunk protoChunk : protoChunks) {
genWorldChunkGenerator.carve(protoRegion, genWorld.getSeed(), config, genWorld.getBiomeAccess(), genWorld.getStructureAccessor(), protoChunk, carver);
for (GenerationStep.Carving carver : GenerationStep.Carving.values()) {
for (ChunkAccess protoChunk : protoChunks) {
genWorldChunkGenerator.applyCarvers(protoRegion, genWorld.getSeed(), config, genWorld.getBiomeManager(), genWorld.structureManager(), protoChunk, carver);
ProtoChunk pChunk = ((ProtoChunk) protoChunk);
if (pChunk.getStatus() == ChunkStatus.SURFACE) pChunk.setStatus(ChunkStatus.CARVERS);
else pChunk.setStatus(ChunkStatus.LIQUID_CARVERS);
}
}
for (Chunk protoChunk : protoChunks) {
ChunkRegion tempRegion = new ChunkRegionHack(genWorld, ChunkPos.stream(protoChunk.getPos(), 10).map(chunkPos -> protoRegion.getChunk(chunkPos.x, chunkPos.z)).collect(Collectors.toList()));
genWorldChunkGenerator.generateFeatures(tempRegion, protoChunk, genWorld.getStructureAccessor().forRegion(tempRegion));
for (ChunkAccess protoChunk : protoChunks) {
WorldGenRegion tempRegion = new ChunkRegionHack(genWorld, ChunkPos.rangeClosed(protoChunk.getPos(), 10).map(chunkPos -> protoRegion.getChunk(chunkPos.x, chunkPos.z)).collect(Collectors.toList()));
genWorldChunkGenerator.applyBiomeDecoration(tempRegion, protoChunk, genWorld.structureManager().forWorldGenRegion(tempRegion));
((ProtoChunk) protoChunk).setStatus(ChunkStatus.FEATURES);
}
for (Chunk protoChunk : protoChunks) { // likely only necessary for spawn step since we copy over anyways
((ServerLightingProvider) genWorld.getLightingProvider()).light(protoChunk, false);
for (ChunkAccess protoChunk : protoChunks) { // likely only necessary for spawn step since we copy over anyways
((ThreadedLevelLightEngine) genWorld.getLightEngine()).lightChunk(protoChunk, false);
((ProtoChunk) protoChunk).setStatus(ChunkStatus.LIGHT);
}
for (Chunk protoChunk : protoChunks) { // TODO: does this even work?
ChunkRegion tempRegion = new ChunkRegionHack(genWorld, ChunkPos.stream(protoChunk.getPos(), 5).map(chunkPos -> protoRegion.getChunk(chunkPos.x, chunkPos.z)).collect(Collectors.toList()));
genWorldChunkGenerator.populateEntities(tempRegion);
for (ChunkAccess protoChunk : protoChunks) { // TODO: does this even work?
WorldGenRegion tempRegion = new ChunkRegionHack(genWorld, ChunkPos.rangeClosed(protoChunk.getPos(), 5).map(chunkPos -> protoRegion.getChunk(chunkPos.x, chunkPos.z)).collect(Collectors.toList()));
genWorldChunkGenerator.spawnOriginalMobs(tempRegion);
((ProtoChunk) protoChunk).setStatus(ChunkStatus.SPAWN);
}
@ -159,33 +157,33 @@ public class ChunkGenerator extends PocketGenerator {
BlockPos firstCorner = pocket.getOrigin();
BlockPos secondCorner = new BlockPos(firstCorner.getX() + size.getX() - 1, Math.min(firstCorner.getY() + size.getY() - 1, world.getHeight() - virtualYOffset - 1), firstCorner.getZ() + size.getZ() - 1); // subtracting 1 here since it should be 0 inclusive and size exclusive
BlockPos pocketOriginChunkOffset = new ChunkPos(pocket.getOrigin()).getStartPos().subtract(firstCorner);
for (BlockPos blockPos : BlockPos.iterate(firstCorner, secondCorner)) {
BlockPos sourcePos = blockPos.add(pocketOriginChunkOffset).add(0, virtualYOffset, 0);
BlockPos pocketOriginChunkOffset = new ChunkPos(pocket.getOrigin()).getWorldPosition().subtract(firstCorner);
for (BlockPos blockPos : BlockPos.betweenClosed(firstCorner, secondCorner)) {
BlockPos sourcePos = blockPos.offset(pocketOriginChunkOffset).offset(0, virtualYOffset, 0);
BlockState blockState = protoRegion.getBlockState(sourcePos);
if (!blockState.isAir()) {
world.setBlockState(blockPos, protoRegion.getBlockState(blockPos.add(pocketOriginChunkOffset).add(0, virtualYOffset, 0)));
world.setBlockAndUpdate(blockPos, protoRegion.getBlockState(blockPos.offset(pocketOriginChunkOffset).offset(0, virtualYOffset, 0)));
}
}
Box realBox = new Box(firstCorner, secondCorner);
for (Chunk protoChunk : protoChunks) {
for(BlockPos virtualBlockPos : protoChunk.getBlockEntityPositions()) {
BlockPos realBlockPos = virtualBlockPos.subtract(pocketOriginChunkOffset).add(0, -virtualYOffset, 0);
AABB realBox = new AABB(firstCorner, secondCorner);
for (ChunkAccess protoChunk : protoChunks) {
for(BlockPos virtualBlockPos : protoChunk.getBlockEntitiesPos()) {
BlockPos realBlockPos = virtualBlockPos.subtract(pocketOriginChunkOffset).offset(0, -virtualYOffset, 0);
if (realBox.contains(realBlockPos.getX(), realBlockPos.getY(), realBlockPos.getZ())) {
world.addBlockEntity(protoChunk.getBlockEntity(virtualBlockPos)); // TODO: ensure this works, likely bugged
world.setBlockEntity(protoChunk.getBlockEntity(virtualBlockPos)); // TODO: ensure this works, likely bugged
}
}
}
Box virtualBox = realBox.offset(pocketOriginChunkOffset.add(0, virtualYOffset, 0));
AABB virtualBox = realBox.move(pocketOriginChunkOffset.offset(0, virtualYOffset, 0));
/*
for (Entity entity : protoRegion.getOtherEntities(null, virtualBox)) { // TODO: does this even work?
TeleportUtil.teleport(entity, world, entity.getPos().add(-pocketOriginChunkOffset.getX(), -pocketOriginChunkOffset.getY() - virtualYOffset, -pocketOriginChunkOffset.getZ()), entity.yaw);
} // TODO: Entities?/ Biomes/ Structure Data
*/
world.setBlockState(world.getTopPosition(Heightmap.Type.MOTION_BLOCKING_NO_LEAVES, pocket.getOrigin()), ModBlocks.DETACHED_RIFT.getDefaultState());
world.setBlockAndUpdate(world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, pocket.getOrigin()), ModBlocks.DETACHED_RIFT.get().defaultBlockState());
DetachedRiftBlockEntity rift = ModBlockEntityTypes.DETACHED_RIFT.instantiate(world.getTopPosition(Heightmap.Type.MOTION_BLOCKING_NO_LEAVES, pocket.getOrigin()), ModBlocks.DETACHED_RIFT.getDefaultState());
world.addBlockEntity(rift);
DetachedRiftBlockEntity rift = ModBlockEntityTypes.DETACHED_RIFT.get().create(world.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES, pocket.getOrigin()), ModBlocks.DETACHED_RIFT.get().defaultBlockState());
world.setBlockEntity(rift);
rift.setDestination(new PocketEntranceMarker());
pocket.virtualLocation = sourceVirtualLocation;
@ -195,7 +193,7 @@ public class ChunkGenerator extends PocketGenerator {
@Override
public PocketGeneratorType<? extends PocketGenerator> getType() {
return PocketGeneratorType.CHUNK;
return PocketGeneratorType.CHUNK.get();
}
@Override
@ -208,38 +206,38 @@ public class ChunkGenerator extends PocketGenerator {
return size;
}
private static class ChunkRegionHack extends ChunkRegion { // Please someone tell me if there is a better way
ChunkRegionHack(ServerWorld world, List<Chunk> chunks) {
private static class ChunkRegionHack extends WorldGenRegion { // Please someone tell me if there is a better way
ChunkRegionHack(ServerLevel world, List<ChunkAccess> chunks) {
super(world, chunks, ChunkStatus.EMPTY, 0);
}
@Override
public Chunk getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) {
Chunk chunk = super.getChunk(chunkX, chunkZ, leastStatus, false);
return chunk == null ? new ProtoChunkHack(new ChunkPos(chunkX, chunkZ), UpgradeData.NO_UPGRADE_DATA, this, this.getRegistryManager().get(RegistryKeys.BIOME)) : chunk;
public ChunkAccess getChunk(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) {
ChunkAccess chunk = super.getChunk(chunkX, chunkZ, leastStatus, false);
return chunk == null ? new ProtoChunkHack(new ChunkPos(chunkX, chunkZ), UpgradeData.EMPTY, this, this.registryAccess().registryOrThrow(Registries.BIOME)) : chunk;
}
// TODO: Override getSeed()
}
private static class ProtoChunkHack extends ProtoChunk { // exists solely to make some calls in the non utilized chunks faster
public ProtoChunkHack(ChunkPos pos, UpgradeData upgradeData, HeightLimitView world, Registry<Biome> biomeRegistry) {
public ProtoChunkHack(ChunkPos pos, UpgradeData upgradeData, LevelHeightAccessor world, Registry<Biome> biomeRegistry) {
super(pos, upgradeData, world, biomeRegistry, null);
}
@Override
public BlockState setBlockState(BlockPos pos, BlockState state, boolean moved) {
return Blocks.VOID_AIR.getDefaultState();
return Blocks.VOID_AIR.defaultBlockState();
}
@Override
public BlockState getBlockState(BlockPos pos) {
return Blocks.VOID_AIR.getDefaultState();
return Blocks.VOID_AIR.defaultBlockState();
}
@Override
public FluidState getFluidState(BlockPos pos) {
return Fluids.EMPTY.getDefaultState();
return Fluids.EMPTY.defaultFluidState();
}
}
}

View file

@ -7,6 +7,8 @@ import java.util.List;
import java.util.Queue;
import java.util.stream.Collectors;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.packs.resources.ResourceManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -54,7 +56,7 @@ public abstract class LazyPocketGenerator extends PocketGenerator {
}
@Override
public PocketGenerator fromNbt(NbtCompound nbt, ResourceManager manager) {
public PocketGenerator fromNbt(CompoundTag nbt, ResourceManager manager) {
super.fromNbt(nbt, manager);
if (nbt.contains("lazy_modifiers")) {

View file

@ -7,15 +7,24 @@ import java.util.List;
import java.util.function.Supplier;
import com.google.common.collect.Multimap;
import com.mojang.serialization.Lifecycle;
import dev.architectury.registry.registries.Registrar;
import dev.architectury.registry.registries.RegistrarManager;
import dev.architectury.registry.registries.RegistrySupplier;
import net.minecraft.core.Vec3i;
import net.minecraft.nbt.*;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.world.Container;
import net.minecraft.world.level.block.entity.ChestBlockEntity;
import net.minecraft.world.level.block.entity.DispenserBlockEntity;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.minecraft.block.entity.ChestBlockEntity;
import net.minecraft.block.entity.DispenserBlockEntity;
import net.minecraft.inventory.Inventory;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtList;
import net.minecraft.nbt.NbtString;
import net.minecraft.registry.Registry;
@ -23,7 +32,7 @@ import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.SimpleRegistry;
import net.minecraft.resource.ResourceManager;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.Vec3i;
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
@ -46,7 +55,7 @@ import org.dimdev.dimdoors.world.pocket.type.Pocket;
public abstract class PocketGenerator implements Weighted<PocketGenerationContext>, ReferenceSerializable {
private static final Logger LOGGER = LogManager.getLogger();
public static final Registry<PocketGeneratorType<? extends PocketGenerator>> REGISTRY = FabricRegistryBuilder.from(new SimpleRegistry<PocketGeneratorType<? extends PocketGenerator>>(RegistryKey.ofRegistry(DimensionalDoors.id("pocket_generator_type")), Lifecycle.stable(), false)).buildAndRegister();
public static final Registrar<PocketGeneratorType<? extends PocketGenerator>> REGISTRY = RegistrarManager.get(DimensionalDoors.MOD_ID).<PocketGeneratorType<? extends PocketGenerator>>builder(DimensionalDoors.id("pocket_generator_type")).build();
public static final String RESOURCE_STARTING_PATH = "pockets/generator"; //TODO: might want to restructure data packs
private static final String defaultWeightEquation = "5"; // TODO: make config
@ -55,7 +64,7 @@ public abstract class PocketGenerator implements Weighted<PocketGenerationContex
private String resourceKey = null;
private NbtCompound builderNbt;
private CompoundTag builderNbt;
protected String weight = defaultWeightEquation;
protected Equation weightEquation;
protected Boolean setupLoot;
@ -69,24 +78,23 @@ public abstract class PocketGenerator implements Weighted<PocketGenerationContex
parseWeight();
}
public static PocketGenerator deserialize(NbtElement nbt, ResourceManager manager) {
switch (nbt.getType()) {
case NbtType.COMPOUND: // It's a serialized Modifier
return PocketGenerator.deserialize((NbtCompound) nbt, manager);
case NbtType.STRING: // It's a reference to a resource location
public static PocketGenerator deserialize(Tag nbt, ResourceManager manager) {
return switch (nbt.getType()) {
case Tag.TAG_COMPOUND -> // It's a serialized Modifier
PocketGenerator.deserialize((CompoundTag) nbt, manager);
case Tag.TAG_STRING -> // It's a reference to a resource location
// TODO: throw if manager is null
return ResourceUtil.loadReferencedResource(manager, RESOURCE_STARTING_PATH, nbt.asString(), ResourceUtil.NBT_READER.andThenComposable(nbtElement -> deserialize(nbtElement, manager)));
default:
throw new RuntimeException(String.format("Unexpected NbtType %d!", nbt.getType()));
}
ResourceUtil.loadReferencedResource(manager, RESOURCE_STARTING_PATH, nbt.getAsString(), ResourceUtil.NBT_READER.andThenComposable(Tag -> deserialize(Tag, manager)));
default -> throw new RuntimeException(String.format("Unexpected NbtType %d!", nbt.getType()));
};
}
public static PocketGenerator deserialize(NbtElement nbt) {
public static PocketGenerator deserialize(Tag nbt) {
return deserialize(nbt, null);
}
public static PocketGenerator deserialize(NbtCompound nbt, ResourceManager manager) {
Identifier id = Identifier.tryParse(nbt.getString("type")); // TODO: return some NONE PocketGenerator if type cannot be found or deserialization fails.
public static PocketGenerator deserialize(CompoundTag nbt, ResourceManager manager) {
ResourceLocation id = ResourceLocation.tryParse(nbt.getString("type")); // TODO: return some NONE PocketGenerator if type cannot be found or deserialization fails.
PocketGeneratorType<? extends PocketGenerator> type = REGISTRY.get(id);
if (type == null) {
LOGGER.error("Could not deserialize PocketGenerator: " + nbt.toString());
@ -95,15 +103,15 @@ public abstract class PocketGenerator implements Weighted<PocketGenerationContex
return type.fromNbt(nbt, manager);
}
public static PocketGenerator deserialize(NbtCompound nbt) {
public static PocketGenerator deserialize(CompoundTag nbt) {
return deserialize(nbt, null);
}
public static NbtElement serialize(PocketGenerator pocketGenerator, boolean allowReference) {
return pocketGenerator.toNbt(new NbtCompound(), allowReference);
public static Tag serialize(PocketGenerator pocketGenerator, boolean allowReference) {
return pocketGenerator.toNbt(new CompoundTag(), allowReference);
}
public static NbtElement serialize(PocketGenerator pocketGenerator) {
public static Tag serialize(PocketGenerator pocketGenerator) {
return serialize(pocketGenerator, false);
}
@ -123,8 +131,8 @@ public abstract class PocketGenerator implements Weighted<PocketGenerationContex
}
}
public PocketGenerator fromNbt(NbtCompound nbt, ResourceManager manager) {
if (nbt.contains("builder", NbtType.COMPOUND)) builderNbt = nbt.getCompound("builder");
public PocketGenerator fromNbt(CompoundTag nbt, ResourceManager manager) {
if (nbt.contains("builder", Tag.TAG_COMPOUND)) builderNbt = nbt.getCompound("builder");
this.weight = nbt.contains("weight") ? nbt.getString("weight") : defaultWeightEquation;
parseWeight();
@ -132,21 +140,21 @@ public abstract class PocketGenerator implements Weighted<PocketGenerationContex
if (nbt.contains("setup_loot")) setupLoot = nbt.getBoolean("setup_loot");
if (nbt.contains("modifiers")) {
NbtList modifiersNbt = nbt.getList("modifiers", 10);
ListTag modifiersNbt = nbt.getList("modifiers", 10);
for (int i = 0; i < modifiersNbt.size(); i++) {
modifierList.add(Modifier.deserialize(modifiersNbt.getCompound(i), manager));
}
}
if (nbt.contains("modifier_references")) {
NbtList modifiersNbt = nbt.getList("modifier_references", NbtType.STRING);
for (NbtElement nbtElement : modifiersNbt) {
modifierList.add(Modifier.deserialize(nbtElement, manager));
ListTag modifiersNbt = nbt.getList("modifier_references", Tag.TAG_STRING);
for (Tag Tag : modifiersNbt) {
modifierList.add(Modifier.deserialize(Tag, manager));
}
}
if (nbt.contains("tags")) {
NbtList nbtList = nbt.getList("tags", NbtType.STRING);
ListTag nbtList = nbt.getList("tags", Tag.TAG_STRING);
for (int i = 0; i < nbtList.size(); i++) {
tags.add(nbtList.getString(i));
}
@ -154,18 +162,18 @@ public abstract class PocketGenerator implements Weighted<PocketGenerationContex
return this;
}
public PocketGenerator fromNbt(NbtCompound nbt) {
public PocketGenerator fromNbt(CompoundTag nbt) {
return fromNbt(nbt, null);
}
public NbtElement toNbt(NbtCompound nbt, boolean allowReference) {
public Tag toNbt(CompoundTag nbt, boolean allowReference) {
if (allowReference && this.resourceKey != null) {
return NbtString.of(this.resourceKey);
return StringTag.valueOf(this.resourceKey);
}
return toNbtInternal(nbt, allowReference);
}
protected NbtCompound toNbtInternal(NbtCompound nbt, boolean allowReference) {
protected CompoundTag toNbtInternal(CompoundTag nbt, boolean allowReference) {
this.getType().toNbt(nbt);
if (builderNbt != null) nbt.put("builder", builderNbt);
@ -174,28 +182,23 @@ public abstract class PocketGenerator implements Weighted<PocketGenerationContex
if (setupLoot != null) nbt.putBoolean("setup_loot", setupLoot);
NbtList modifiersNbt = new NbtList();
NbtList modifierReferences = new NbtList();
ListTag modifiersNbt = new ListTag();
ListTag modifierReferences = new ListTag();
for (Modifier modifier : modifierList) {
NbtElement modNbt = modifier.toNbt(new NbtCompound(), allowReference);
switch (modNbt.getType()) {
case NbtType.COMPOUND:
modifiersNbt.add(modNbt);
break;
case NbtType.STRING:
modifierReferences.add(modNbt);
break;
default:
throw new RuntimeException(String.format("Unexpected NbtType %d!", modNbt.getType()));
Tag modNbt = modifier.toNbt(new CompoundTag(), allowReference);
switch (modNbt.getId()) {
case Tag.TAG_COMPOUND -> modifiersNbt.add(modNbt);
case Tag.TAG_STRING -> modifierReferences.add(modNbt);
default -> throw new RuntimeException(String.format("Unexpected NbtType %d!", modNbt.getType()));
}
}
if (modifiersNbt.size() > 0) nbt.put("modifiers", modifiersNbt);
if (modifierReferences.size() > 0) nbt.put("modifier_references", modifierReferences);
if (tags.size() > 0) {
NbtList nbtList = new NbtList();
ListTag nbtList = new ListTag();
for (String nbtStr : tags) {
nbtList.add(NbtString.of(nbtStr));
nbtList.add(StringTag.valueOf(nbtStr));
}
nbt.put("tags", nbtList);
}
@ -203,7 +206,7 @@ public abstract class PocketGenerator implements Weighted<PocketGenerationContex
return nbt;
}
public NbtElement toNbt(NbtCompound nbt) {
public Tag toNbt(CompoundTag nbt) {
return toNbt(nbt, false);
}
@ -243,13 +246,13 @@ public abstract class PocketGenerator implements Weighted<PocketGenerationContex
}
public void setup(Pocket pocket, RiftManager manager, PocketGenerationContext parameters, boolean setupLootTables) {
ServerWorld world = parameters.world();
ServerLevel world = parameters.world();
if (!(pocket instanceof LazyGenerationPocket)) { // should not iterate over that which does not exist & area may be massive, getBlockEntities() might force generation
if (setupLootTables) // temp
pocket.getBlockEntities().forEach((blockPos, blockEntity) -> {
if (/*setupLootTables &&*/ blockEntity instanceof Inventory) { // comment in if needed
Inventory inventory = (Inventory) blockEntity;
if (/*setupLootTables &&*/ blockEntity instanceof Container) { // comment in if needed
Container inventory = (Container) blockEntity;
if (inventory.isEmpty()) {
if (blockEntity instanceof ChestBlockEntity || blockEntity instanceof DispenserBlockEntity) {
TemplateUtils.setupLootTable(world, blockEntity, inventory, LOGGER);
@ -261,7 +264,7 @@ public abstract class PocketGenerator implements Weighted<PocketGenerationContex
}
});
}
manager.getRifts().forEach(rift -> rift.getDestination().setLocation(new Location(world, rift.getPos())));
manager.getRifts().forEach(rift -> rift.getDestination().setLocation(new Location(world, rift.getBlockPos())));
TemplateUtils.registerRifts(manager.getRifts(), parameters.linkTo(), parameters.linkProperties(), pocket);
}
@ -302,27 +305,25 @@ public abstract class PocketGenerator implements Weighted<PocketGenerationContex
public abstract Vec3i getSize(PocketGenerationContext parameters);
public interface PocketGeneratorType<T extends PocketGenerator> {
PocketGeneratorType<SchematicGenerator> SCHEMATIC = register(DimensionalDoors.id(SchematicGenerator.KEY), SchematicGenerator::new);
PocketGeneratorType<ChunkGenerator> CHUNK = register(DimensionalDoors.id(ChunkGenerator.KEY), ChunkGenerator::new);
PocketGeneratorType<VoidGenerator> VOID = register(DimensionalDoors.id(VoidGenerator.KEY), VoidGenerator::new);
RegistrySupplier<PocketGeneratorType<PocketGenerator>> SCHEMATIC = register(DimensionalDoors.id(SchematicGenerator.KEY), SchematicGenerator::new);
RegistrySupplier<PocketGeneratorType<ChunkGenerator>> CHUNK = register(DimensionalDoors.id(ChunkGenerator.KEY), ChunkGenerator::new);
RegistrySupplier<PocketGeneratorType<VoidGenerator>> VOID = register(DimensionalDoors.id(VoidGenerator.KEY), VoidGenerator::new);
PocketGenerator fromNbt(NbtCompound nbt, ResourceManager manager);
PocketGenerator fromNbt(CompoundTag nbt, ResourceManager manager);
NbtCompound toNbt(NbtCompound nbt);
CompoundTag toNbt(CompoundTag nbt);
static void register() {
DimensionalDoors.apiSubscribers.forEach(d -> d.registerPocketGeneratorTypes(REGISTRY));
}
static void register() {}
static <U extends PocketGenerator> PocketGeneratorType<U> register(Identifier id, Supplier<U> constructor) {
return Registry.register(REGISTRY, id, new PocketGeneratorType<U>() {
static <U extends PocketGenerator> RegistrySupplier<PocketGeneratorType<U>> register(ResourceLocation id, Supplier<U> constructor) {
return REGISTRY.register(id, () -> new PocketGeneratorType<U>() {
@Override
public PocketGenerator fromNbt(NbtCompound nbt, ResourceManager manager) {
public PocketGenerator fromNbt(CompoundTag nbt, ResourceManager manager) {
return constructor.get().fromNbt(nbt, manager);
}
@Override
public NbtCompound toNbt(NbtCompound nbt) {
public CompoundTag toNbt(CompoundTag nbt) {
nbt.putString("type", id.toString());
return nbt;
}

View file

@ -5,6 +5,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.minecraft.nbt.CompoundTag;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -77,7 +78,7 @@ public class SchematicGenerator extends LazyPocketGenerator{
}
@Override
public PocketGenerator fromNbt(NbtCompound nbt, ResourceManager manager) {
public PocketGenerator fromNbt(CompoundTag nbt, ResourceManager manager) {
super.fromNbt(nbt, manager);
this.id = nbt.getString("id"); // TODO: should we force having the "dimdoors:" in the json?

View file

@ -3,6 +3,7 @@ package org.dimdev.dimdoors.pockets.generator;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.nbt.CompoundTag;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -53,7 +54,7 @@ public class VoidGenerator extends LazyPocketGenerator {
}
@Override
public PocketGenerator fromNbt(NbtCompound nbt, ResourceManager manager) {
public PocketGenerator fromNbt(CompoundTag nbt, ResourceManager manager) {
super.fromNbt(nbt, manager);
try {

View file

@ -1,78 +1,71 @@
package org.dimdev.dimdoors.pockets.modifier;
import java.util.Collection;
import java.util.function.Supplier;
import com.google.common.collect.Multimap;
import com.mojang.serialization.Lifecycle;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.SimpleRegistry;
import net.minecraft.resource.ResourceManager;
import net.minecraft.util.Identifier;
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
import net.fabricmc.fabric.api.util.NbtType;
import dev.architectury.registry.registries.Registrar;
import dev.architectury.registry.registries.RegistrarManager;
import dev.architectury.registry.registries.RegistrySupplier;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.packs.resources.ResourceManager;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.api.util.ReferenceSerializable;
import org.dimdev.dimdoors.api.util.ResourceUtil;
import org.dimdev.dimdoors.pockets.PocketGenerationContext;
import org.dimdev.dimdoors.world.pocket.type.Pocket;
import java.util.Collection;
import java.util.function.Supplier;
public interface Modifier extends ReferenceSerializable {
Registry<ModifierType<? extends Modifier>> REGISTRY = FabricRegistryBuilder.from(new SimpleRegistry<ModifierType<? extends Modifier>>(RegistryKey.ofRegistry(DimensionalDoors.id("modifier_type")), Lifecycle.stable(), false)).buildAndRegister();
Registrar<ModifierType<? extends Modifier>> REGISTRY = RegistrarManager.get(DimensionalDoors.MOD_ID).<ModifierType<? extends Modifier>>builder(DimensionalDoors.id("modifier_type")).build();
String RESOURCE_STARTING_PATH = "pockets/modifier"; //TODO: might want to restructure data packs
static Modifier deserialize(NbtElement nbt, ResourceManager manager) {
switch (nbt.getType()) {
case NbtType.COMPOUND: // It's a serialized Modifier
return Modifier.deserialize((NbtCompound) nbt, manager);
case NbtType.STRING: // It's a reference to a resource location
static Modifier deserialize(Tag nbt, ResourceManager manager) {
return switch (nbt.getId()) {
case Tag.TAG_COMPOUND -> // It's a serialized Modifier
Modifier.deserialize((CompoundTag) nbt, manager);
case Tag.TAG_STRING -> // It's a reference to a resource location
// TODO: throw if manager is null
return ResourceUtil.loadReferencedResource(manager, RESOURCE_STARTING_PATH, nbt.asString(), ResourceUtil.NBT_READER.andThenComposable(nbtElement -> deserialize(nbtElement, manager)));
default:
throw new RuntimeException(String.format("Unexpected NbtType %d!", nbt.getType()));
}
ResourceUtil.loadReferencedResource(manager, RESOURCE_STARTING_PATH, nbt.getAsString(), ResourceUtil.NBT_READER.andThenComposable(Tag -> deserialize(Tag, manager)));
default -> throw new RuntimeException(String.format("Unexpected NbtType %d!", nbt.getId()));
};
}
static Modifier deserialize(NbtElement nbt) {
static Modifier deserialize(Tag nbt) {
return deserialize(nbt, null);
}
static Modifier deserialize(NbtCompound nbt, ResourceManager manager) {
Identifier id = Identifier.tryParse(nbt.getString("type")); // TODO: return some NONE Modifier if type cannot be found or deserialization fails.
static Modifier deserialize(CompoundTag nbt, ResourceManager manager) {
ResourceLocation id = ResourceLocation.tryParse(nbt.getString("type")); // TODO: return some NONE Modifier if type cannot be found or deserialization fails.
return REGISTRY.get(id).fromNbt(nbt, manager);
}
static Modifier deserialize(NbtCompound nbt) {
static Modifier deserialize(CompoundTag nbt) {
return deserialize(nbt, null);
}
static NbtElement serialize(Modifier modifier, boolean allowReference) {
return modifier.toNbt(new NbtCompound(), allowReference);
static Tag serialize(Modifier modifier, boolean allowReference) {
return modifier.toNbt(new CompoundTag(), allowReference);
}
static NbtElement serialize(Modifier modifier) {
static Tag serialize(Modifier modifier) {
return serialize(modifier, false);
}
Modifier fromNbt(NbtCompound nbt, ResourceManager manager);
Modifier fromNbt(CompoundTag nbt, ResourceManager manager);
default Modifier fromNbt(NbtCompound nbt) {
default Modifier fromNbt(CompoundTag nbt) {
return fromNbt(nbt, null);
}
default NbtElement toNbt(NbtCompound nbt, boolean allowReference) {
default Tag toNbt(CompoundTag nbt, boolean allowReference) {
return this.getType().toNbt(nbt);
}
default NbtElement toNbt(NbtCompound nbt) {
default Tag toNbt(CompoundTag nbt) {
return toNbt(nbt, false);
}
@ -97,35 +90,33 @@ public interface Modifier extends ReferenceSerializable {
void apply(PocketGenerationContext parameters, Pocket.PocketBuilder<?, ?> builder);
interface ModifierType<T extends Modifier> {
ModifierType<ShellModifier> SHELL_MODIFIER_TYPE = register(DimensionalDoors.id(ShellModifier.KEY), ShellModifier::new);
ModifierType<DimensionalDoorModifier> DIMENSIONAL_DOOR_MODIFIER_TYPE = register(DimensionalDoors.id(DimensionalDoorModifier.KEY), DimensionalDoorModifier::new);
ModifierType<PocketEntranceModifier> PUBLIC_MODIFIER_TYPE = register(DimensionalDoors.id(PocketEntranceModifier.KEY), PocketEntranceModifier::new);
ModifierType<RiftDataModifier> RIFT_DATA_MODIFIER_TYPE = register(DimensionalDoors.id(RiftDataModifier.KEY), RiftDataModifier::new);
ModifierType<RelativeReferenceModifier> RELATIVE_REFERENCE_MODIFIER_TYPE = register(DimensionalDoors.id(RelativeReferenceModifier.KEY), RelativeReferenceModifier::new);
ModifierType<OffsetModifier> OFFSET_MODIFIER_TYPE = register(DimensionalDoors.id(OffsetModifier.KEY), OffsetModifier::new);
ModifierType<AbsoluteRiftBlockEntityModifier> ABSOLUTE_RIFT_BLOCK_ENTITY_MODIFIER_TYPE = register(DimensionalDoors.id(AbsoluteRiftBlockEntityModifier.KEY), AbsoluteRiftBlockEntityModifier::new);
RegistrySupplier<ModifierType<ShellModifier>> SHELL_MODIFIER_TYPE = register(DimensionalDoors.id(ShellModifier.KEY), ShellModifier::new);
RegistrySupplier<ModifierType<DimensionalDoorModifier>> DIMENSIONAL_DOOR_MODIFIER_TYPE = register(DimensionalDoors.id(DimensionalDoorModifier.KEY), DimensionalDoorModifier::new);
RegistrySupplier<ModifierType<Modifier>> PUBLIC_MODIFIER_TYPE = register(DimensionalDoors.id(PocketEntranceModifier.KEY), PocketEntranceModifier::new);
RegistrySupplier<ModifierType<RiftDataModifier>> RIFT_DATA_MODIFIER_TYPE = register(DimensionalDoors.id(RiftDataModifier.KEY), RiftDataModifier::new);
RegistrySupplier<ModifierType<RelativeReferenceModifier>> RELATIVE_REFERENCE_MODIFIER_TYPE = register(DimensionalDoors.id(RelativeReferenceModifier.KEY), RelativeReferenceModifier::new);
RegistrySupplier<ModifierType<OffsetModifier>> OFFSET_MODIFIER_TYPE = register(DimensionalDoors.id(OffsetModifier.KEY), OffsetModifier::new);
RegistrySupplier<ModifierType<Modifier>> ABSOLUTE_RIFT_BLOCK_ENTITY_MODIFIER_TYPE = register(DimensionalDoors.id(AbsoluteRiftBlockEntityModifier.KEY), AbsoluteRiftBlockEntityModifier::new);
Modifier fromNbt(NbtCompound nbt, ResourceManager manager);
Modifier fromNbt(CompoundTag nbt, ResourceManager manager);
default Modifier fromNbt(NbtCompound nbt) {
default Modifier fromNbt(CompoundTag nbt) {
return fromNbt(nbt, null);
}
NbtCompound toNbt(NbtCompound nbt);
CompoundTag toNbt(CompoundTag nbt);
static void register() {
DimensionalDoors.apiSubscribers.forEach(d -> d.registerModifierTypes(REGISTRY));
}
static void register() {}
static <U extends Modifier> ModifierType<U> register(Identifier id, Supplier<U> factory) {
return Registry.register(REGISTRY, id, new ModifierType<U>() {
static <U extends Modifier> RegistrySupplier<ModifierType<U>> register(ResourceLocation id, Supplier<U> factory) {
return REGISTRY.register(id, () -> new ModifierType<U>() {
@Override
public Modifier fromNbt(NbtCompound nbt, ResourceManager manager) {
public Modifier fromNbt(CompoundTag nbt, ResourceManager manager) {
return factory.get().fromNbt(nbt, manager);
}
@Override
public NbtCompound toNbt(NbtCompound nbt) {
public CompoundTag toNbt(CompoundTag nbt) {
nbt.putString("type", id.toString());
return nbt;
}

View file

@ -1,8 +1,10 @@
package org.dimdev.dimdoors.pockets.virtual;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.nbt.NbtString;
import net.minecraft.nbt.Tag;
public abstract class AbstractVirtualPocket implements ImplementedVirtualPocket {
private String resourceKey = null;
@ -18,7 +20,7 @@ public abstract class AbstractVirtualPocket implements ImplementedVirtualPocket
}
@Override
public NbtElement toNbt(NbtCompound nbt, boolean allowReference) {
public Tag toNbt(CompoundTag nbt, boolean allowReference) {
if (allowReference && this.getResourceKey() != null) {
return NbtString.of(this.getResourceKey());
}
@ -28,7 +30,7 @@ public abstract class AbstractVirtualPocket implements ImplementedVirtualPocket
// utility so the first part of toNbt can be extracted into default method
// at this point we know for a fact, that we need to serialize into the NbtCompound
// overwrite in subclass
protected NbtCompound toNbtInternal(NbtCompound nbt, boolean allowReference) {
protected CompoundTag toNbtInternal(CompoundTag nbt, boolean allowReference) {
return this.getType().toNbt(nbt);
}
}

View file

@ -3,6 +3,7 @@ package org.dimdev.dimdoors.pockets.virtual;
import java.util.function.Supplier;
import com.mojang.serialization.Lifecycle;
import net.minecraft.nbt.CompoundTag;
import org.jetbrains.annotations.Nullable;
import net.minecraft.nbt.NbtCompound;
@ -32,10 +33,10 @@ public interface ImplementedVirtualPocket extends VirtualPocket {
Registry<VirtualPocketType<? extends ImplementedVirtualPocket>> REGISTRY = FabricRegistryBuilder.from(new SimpleRegistry<VirtualPocketType<? extends ImplementedVirtualPocket>>(RegistryKey.ofRegistry(DimensionalDoors.id("virtual_pocket_type")), Lifecycle.stable(), false)).buildAndRegister();
static ImplementedVirtualPocket deserialize(NbtElement nbt, @Nullable ResourceManager manager) {
return switch (nbt.getType()) {
return switch (nbt.getId()) {
case NbtType.COMPOUND -> deserialize((NbtCompound) nbt, manager);
case NbtType.STRING -> ResourceUtil.loadReferencedResource(manager, RESOURCE_STARTING_PATH, nbt.asString(), ResourceUtil.NBT_READER.andThenComposable(nbtElement -> deserialize(nbtElement, manager)));
default -> throw new RuntimeException(String.format("Unexpected NbtType %d!", nbt.getType()));
default -> throw new RuntimeException(String.format("Unexpected NbtType %d!", nbt.getId()));
};
}
@ -84,7 +85,7 @@ public interface ImplementedVirtualPocket extends VirtualPocket {
VirtualPocketType<ConditionalSelector> CONDITIONAL_SELECTOR = register(DimensionalDoors.id(ConditionalSelector.KEY), ConditionalSelector::new);
VirtualPocketType<PathSelector> PATH_SELECTOR = register(DimensionalDoors.id(PathSelector.KEY), PathSelector::new);
ImplementedVirtualPocket fromNbt(NbtCompound nbt, @Nullable ResourceManager manager);
ImplementedVirtualPocket fromNbt(CompoundTag nbt, @Nullable ResourceManager manager);
default ImplementedVirtualPocket fromNbt(NbtCompound nbt) {
return fromNbt(nbt, null);

View file

@ -29,7 +29,7 @@ public interface VirtualPocket extends Weighted<PocketGenerationContext>, Refere
//TODO: split up in ImplementedVirtualPocket and VirtualPocketList
static VirtualPocket deserialize(NbtElement nbt, @Nullable ResourceManager manager) {
switch (nbt.getType()) {
switch (nbt.getId()) {
case NbtType.LIST: // It's a list of VirtualPocket
return VirtualPocketList.deserialize((NbtList) nbt, manager);
case NbtType.COMPOUND: // It's a serialized VirtualPocket
@ -38,7 +38,7 @@ public interface VirtualPocket extends Weighted<PocketGenerationContext>, Refere
case NbtType.STRING: // It's a reference to a resource location
return ResourceUtil.loadReferencedResource(manager, RESOURCE_STARTING_PATH, nbt.asString(), ResourceUtil.NBT_READER.andThenComposable(nbtElement -> deserialize(nbtElement, manager)));
default:
throw new RuntimeException(String.format("Unexpected NbtType %d!", nbt.getType()));
throw new RuntimeException(String.format("Unexpected NbtType %d!", nbt.getId()));
}
}

View file

@ -19,13 +19,13 @@ public class VirtualPocketList extends WeightedList<VirtualPocket, PocketGenerat
private String resourceKey = null;
public static VirtualPocketList deserialize(NbtElement nbt, @Nullable ResourceManager manager) {
switch (nbt.getType()) {
switch (nbt.getId()) {
case NbtType.LIST:
return deserialize((NbtList) nbt, manager);
case NbtType.STRING:
return ResourceUtil.loadReferencedResource(manager, RESOURCE_STARTING_PATH, nbt.asString(), ResourceUtil.NBT_READER.andThenComposable(nbtElement -> deserialize(nbtElement, manager)));
default:
throw new RuntimeException(String.format("Unexpected NbtType %d!", nbt.getType()));
throw new RuntimeException(String.format("Unexpected NbtType %d!", nbt.getId()));
}
}

View file

@ -4,12 +4,9 @@ import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import com.mojang.serialization.Lifecycle;
import dev.architectury.registry.registries.DeferredRegister;
import dev.architectury.registry.registries.Registrar;
import dev.architectury.registry.registries.RegistrarManager;
import dev.architectury.registry.registries.RegistrySupplier;
import dev.architectury.registry.registries.options.RegistrarOption;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.minecraft.nbt.CompoundTag;
@ -128,12 +125,10 @@ public abstract class VirtualTarget implements Target {
});
}
static void register() {
DimensionalDoors.apiSubscribers.forEach(d -> d.registerVirtualTargetTypes(REGISTRY));
}
static void register() {}
@SuppressWarnings("unchecked")
static <T extends VirtualTarget> VirtualTargetType<T> register(String id, Function<CompoundTag, T> fromNbt, Function<T, CompoundTag> toNbt, RGBA color) {
static <T extends VirtualTarget> RegistrySupplier<VirtualTargetType<T>> register(String id, Function<CompoundTag, T> fromNbt, Function<T, CompoundTag> toNbt, RGBA color) {
return REGISTRY.register(new ResourceLocation(id), () -> new VirtualTargetType<T>() {
@Override
public T fromNbt(CompoundTag nbt) {

View file

@ -0,0 +1,21 @@
package org.dimdev.dimdoors.world;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.world.biome.Biome;
import static org.dimdev.dimdoors.DimensionalDoors.id;
public final class ModBiomes {
public static final RegistryKey<Biome> PERSONAL_WHITE_VOID_KEY = register("white_void");
public static final RegistryKey<Biome> PUBLIC_BLACK_VOID_KEY = register("black_void");
public static final RegistryKey<Biome> DUNGEON_DANGEROUS_BLACK_VOID_KEY = register("dangerous_black_void");
public static final RegistryKey<Biome> LIMBO_KEY = register("limbo");
public static void init() {
}
private static RegistryKey<Biome> register(String name) {
return RegistryKey.of(RegistryKeys.BIOME, id(name));
}
}

View file

@ -0,0 +1,59 @@
package org.dimdev.dimdoors.world;
import dev.architectury.event.events.common.LifecycleEvent;
import dev.architectury.registry.registries.DeferredRegister;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.dimension.DimensionType;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.world.pocket.BlankChunkGenerator;
import java.util.Objects;
public final class ModDimensions {
public static final ResourceKey<Level> LIMBO = ResourceKey.create(Registries.DIMENSION, DimensionalDoors.id("limbo"));
public static final ResourceKey<Level> PERSONAL = ResourceKey.create(Registries.DIMENSION, DimensionalDoors.id("personal_pockets"));
public static final ResourceKey<Level> PUBLIC = ResourceKey.create(Registries.DIMENSION, DimensionalDoors.id("public_pockets"));
public static final ResourceKey<Level> DUNGEON = ResourceKey.create(Registries.DIMENSION, DimensionalDoors.id("dungeon_pockets"));
public static final ResourceKey<DimensionType> LIMBO_TYPE_KEY = ResourceKey.create(Registries.DIMENSION_TYPE, DimensionalDoors.id("limbo"));
public static final ResourceKey<DimensionType> POCKET_TYPE_KEY = ResourceKey.create(Registries.DIMENSION_TYPE, DimensionalDoors.id("personal_pockets"));
public static DimensionType LIMBO_TYPE;
public static DimensionType POCKET_TYPE;
public static ServerLevel LIMBO_DIMENSION;
public static ServerLevel PERSONAL_POCKET_DIMENSION;
public static ServerLevel PUBLIC_POCKET_DIMENSION;
public static ServerLevel DUNGEON_POCKET_DIMENSION;
public static boolean isPocketDimension(Level world) {
return isPocketDimension(world.dimension());
}
public static boolean isPrivatePocketDimension(Level world) {
return world != null && world == PERSONAL_POCKET_DIMENSION;
}
public static boolean isPocketDimension(ResourceKey<Level> type) {
return Objects.equals(type, PERSONAL) || Objects.equals(type, PUBLIC) || Objects.equals(type, DUNGEON);
}
public static boolean isLimboDimension(Level world) {
return world != null && world.dimension().equals(LIMBO);
}
public static void init() {
LifecycleEvent.SERVER_STARTED.register(server -> {
ModDimensions.LIMBO_TYPE = server.registryAccess().registryOrThrow(Registries.DIMENSION_TYPE).get(LIMBO_TYPE_KEY);
ModDimensions.POCKET_TYPE = server.registryAccess().registryOrThrow(Registries.DIMENSION_TYPE).get(POCKET_TYPE_KEY);
ModDimensions.LIMBO_DIMENSION = server.getLevel(LIMBO);
ModDimensions.PERSONAL_POCKET_DIMENSION = server.getLevel(PERSONAL);
ModDimensions.PUBLIC_POCKET_DIMENSION = server.getLevel(PUBLIC);
ModDimensions.DUNGEON_POCKET_DIMENSION = server.getLevel(DUNGEON);
});
DeferredRegister.create(DimensionalDoors.MOD_ID, Registries.CHUNK_GENERATOR).register("blank", () -> BlankChunkGenerator.CODEC);
}
}

View file

@ -0,0 +1,79 @@
package org.dimdev.dimdoors.world.decay;
import java.util.Set;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
public class DecayPattern {
public static final Event<EntropyEvent> ENTROPY_EVENT = EventFactory.createArrayBacked(EntropyEvent.class, (world, pos, entorpy) -> {}, entropyEvents -> (world, pos, entorpy) -> {
for (EntropyEvent event : entropyEvents) event.entropy(world, pos, entorpy);
});
private DecayPredicate predicate;
private DecayProcessor processor;
public DecayPattern() {}
public DecayPattern(DecayPredicate predicate, DecayProcessor processor) {
this.predicate = predicate;
this.processor = processor;
}
public static DecayPattern deserialize(NbtCompound nbt) {
DecayPredicate predicate = DecayPredicate.deserialize(nbt.getCompound("predicate"));
DecayProcessor processor = DecayProcessor.deserialize(nbt.getCompound("processor"));
return DecayPattern.builder().predicate(predicate).processor(processor).create();
}
public boolean test(World world, BlockPos pos, BlockState origin, BlockState targetBlock, FluidState targetFluid) {
return predicate.test(world, pos, origin, targetBlock, targetFluid);
}
public void process(World world, BlockPos pos, BlockState origin, BlockState targetBlock, FluidState targetFluid) {
ENTROPY_EVENT.invoker().entropy(world, pos, processor.process(world, pos, origin, targetBlock, targetFluid));
}
public Set<Block> constructApplicableBlocks() {
return predicate.constructApplicableBlocks();
}
public Set<Fluid> constructApplicableFluids() {
return predicate.constructApplicableFluids();
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private DecayPredicate predicate = DecayPredicate.NONE;
private DecayProcessor processor = DecayProcessor.NONE;
public Builder predicate(DecayPredicate predicate) {
this.predicate = predicate;
return this;
}
public Builder processor(DecayProcessor processor) {
this.processor = processor;
return this;
}
public DecayPattern create() {
return new DecayPattern(predicate, processor);
}
}
private interface EntropyEvent {
void entropy(World world, BlockPos pos, int entorpy);
}
}

View file

@ -0,0 +1,111 @@
package org.dimdev.dimdoors.world.decay;
import java.util.Set;
import java.util.function.Supplier;
import com.mojang.serialization.Lifecycle;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.SimpleRegistry;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.datagen.FluidDecayPredicate;
import org.dimdev.dimdoors.world.decay.predicates.SimpleDecayPredicate;
public interface DecayPredicate {
Registry<DecayPredicateType<? extends DecayPredicate>> REGISTRY = FabricRegistryBuilder.from(new SimpleRegistry<DecayPredicateType<? extends DecayPredicate>>(RegistryKey.ofRegistry(DimensionalDoors.id("decay_predicate_type")), Lifecycle.stable(), false)).buildAndRegister();
DecayPredicate NONE = new DecayPredicate() {
private static final String ID = "none";
@Override
public DecayPredicate fromNbt(NbtCompound nbt) {
return this;
}
@Override
public DecayPredicateType<? extends DecayPredicate> getType() {
return DecayPredicateType.NONE_PREDICATE_TYPE;
}
@Override
public String getKey() {
return ID;
}
@Override
public boolean test(World world, BlockPos pos, BlockState origin, BlockState targetBlock, FluidState targetFluid) {
return false;
}
};
static DecayPredicate deserialize(NbtCompound nbt) {
Identifier id = Identifier.tryParse(nbt.getString("type"));
return REGISTRY.getOrEmpty(id).orElse(DecayPredicateType.NONE_PREDICATE_TYPE).fromNbt(nbt);
}
static NbtCompound serialize(DecayPredicate modifier) {
return modifier.toNbt(new NbtCompound());
}
DecayPredicate fromNbt(NbtCompound nbt);
default NbtCompound toNbt(NbtCompound nbt) {
return this.getType().toNbt(nbt);
}
DecayPredicateType<? extends DecayPredicate> getType();
String getKey();
boolean test(World world, BlockPos pos, BlockState origin, BlockState targetBlock, FluidState targetFluid);
default Set<Fluid> constructApplicableFluids() {
return Set.of();
}
default Set<Block> constructApplicableBlocks() {
return Set.of();
}
interface DecayPredicateType<T extends DecayPredicate> {
DecayPredicateType<DecayPredicate> NONE_PREDICATE_TYPE = register(DimensionalDoors.id("none"), () -> NONE);
DecayPredicateType<SimpleDecayPredicate> SIMPLE_PREDICATE_TYPE = register(DimensionalDoors.id(SimpleDecayPredicate.KEY), SimpleDecayPredicate::new);
DecayPredicateType<FluidDecayPredicate> FLUID_PREDICATE_TYPE = register(DimensionalDoors.id(FluidDecayPredicate.KEY), FluidDecayPredicate::new);
DecayPredicate fromNbt(NbtCompound nbt);
NbtCompound toNbt(NbtCompound nbt);
static void register() {
DimensionalDoors.apiSubscribers.forEach(d -> d.registerDecayPredicates(REGISTRY));
}
static <U extends DecayPredicate> DecayPredicateType<U> register(Identifier id, Supplier<U> factory) {
return Registry.register(REGISTRY, id, new DecayPredicateType<U>() {
@Override
public DecayPredicate fromNbt(NbtCompound nbt) {
return factory.get().fromNbt(nbt);
}
@Override
public NbtCompound toNbt(NbtCompound nbt) {
nbt.putString("type", id.toString());
return nbt;
}
});
}
}
}

View file

@ -0,0 +1,106 @@
package org.dimdev.dimdoors.world.decay;
import java.util.function.Supplier;
import com.mojang.serialization.Lifecycle;
import net.minecraft.block.BlockState;
import net.minecraft.fluid.FluidState;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.SimpleRegistry;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.datagen.FluidDecayProcessor;
import org.dimdev.dimdoors.world.decay.processors.DoorDecayProccessor;
import org.dimdev.dimdoors.world.decay.processors.DoubleDecayProcessor;
import org.dimdev.dimdoors.world.decay.processors.SelfDecayProcessor;
import org.dimdev.dimdoors.world.decay.processors.BlockDecayProcessor;
public interface DecayProcessor {
Registry<DecayProcessorType<? extends DecayProcessor>> REGISTRY = FabricRegistryBuilder.from(new SimpleRegistry<DecayProcessorType<? extends DecayProcessor>>(RegistryKey.ofRegistry(DimensionalDoors.id("decay_processor_type")), Lifecycle.stable(), false)).buildAndRegister();
DecayProcessor NONE = new DecayProcessor() {
@Override
public DecayProcessor fromNbt(NbtCompound nbt) {
return this;
}
@Override
public DecayProcessorType<? extends DecayProcessor> getType() {
return DecayProcessorType.NONE_PROCESSOR_TYPE;
}
@Override
public String getKey() {
return ID;
}
@Override
public int process(World world, BlockPos pos, BlockState origin, BlockState targetBlock, FluidState targetFluid) {
return 0;
}
private static final String ID = "none";
};
static DecayProcessor deserialize(NbtCompound nbt) {
Identifier id = Identifier.tryParse(nbt.getString("type"));
return REGISTRY.getOrEmpty(id).orElse(DecayProcessorType.NONE_PROCESSOR_TYPE).fromNbt(nbt);
}
static NbtCompound serialize(DecayProcessor modifier) {
return modifier.toNbt(new NbtCompound());
}
DecayProcessor fromNbt(NbtCompound nbt);
default NbtCompound toNbt(NbtCompound nbt) {
return this.getType().toNbt(nbt);
}
DecayProcessorType<? extends DecayProcessor> getType();
String getKey();
int process(World world, BlockPos pos, BlockState origin, BlockState targetState, FluidState targetFluid);
interface DecayProcessorType<T extends DecayProcessor> {
DecayProcessorType<BlockDecayProcessor> SIMPLE_PROCESSOR_TYPE = register(DimensionalDoors.id(BlockDecayProcessor.KEY), BlockDecayProcessor::new);
DecayProcessorType<DecayProcessor> NONE_PROCESSOR_TYPE = register(DimensionalDoors.id("none"), () -> NONE);
DecayProcessorType<SelfDecayProcessor> SELF = register(DimensionalDoors.id(SelfDecayProcessor.KEY), SelfDecayProcessor::instance);
DecayProcessorType<DoorDecayProccessor> DOOR_PROCESSOR_TYPE = register(DimensionalDoors.id(DoorDecayProccessor.KEY), DoorDecayProccessor::new);
DecayProcessorType<DoubleDecayProcessor> DOUBLE_PROCESSOR_TYPE = register(DimensionalDoors.id(DoubleDecayProcessor.KEY), DoubleDecayProcessor::new);
DecayProcessorType<FluidDecayProcessor> FLUID_PROCESSOR_TYPE = register(DimensionalDoors.id(FluidDecayProcessor.KEY), FluidDecayProcessor::new);
DecayProcessor fromNbt(NbtCompound nbt);
NbtCompound toNbt(NbtCompound nbt);
static void register() {
DimensionalDoors.apiSubscribers.forEach(d -> d.registerDecayProcessors(REGISTRY));
}
static <U extends DecayProcessor> DecayProcessorType<U> register(Identifier id, Supplier<U> factory) {
return Registry.register(REGISTRY, id, new DecayProcessorType<U>() {
@Override
public DecayProcessor fromNbt(NbtCompound nbt) {
return factory.get().fromNbt(nbt);
}
@Override
public NbtCompound toNbt(NbtCompound nbt) {
nbt.putString("type", id.toString());
return nbt;
}
});
}
}
}

View file

@ -0,0 +1,198 @@
package org.dimdev.dimdoors.world.decay;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.FluidState;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.registry.RegistryKey;
import net.minecraft.resource.ResourceManager;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.random.Random;
import net.minecraft.world.World;
import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.api.util.ResourceUtil;
import org.dimdev.dimdoors.network.ExtendedServerPlayNetworkHandler;
import org.dimdev.dimdoors.network.packet.s2c.RenderBreakBlockS2CPacket;
import org.dimdev.dimdoors.sound.ModSoundEvents;
/**
* Provides methods for applying Limbo decay. Limbo decay refers to the effect that most blocks placed in Limbo
* naturally change into stone, then cobble, then gravel, and finally Unraveled Fabric as time passes.
*/
public final class LimboDecay {
private static final Logger LOGGER = LogManager.getLogger();
private static final Map<RegistryKey<World>, Set<DecayTask>> DECAY_QUEUE = new HashMap<>();
private static final Random RANDOM = Random.create();
/**
* Checks the blocks orthogonally around a given location (presumably the location of an Unraveled Fabric block)
* and applies Limbo decay to them. This gives the impression that decay spreads outward from Unraveled Fabric.
*/
public static void applySpreadDecay(ServerWorld world, BlockPos pos) {
//Check if we randomly apply decay spread or not. This can be used to moderate the frequency of
//full spread decay checks, which can also shift its performance impact on the game.
if (RANDOM.nextDouble() < DimensionalDoors.getConfig().getLimboConfig().decaySpreadChance) {
BlockState origin = world.getBlockState(pos);
//Apply decay to the blocks above, below, and on all four sides.
// TODO: make max amount configurable
int decayAmount = RANDOM.nextInt(5) + 1;
List<Direction> directions = new ArrayList<>(Arrays.asList(Direction.values()));
for (int i = 0; i < decayAmount; i++) {
decayBlock(world, pos.offset(directions.remove(RANDOM.nextInt(5 - i))), origin);
}
}
}
/**
* Checks if a block can be decayed and, if so, changes it to the next block ID along the decay sequence.
*/
public static void decayBlock(ServerWorld world, BlockPos pos, BlockState origin) {
BlockState targetState = world.getBlockState(pos);
FluidState fluidState = world.getFluidState(pos);
Collection<DecayPattern> patterns = DecayLoader.getInstance().getPatterns(targetState.getBlock());
if(patterns.isEmpty()) patterns = DecayLoader.getInstance().getPatterns(fluidState.getFluid());
if(patterns.isEmpty()) {
return;
}
for(DecayPattern pattern : patterns) {
if (!pattern.test(world, pos, origin, targetState, fluidState)) {
continue;
}
world.getPlayers(EntityPredicates.maxDistance(pos.getX(), pos.getY(), pos.getZ(), 100)).forEach(player -> {
ExtendedServerPlayNetworkHandler.get(player.networkHandler).getDimDoorsPacketHandler().sendPacket(new RenderBreakBlockS2CPacket(pos, 5));
});
world.playSound(null, pos.getX(), pos.getY(), pos.getZ(), ModSoundEvents.TEARING, SoundCategory.BLOCKS, 0.5f, 1f);
queueDecay(world, pos, origin, pattern, DimensionalDoors.getConfig().getLimboConfig().limboDecay);
break;
}
}
public static void queueDecay(ServerWorld world, BlockPos pos, BlockState origin, DecayPattern pattern, int delay) {
DecayTask task = new DecayTask(pos, origin, pattern, delay);
if (delay <= 0) {
task.process(world);
} else {
DECAY_QUEUE.computeIfAbsent(world.getRegistryKey(), k -> new HashSet<>()).add(task);
}
}
public static void tick(ServerWorld world) {
RegistryKey<World> key = world.getRegistryKey();
if (DECAY_QUEUE.containsKey(key)) {
Set<DecayTask> tasks = DECAY_QUEUE.get(key);
Set<DecayTask> tasksToRun = tasks.stream().filter(DecayTask::reduceDelayIsDone).collect(Collectors.toSet());
tasks.removeAll(tasksToRun);
tasksToRun.forEach(task -> task.process(world));
}
}
public static class DecayLoader implements SimpleSynchronousResourceReloadListener {
private static final Logger LOGGER = LogManager.getLogger();
private static final DecayLoader INSTANCE = new DecayLoader();
private final Map<Block, List<DecayPattern>> blockPatterns = new HashMap<>();
private final Map<Fluid, List<DecayPattern>> fluidPatterns = new HashMap<>();
private DecayLoader() {
}
public static DecayLoader getInstance() {
return INSTANCE;
}
@Override
public void reload(ResourceManager manager) {
blockPatterns.clear();
CompletableFuture<List<DecayPattern>> futurePatternList = ResourceUtil.loadResourcePathToCollection(manager, "decay_patterns", ".json", new ArrayList<>(), ResourceUtil.NBT_READER.andThenReader(this::loadPattern));
for (DecayPattern pattern : futurePatternList.join()) {
for (Block block : pattern.constructApplicableBlocks()) {
blockPatterns.computeIfAbsent(block, (b) -> new ArrayList<>());
blockPatterns.get(block).add(pattern);
}
for (Fluid fluid : pattern.constructApplicableFluids()) {
fluidPatterns.computeIfAbsent(fluid, (b) -> new ArrayList<>());
fluidPatterns.get(fluid).add(pattern);
}
}
}
private DecayPattern loadPattern(NbtElement nbt, Identifier ignored) {
return DecayPattern.deserialize((NbtCompound) nbt);
}
public Collection<DecayPattern> getPatterns(Block block) {
return blockPatterns.getOrDefault(block, new ArrayList<>());
}
public Collection<DecayPattern> getPatterns(Fluid fluid) {
return fluidPatterns.getOrDefault(fluid, new ArrayList<>());
}
@Override
public Identifier getFabricId() {
return DimensionalDoors.id("decay_pattern");
}
}
private static class DecayTask {
private final BlockPos pos;
private final BlockState origin;
private final DecayPattern processor;
private int delay;
public DecayTask(BlockPos pos, BlockState origin, DecayPattern processor, int delay) {
this.pos = pos;
this.origin = origin;
this.processor = processor;
this.delay = delay;
}
public boolean reduceDelayIsDone() {
return --delay <= 0;
}
public void process(ServerWorld world) {
BlockState targetBlock = world.getBlockState(pos);
FluidState targetFluid = world.getFluidState(pos);
if (world.isChunkLoaded(pos) && processor.test(world, pos, origin, targetBlock, targetFluid)) {
world.getPlayers(EntityPredicates.maxDistance(pos.getX(), pos.getY(), pos.getZ(), 100)).forEach(player -> {
ExtendedServerPlayNetworkHandler.get(player.networkHandler).getDimDoorsPacketHandler().sendPacket(new RenderBreakBlockS2CPacket(pos, -1));
});
world.playSound(null, pos.getX(), pos.getY(), pos.getZ(), targetBlock.getSoundGroup().getBreakSound(), SoundCategory.BLOCKS, 0.5f, 1f);
processor.process(world, pos, origin, targetBlock, targetFluid);
}
}
}
}

View file

@ -0,0 +1,93 @@
package org.dimdev.dimdoors.world.decay.predicates;
import java.util.Set;
import java.util.stream.Collectors;
import com.google.common.collect.Streams;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.fluid.FluidState;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.Registries;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.dimdev.dimdoors.world.decay.DecayPredicate;
public class SimpleDecayPredicate implements DecayPredicate {
public static final String KEY = "block";
private Block block;
private TagKey<Block> tag;
public SimpleDecayPredicate() {}
public SimpleDecayPredicate(TagKey<Block> tag, Block block) {
this.tag = tag;
this.block = block;
}
@Override
public DecayPredicate fromNbt(NbtCompound nbt) {
String name = nbt.getString("entry");
if(name.startsWith("#")) tag = TagKey.of(RegistryKeys.BLOCK, Identifier.tryParse(name.substring(1)));
else block = Registries.BLOCK.get(Identifier.tryParse(name));
return this;
}
@Override
public NbtCompound toNbt(NbtCompound nbt) {
DecayPredicate.super.toNbt(nbt);
nbt.putString("entry", tag != null ? "#" + tag.id().toString() : Registries.BLOCK.getId(block).toString());
return nbt;
}
@Override
public DecayPredicateType<? extends DecayPredicate> getType() {
return DecayPredicateType.SIMPLE_PREDICATE_TYPE;
}
@Override
public String getKey() {
return KEY;
}
@Override
public boolean test(World world, BlockPos pos, BlockState origin, BlockState targetBlock, FluidState targetFluid) {
return block != null ? targetBlock.isOf(block) : targetBlock.isIn(tag);
}
@Override
public Set<Block> constructApplicableBlocks() {
return block != null ? Set.of(block) : Streams.stream(Registries.BLOCK.iterateEntries(tag)).map(RegistryEntry::value).collect(Collectors.toSet());
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private Block block;
private TagKey<Block> tag;
public Builder block(Block block) {
this.block = block;
return this;
}
public Builder tag(TagKey<Block> tag) {
this.tag = tag;
return this;
}
public SimpleDecayPredicate create() {
return new SimpleDecayPredicate(tag, block);
}
}
}

View file

@ -0,0 +1,100 @@
package org.dimdev.dimdoors.world.decay.processors;
import java.util.Set;
import java.util.stream.Collectors;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.TallPlantBlock;
import net.minecraft.block.enums.DoubleBlockHalf;
import net.minecraft.fluid.FluidState;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.Registries;
import net.minecraft.state.property.Property;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.dimdev.dimdoors.world.decay.DecayProcessor;
public class BlockDecayProcessor implements DecayProcessor {
public static final String KEY = "block";
protected Block block;
protected int entropy;
public BlockDecayProcessor() {}
protected BlockDecayProcessor(Block block, int entropy) {
this.block = block;
this.entropy = entropy;
}
@Override
public DecayProcessor fromNbt(NbtCompound json) {
block = Registries.BLOCK.get(Identifier.tryParse(json.getString("block")));
entropy = json.getInt("entropy");
return this;
}
@Override
public NbtCompound toNbt(NbtCompound nbt) {
DecayProcessor.super.toNbt(nbt);
nbt.putString("block", Registries.BLOCK.getId(block).toString());
nbt.putInt("entropy", entropy);
return nbt;
}
@Override
public DecayProcessorType<? extends DecayProcessor> getType() {
return DecayProcessorType.SIMPLE_PROCESSOR_TYPE;
}
@Override
public String getKey() {
return KEY;
}
@Override
public int process(World world, BlockPos pos, BlockState origin, BlockState target, FluidState targetFluid) {
BlockState newState = block.getDefaultState();
if(target.getBlock() instanceof TallPlantBlock) pos = target.get(TallPlantBlock.HALF) == DoubleBlockHalf.UPPER ? pos.down() : pos;
Set<Property<?>> commonProperties = target.getProperties().stream().filter(newState.getProperties()::contains).collect(Collectors.toSet());
for(Property<?> property : commonProperties) {
newState = transferProperty(target, newState, property);
}
world.setBlockState(pos, newState);
return entropy;
}
private static <T extends Comparable<T>> BlockState transferProperty(BlockState from, BlockState to, Property<T> property) {
return to.with(property, from.get(property));
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private Block block = Blocks.AIR;
private int entropy;
public Builder block(Block block) {
this.block = block;
return this;
}
public Builder entropy(int entropy) {
this.entropy = entropy;
return this;
}
public BlockDecayProcessor create() {
return new BlockDecayProcessor(block, entropy);
}
}
}

View file

@ -0,0 +1,101 @@
package org.dimdev.dimdoors.world.decay.processors;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.DoorBlock;
import net.minecraft.block.TrapdoorBlock;
import net.minecraft.block.enums.DoorHinge;
import net.minecraft.block.enums.DoubleBlockHalf;
import net.minecraft.fluid.FluidState;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.Registries;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import org.dimdev.dimdoors.world.decay.DecayProcessor;
public class DoorDecayProccessor implements DecayProcessor {
public static final String KEY = "door";
protected Block block;
protected int entropy;
public DoorDecayProccessor() {}
protected DoorDecayProccessor(Block block, int entropy) {
this.block = block;
this.entropy = entropy;
}
@Override
public DecayProcessor fromNbt(NbtCompound json) {
block = Registries.BLOCK.get(Identifier.tryParse(json.getString("block")));
entropy = json.getInt("entropy");
return this;
}
@Override
public NbtCompound toNbt(NbtCompound nbt) {
DecayProcessor.super.toNbt(nbt);
nbt.putString("block", Registries.BLOCK.getId(block).toString());
nbt.putInt("entropy", entropy);
return nbt;
}
@Override
public DecayProcessorType<? extends DecayProcessor> getType() {
return DecayProcessorType.DOOR_PROCESSOR_TYPE;
}
@Override
public String getKey() {
return null;
}
@Override
public int process(World world, BlockPos pos, BlockState origin, BlockState target, FluidState targetFluid) {
if(target.getBlock() instanceof DoorBlock) {
BlockPos otherPos = target.get(DoorBlock.HALF) == DoubleBlockHalf.UPPER ? pos.down() : pos.up();
Direction facing = target.get(DoorBlock.FACING);
if(target.get(DoorBlock.OPEN)) facing = target.get(DoorBlock.HINGE) == DoorHinge.RIGHT ? facing.rotateYCounterclockwise() : facing.rotateYClockwise();
BlockState newState = block.getDefaultState().with(TrapdoorBlock.OPEN, true).with(TrapdoorBlock.FACING, facing);
world.setBlockState(pos, newState);
world.setBlockState(otherPos, newState);
return entropy;
}
return 0;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private Block block = Blocks.AIR;
private int entropy;
public Builder block(Block block) {
this.block = block;
return this;
}
public Builder entropy(int entropy) {
this.entropy = entropy;
return this;
}
public DoorDecayProccessor create() {
return new DoorDecayProccessor(block, entropy);
}
}
}

View file

@ -0,0 +1,108 @@
package org.dimdev.dimdoors.world.decay.processors;
import net.minecraft.block.BedBlock;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.DoorBlock;
import net.minecraft.block.TrapdoorBlock;
import net.minecraft.block.enums.DoorHinge;
import net.minecraft.block.enums.DoubleBlockHalf;
import net.minecraft.fluid.FluidState;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.Registries;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import org.dimdev.dimdoors.world.decay.DecayProcessor;
public class DoubleDecayProcessor implements DecayProcessor {
public static final String KEY = "double";
protected Block block;
protected int entropy;
public DoubleDecayProcessor() {}
protected DoubleDecayProcessor(Block block, int entropy) {
this.block = block;
this.entropy = entropy;
}
@Override
public DecayProcessor fromNbt(NbtCompound json) {
block = Registries.BLOCK.get(Identifier.tryParse(json.getString("block")));
entropy = json.getInt("entropy");
return this;
}
@Override
public NbtCompound toNbt(NbtCompound nbt) {
DecayProcessor.super.toNbt(nbt);
nbt.putString("block", Registries.BLOCK.getId(block).toString());
nbt.putInt("entropy", entropy);
return nbt;
}
@Override
public DecayProcessorType<? extends DecayProcessor> getType() {
return DecayProcessorType.DOOR_PROCESSOR_TYPE;
}
@Override
public String getKey() {
return null;
}
@Override
public int process(World world, BlockPos pos, BlockState origin, BlockState target, FluidState targetFluid) {
if(target.getBlock() instanceof DoorBlock) {
BlockPos otherPos = target.get(DoorBlock.HALF) == DoubleBlockHalf.UPPER ? pos.down() : pos.up();
Direction facing = target.get(DoorBlock.FACING);
if(target.get(DoorBlock.OPEN)) facing = target.get(DoorBlock.HINGE) == DoorHinge.RIGHT ? facing.rotateYCounterclockwise() : facing.rotateYClockwise();
BlockState newState = block.getDefaultState().with(TrapdoorBlock.OPEN, true).with(TrapdoorBlock.FACING, facing);
world.setBlockState(pos, newState);
world.setBlockState(otherPos, newState);
return entropy;
} else if(target.getBlock() instanceof BedBlock) {
BlockPos otherPos = pos.offset(BedBlock.getOppositePartDirection(target));
BlockState newState = block.getDefaultState();
world.setBlockState(pos, newState);
world.setBlockState(otherPos, newState);
}
return 0;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private Block block = Blocks.AIR;
private int entropy;
public Builder block(Block block) {
this.block = block;
return this;
}
public Builder entropy(int entropy) {
this.entropy = entropy;
return this;
}
public DoubleDecayProcessor create() {
return new DoubleDecayProcessor(block, entropy);
}
}
}

View file

@ -0,0 +1,42 @@
package org.dimdev.dimdoors.world.decay.processors;
import net.minecraft.block.BlockState;
import net.minecraft.fluid.FluidState;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.dimdev.dimdoors.world.decay.DecayProcessor;
import static org.dimdev.dimdoors.world.decay.DecayProcessor.DecayProcessorType.SELF;
public class SelfDecayProcessor implements DecayProcessor {
public static final String KEY = "self";
private static final SelfDecayProcessor instance = new SelfDecayProcessor();
public static SelfDecayProcessor instance() {
return instance;
}
@Override
public DecayProcessor fromNbt(NbtCompound nbt) {
return this;
}
@Override
public DecayProcessorType<? extends DecayProcessor> getType() {
return SELF;
}
@Override
public String getKey() {
return KEY;
}
@Override
public int process(World world, BlockPos pos, BlockState origin, BlockState targetBlock, FluidState targetFluid) {
world.setBlockState(pos, origin);
return 0;
}
}

View file

@ -0,0 +1,94 @@
package org.dimdev.dimdoors.world.feature;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.world.biome.BiomeKeys;
import net.minecraft.world.gen.GenerationStep;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.DefaultFeatureConfig;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.PlacedFeature;
import net.fabricmc.fabric.api.biome.v1.BiomeModifications;
import net.fabricmc.fabric.api.tag.convention.v1.ConventionalBiomeTags;
import org.dimdev.dimdoors.world.feature.gateway.LimboGatewayFeature;
import org.dimdev.dimdoors.world.feature.gateway.schematic.EndGateway;
import org.dimdev.dimdoors.world.feature.gateway.schematic.SandstonePillarsGateway;
import org.dimdev.dimdoors.world.feature.gateway.schematic.SchematicGateway;
import org.dimdev.dimdoors.world.feature.gateway.schematic.SchematicGatewayFeature;
import org.dimdev.dimdoors.world.feature.gateway.schematic.SchematicGatewayFeatureConfig;
import org.dimdev.dimdoors.world.feature.gateway.schematic.TwoPillarsGateway;
import static org.dimdev.dimdoors.DimensionalDoors.id;
@SuppressWarnings("unused")
public final class ModFeatures {
public static final SchematicGateway SANDSTONE_PILLARS_GATEWAY = new SandstonePillarsGateway();
public static final SchematicGateway TWO_PILLARS_GATEWAY = new TwoPillarsGateway();
public static final SchematicGateway END_GATEWAY = new EndGateway();
public static final Feature<SchematicGatewayFeatureConfig> SCHEMATIC_GATEWAY_FEATURE = Registry.register(Registries.FEATURE, id("schematic_gateway"), new SchematicGatewayFeature(SchematicGatewayFeatureConfig.CODEC));
public static final Feature<DefaultFeatureConfig> LIMBO_GATEWAY_FEATURE = Registry.register(Registries.FEATURE, id("limbo_gateway"), new LimboGatewayFeature());
public static void init() {
SANDSTONE_PILLARS_GATEWAY.init();
TWO_PILLARS_GATEWAY.init();
END_GATEWAY.init();
Configured.init();
Placed.init();
}
public static final class Configured {
public static final RegistryKey<ConfiguredFeature<?, ?>> SANDSTONE_PILLARS = of("sandstone_pillars");
public static final RegistryKey<ConfiguredFeature<?, ?>> TWO_PILLARS = of("two_pillars");
public static final RegistryKey<ConfiguredFeature<?, ?>> END_GATEWAY = of("end_gateway");
public static final RegistryKey<ConfiguredFeature<?, ?>> LIMBO_GATEWAY = of("limbo_gateway");
public static final RegistryKey<ConfiguredFeature<?, ?>> SOLID_STATIC_ORE = of("solid_static_ore");
public static final RegistryKey<ConfiguredFeature<?, ?>> DECAYED_BLOCK_ORE = of("decayed_block_ore");
public static final RegistryKey<ConfiguredFeature<?, ?>> ETERNAL_FLUID_SPRING = of("eternal_fluid_spring");
public static void init() {}
public static RegistryKey<ConfiguredFeature<?, ?>> of(String id) {
return RegistryKey.of(RegistryKeys.CONFIGURED_FEATURE, id(id));
}
}
public static class Placed {
public static final RegistryKey<PlacedFeature> SANDSTONE_PILLARS = of("sandstone_pillars");
public static final RegistryKey<PlacedFeature> TWO_PILLARS = of("two_pillars");
public static final RegistryKey<PlacedFeature> END_GATEWAY = of("end_gateway");
public static final RegistryKey<PlacedFeature> LIMBO_GATEWAY = of("limbo_gateway");
public static final RegistryKey<PlacedFeature> SOLID_STATIC_ORE = of("solid_static_ore");
public static final RegistryKey<PlacedFeature> DECAYED_BLOCK_ORE = of("decayed_block_ore");
public static final RegistryKey<PlacedFeature> ETERNAL_FLUID_SPRING = of("eternal_fluid_spring");
public static void init() {
BiomeModifications.addFeature(ctx -> ctx.hasTag(ConventionalBiomeTags.IN_OVERWORLD) &&
!ctx.hasTag(ConventionalBiomeTags.DESERT) &&
!ctx.hasTag(ConventionalBiomeTags.OCEAN),
GenerationStep.Feature.SURFACE_STRUCTURES,
TWO_PILLARS
);
BiomeModifications.addFeature(
ctx -> ctx.hasTag(ConventionalBiomeTags.DESERT),
GenerationStep.Feature.SURFACE_STRUCTURES,
SANDSTONE_PILLARS
);
BiomeModifications.addFeature(
ctx -> !ctx.getBiomeKey().equals(BiomeKeys.THE_END) && ctx.hasTag(ConventionalBiomeTags.IN_THE_END),
GenerationStep.Feature.SURFACE_STRUCTURES,
END_GATEWAY
);
}
public static RegistryKey<PlacedFeature> of(String id) {
return RegistryKey.of(RegistryKeys.PLACED_FEATURE, id(id));
}
}
}

View file

@ -0,0 +1,12 @@
package org.dimdev.dimdoors.world.feature.gateway;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.StructureWorldAccess;
public interface Gateway {
void generate(StructureWorldAccess world, BlockPos pos);
default boolean isLocationValid(StructureWorldAccess world, BlockPos pos) {
return true;
}
}

View file

@ -0,0 +1,44 @@
package org.dimdev.dimdoors.world.feature.gateway;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.StructureWorldAccess;
import org.dimdev.dimdoors.block.ModBlocks;
import org.dimdev.dimdoors.block.entity.ModBlockEntityTypes;
import org.dimdev.dimdoors.rift.targets.EscapeTarget;
import org.dimdev.dimdoors.world.ModDimensions;
public enum LimboGateway implements Gateway {
INSTANCE;
@Override
public void generate(StructureWorldAccess world, BlockPos pos) {
if (!this.isLocationValid(world, pos)) {
return;
}
BlockState unravelledFabric = ModBlocks.UNRAVELLED_FABRIC.getDefaultState();
// Build the gateway out of Unraveled Fabric. Since nearly all the blocks in Limbo are of
// that type, there is no point replacing the ground.
world.setBlockState(pos.add(1, 3, 0), unravelledFabric, 2);
world.setBlockState(pos.add(-1, 3, 0), unravelledFabric, 2);
// Build the columns around the door
world.setBlockState(pos.add(-1, 2, 0), unravelledFabric, 2);
world.setBlockState(pos.add(1, 2, 0), unravelledFabric, 2);
world.setBlockState(pos.add(1, 1, 0), unravelledFabric, 2);
world.setBlockState(pos.add(1, 1, 0), unravelledFabric, 2);
this.placePortal(world, pos.add(0, 1, 0), Direction.NORTH);
}
@Override
public boolean isLocationValid(StructureWorldAccess world, BlockPos pos) {
return ModDimensions.isLimboDimension(world.toServerWorld());
}
private void placePortal(StructureWorldAccess world, BlockPos pos, Direction facing) {
world.setBlockState(pos, ModBlocks.DIMENSIONAL_PORTAL.getDefaultState(), 2);
}
}

View file

@ -0,0 +1,17 @@
package org.dimdev.dimdoors.world.feature.gateway;
import net.minecraft.world.gen.feature.DefaultFeatureConfig;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.util.FeatureContext;
public class LimboGatewayFeature extends Feature<DefaultFeatureConfig> {
public LimboGatewayFeature() {
super(DefaultFeatureConfig.CODEC);
}
@Override
public boolean generate(FeatureContext<DefaultFeatureConfig> context) {
LimboGateway.INSTANCE.generate(context.getWorld(), context.getOrigin());
return true;
}
}

View file

@ -0,0 +1,16 @@
package org.dimdev.dimdoors.world.feature.gateway.schematic;
import net.minecraft.block.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.StructureWorldAccess;
public class EndGateway extends SchematicGateway{
public EndGateway() {
super("end_gateway");
}
@Override
public boolean test(StructureWorldAccess structureWorldAccess, BlockPos blockPos) {
return structureWorldAccess.getBlockState(blockPos.down()).isOf(Blocks.END_STONE);
}
}

View file

@ -0,0 +1,16 @@
package org.dimdev.dimdoors.world.feature.gateway.schematic;
import net.minecraft.block.SandBlock;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.StructureWorldAccess;
public class SandstonePillarsGateway extends SchematicGateway {
public SandstonePillarsGateway() {
super("sandstone_pillars");
}
@Override
public boolean test(StructureWorldAccess structureWorldAccess, BlockPos blockPos) {
return structureWorldAccess.getBlockState(blockPos.down()).getBlock() instanceof SandBlock;
}
}

View file

@ -0,0 +1,74 @@
package org.dimdev.dimdoors.world.feature.gateway.schematic;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.function.BiPredicate;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import net.minecraft.nbt.NbtIo;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.StructureWorldAccess;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.api.util.BlockPlacementType;
import org.dimdev.dimdoors.pockets.TemplateUtils;
import org.dimdev.dimdoors.util.schematic.Schematic;
import org.dimdev.dimdoors.util.schematic.SchematicPlacer;
import org.dimdev.dimdoors.world.feature.gateway.Gateway;
public abstract class SchematicGateway implements Gateway, BiPredicate<StructureWorldAccess, BlockPos> {
private Schematic schematic;
private final String id;
public static final BiMap<String, SchematicGateway> ID_SCHEMATIC_MAP = HashBiMap.create();
private boolean replaced;
public SchematicGateway(String id) {
ID_SCHEMATIC_MAP.putIfAbsent(id, this);
this.id = id;
}
public void init() {
String schematicJarDirectory = "/data/dimdoors/gateways/";
try (InputStream stream = DimensionalDoors.class.getResourceAsStream(schematicJarDirectory + this.id + ".schem")) {
if (stream == null) {
throw new RuntimeException("Schematic '" + this.id + "' was not found in the jar.");
}
try {
this.schematic = Schematic.fromNbt(NbtIo.readCompressed(stream));
} catch (IOException ex) {
throw new RuntimeException("Schematic file for " + this.id + " could not be read as a valid schematic NBT file.", ex);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
public final void generate(StructureWorldAccess world, BlockPos pos) {
if (DimensionalDoors.getConfig()
.getWorldConfig()
.gatewayDimBlacklist
.contains(world.toServerWorld().getRegistryKey().getValue().toString())
) {
return;
}
if (!this.replaced) {
TemplateUtils.replacePlaceholders(this.schematic, world);
this.replaced = true;
}
SchematicPlacer.place(this.schematic, world, pos, BlockPlacementType.SECTION_NO_UPDATE_QUEUE_BLOCK_ENTITY);
this.generateRandomBits(world, pos);
}
/**
* Generates randomized portions of the gateway structure (e.g. rubble, foliage)
*
* @param world - the world in which to generate the gateway
* @param pos - the position at which the schematic is placed
*/
protected void generateRandomBits(StructureWorldAccess world, BlockPos pos) {
}
}

View file

@ -0,0 +1,22 @@
package org.dimdev.dimdoors.world.feature.gateway.schematic;
import com.mojang.serialization.Codec;
import net.minecraft.block.AirBlock;
import net.minecraft.world.gen.feature.Feature;
import net.minecraft.world.gen.feature.util.FeatureContext;
public class SchematicGatewayFeature extends Feature<SchematicGatewayFeatureConfig> {
public SchematicGatewayFeature(Codec<SchematicGatewayFeatureConfig> codec) {
super(codec);
}
@Override
public boolean generate(FeatureContext<SchematicGatewayFeatureConfig> featureContext) {
if (featureContext.getWorld().getBlockState(featureContext.getOrigin()).getBlock() instanceof AirBlock && featureContext.getConfig().getGateway().test(featureContext.getWorld(), featureContext.getOrigin())) {
featureContext.getConfig().getGateway().generate(featureContext.getWorld(), featureContext.getOrigin());
return true;
}
return false;
}
}

View file

@ -0,0 +1,28 @@
package org.dimdev.dimdoors.world.feature.gateway.schematic;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.world.gen.feature.FeatureConfig;
public class SchematicGatewayFeatureConfig implements FeatureConfig {
public static final Codec<SchematicGatewayFeatureConfig> CODEC = RecordCodecBuilder.create((instance) -> instance.group(
Codec.STRING.fieldOf("gatewayId").forGetter(SchematicGatewayFeatureConfig::getGatewayId)
).apply(instance, SchematicGatewayFeatureConfig::new));
private final SchematicGateway gateway;
private final String gatewayId;
public SchematicGatewayFeatureConfig(String id) {
this.gatewayId = id;
this.gateway = SchematicGateway.ID_SCHEMATIC_MAP.get(id);
}
public SchematicGateway getGateway() {
return this.gateway;
}
public String getGatewayId() {
return this.gatewayId;
}
}

View file

@ -0,0 +1,42 @@
package org.dimdev.dimdoors.world.feature.gateway.schematic;
import net.minecraft.block.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.StructureWorldAccess;
public class TwoPillarsGateway extends SchematicGateway {
private static final int GATEWAY_RADIUS = 4;
public TwoPillarsGateway() {
super("two_pillars");
}
@Override
protected void generateRandomBits(StructureWorldAccess world, BlockPos pos) {
//Replace some of the ground around the gateway with bricks
for (int xc = -GATEWAY_RADIUS; xc <= GATEWAY_RADIUS; xc++) {
for (int zc = -GATEWAY_RADIUS; zc <= GATEWAY_RADIUS; zc++) {
//Check that the block is supported by an opaque block.
//This prevents us from building over a cliff, on the peak of a mountain,
//or the surface of the ocean or a frozen lake.
if (world.getBlockState(pos.add(xc, -1, zc)).getMaterial().isSolid()) {
//Randomly choose whether to place bricks or not. The math is designed so that the
//chances of placing a block decrease as we get farther from the gateway's center.
int i = Math.abs(xc) + Math.abs(zc);
if (i < world.getRandom().nextInt(2) + 3) {
//Place Stone Bricks
world.setBlockState(pos.add(xc, 0, zc), Blocks.STONE_BRICKS.getDefaultState(), 2);
} else if (i < world.getRandom().nextInt(3) + 3) {
//Place Cracked Stone Bricks
world.setBlockState(pos.add(xc, 0, zc), Blocks.CRACKED_STONE_BRICKS.getDefaultState(), 2);
}
}
}
}
}
@Override
public boolean test(StructureWorldAccess structureWorldAccess, BlockPos blockPos) {
return !structureWorldAccess.getBlockState(blockPos).isOf(Blocks.WATER);
}
}

View file

@ -0,0 +1,41 @@
package org.dimdev.dimdoors.world.level.component;
import dev.onyxstudios.cca.api.v3.component.Component;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.world.chunk.Chunk;
import net.fabricmc.fabric.api.util.NbtType;
import org.dimdev.dimdoors.DimensionalDoorsComponents;
public class ChunkLazilyGeneratedComponent implements Component {
private boolean hasBeenLazyGenned = false;
public boolean hasBeenLazyGenned() {
return hasBeenLazyGenned;
}
public void setGenned() {
if (hasBeenLazyGenned) throw new UnsupportedOperationException("This chunk seems to have already been lazily generated!");
hasBeenLazyGenned = true;
}
public static ChunkLazilyGeneratedComponent get(Chunk chunk) {
return DimensionalDoorsComponents.CHUNK_LAZILY_GENERATED_COMPONENT_KEY.get(chunk);
}
@Override
public void readFromNbt(NbtCompound nbt) {
if (nbt.contains("has_been_lazy_genned", NbtType.INT)) {
hasBeenLazyGenned = nbt.getInt("has_been_lazy_genned") == 1;
}
}
@Override
public void writeToNbt(NbtCompound nbt) {
if (hasBeenLazyGenned) {
nbt.putInt("has_been_lazy_genned", 1);
}
}
}

View file

@ -0,0 +1,107 @@
package org.dimdev.dimdoors.world.level.registry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import dev.onyxstudios.cca.api.v3.component.ComponentV3;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.resources.ResourceKey;
import net.minecraft.util.Identifier;
import net.minecraft.util.Pair;
import net.minecraft.world.World;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelProperties;
import org.dimdev.dimdoors.DimensionalDoorsComponents;
import org.dimdev.dimdoors.rift.registry.RiftRegistry;
import org.dimdev.dimdoors.world.ModDimensions;
import org.dimdev.dimdoors.world.pocket.PocketDirectory;
import org.dimdev.dimdoors.world.pocket.PrivateRegistry;
import static org.dimdev.dimdoors.DimensionalDoors.getServer;
public class DimensionalRegistry implements ComponentV3 {
public static final int RIFT_DATA_VERSION = 1; // Increment this number every time a new schema is added
private Map<RegistryKey<World>, PocketDirectory> pocketRegistry = new HashMap<>();
private RiftRegistry riftRegistry = new RiftRegistry();
private PrivateRegistry privateRegistry = new PrivateRegistry();
@Override
public void readFromNbt(NbtCompound nbt) {
int riftDataVersion = nbt.getInt("RiftDataVersion");
if (riftDataVersion < RIFT_DATA_VERSION) {
nbt = RiftSchemas.update(riftDataVersion, nbt);
} else if (RIFT_DATA_VERSION < riftDataVersion) {
throw new UnsupportedOperationException("Downgrading is not supported!");
}
NbtCompound pocketRegistryNbt = nbt.getCompound("pocket_registry");
CompletableFuture<Map<RegistryKey<World>, PocketDirectory>> futurePocketRegistry = CompletableFuture.supplyAsync(() -> pocketRegistryNbt.getKeys().stream().map(key -> {
NbtCompound pocketDirectoryNbt = pocketRegistryNbt.getCompound(key);
return CompletableFuture.supplyAsync(() -> new Pair<>(RegistryKey.of(RegistryKeys.WORLD, Identifier.tryParse(key)), PocketDirectory.readFromNbt(key, pocketDirectoryNbt)));
}).parallel().map(CompletableFuture::join).collect(Collectors.toConcurrentMap(Pair::getLeft, Pair::getRight)));
NbtCompound privateRegistryNbt = nbt.getCompound("private_registry");
CompletableFuture<PrivateRegistry> futurePrivateRegistry = CompletableFuture.supplyAsync(() -> {
PrivateRegistry privateRegistry = new PrivateRegistry();
privateRegistry.fromNbt(privateRegistryNbt);
return privateRegistry;
});
pocketRegistry = futurePocketRegistry.join();
NbtCompound riftRegistryNbt = nbt.getCompound("rift_registry");
CompletableFuture<RiftRegistry> futureRiftRegistry = CompletableFuture.supplyAsync(() -> RiftRegistry.fromNbt(pocketRegistry, riftRegistryNbt));
riftRegistry = futureRiftRegistry.join();
this.privateRegistry = futurePrivateRegistry.join();
}
@Override
public void writeToNbt(NbtCompound nbt) {
CompletableFuture<NbtElement> futurePocketRegistryNbt = CompletableFuture.supplyAsync(() -> {
List<CompletableFuture<Pair<String, NbtElement>>> futurePocketRegistryNbts = new ArrayList<>();
pocketRegistry.forEach((key, value) -> futurePocketRegistryNbts.add(CompletableFuture.supplyAsync(() -> new Pair<>(key.getValue().toString(), value.writeToNbt()))));
NbtCompound pocketRegistryNbt = new NbtCompound();
futurePocketRegistryNbts.parallelStream().unordered().map(CompletableFuture::join).collect(Collectors.toConcurrentMap(Pair::getLeft, Pair::getRight)).forEach(pocketRegistryNbt::put);
return pocketRegistryNbt;
});
CompletableFuture<NbtElement> futureRiftRegistryNbt = CompletableFuture.supplyAsync(riftRegistry::toNbt);
CompletableFuture<NbtElement> futurePrivateRegistryNbt = CompletableFuture.supplyAsync(() -> privateRegistry.toNbt(new NbtCompound()));
nbt.put("pocket_registry", futurePocketRegistryNbt.join());
nbt.put("rift_registry", futureRiftRegistryNbt.join());
nbt.put("private_registry", futurePrivateRegistryNbt.join());
nbt.putInt("RiftDataVersion", RIFT_DATA_VERSION);
}
public static DimensionalRegistry instance() {
return DimensionalDoorsComponents.DIMENSIONAL_REGISTRY_COMPONENT_KEY.get((LevelProperties) getServer().getSaveProperties());
}
public static RiftRegistry getRiftRegistry() {
return instance().riftRegistry;
}
public static PrivateRegistry getPrivateRegistry() {
return instance().privateRegistry;
}
public static PocketDirectory getPocketDirectory(ResourceKey<Level> key) {
if (!(ModDimensions.isPocketDimension(key))) {
throw new UnsupportedOperationException("PocketRegistry is only available for pocket dimensions!");
}
return instance().pocketRegistry.computeIfAbsent(key, PocketDirectory::new);
}
}

View file

@ -0,0 +1,29 @@
package org.dimdev.dimdoors.world.level.registry;
import java.util.function.BiFunction;
import com.mojang.datafixers.DSL;
import com.mojang.datafixers.DataFixer;
import com.mojang.datafixers.DataFixerBuilder;
import com.mojang.datafixers.schemas.Schema;
import com.mojang.serialization.Dynamic;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtOps;
import net.minecraft.util.Util;
import org.dimdev.dimdoors.world.level.registry.schema.Schema1;
public class RiftSchemas {
public static final DSL.TypeReference RIFT_DATA_TYPE_REF = () -> "rift_data";
public static final int RIFT_DATA_VERSION = DimensionalRegistry.RIFT_DATA_VERSION;
public static final BiFunction<Integer, Schema, Schema> EMPTY = Schema::new;
public static final DataFixer DATA_FIXER = Util.make(new DataFixerBuilder(RIFT_DATA_VERSION), builder -> {
builder.addSchema(1, Schema1::new);
// TODO: add schemas if schema changes
}).buildUnoptimized();
public static NbtCompound update(int oldVersion, NbtCompound original) {
return (NbtCompound) DATA_FIXER.update(RIFT_DATA_TYPE_REF, new Dynamic<>( NbtOps.INSTANCE, original), oldVersion, RIFT_DATA_VERSION).getValue();
}
}

View file

@ -0,0 +1,21 @@
package org.dimdev.dimdoors.world.level.registry.schema;
import java.util.Map;
import java.util.function.Supplier;
import com.mojang.datafixers.DSL;
import com.mojang.datafixers.schemas.Schema;
import com.mojang.datafixers.types.templates.TypeTemplate;
import org.dimdev.dimdoors.world.level.registry.RiftSchemas;
public class Schema1 extends Schema {
public Schema1(int versionKey, Schema parent) {
super(versionKey, parent);
}
@Override
public void registerTypes(Schema schema, Map<String, Supplier<TypeTemplate>> entityTypes, Map<String, Supplier<TypeTemplate>> blockEntityTypes) {
schema.registerType(false, RiftSchemas.RIFT_DATA_TYPE_REF, DSL::remainder);
}
}

View file

@ -0,0 +1,93 @@
package org.dimdev.dimdoors.world.pocket;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.WorldGenRegion;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.NoiseColumn;
import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.biome.BiomeManager;
import net.minecraft.world.level.biome.BiomeSource;
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.GenerationStep;
import net.minecraft.world.level.levelgen.Heightmap;
import net.minecraft.world.level.levelgen.RandomState;
import net.minecraft.world.level.levelgen.blending.Blender;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
public class BlankChunkGenerator extends ChunkGenerator {
public static final Codec<BlankChunkGenerator> CODEC = RecordCodecBuilder.create((instance) ->
instance.group(BiomeSource.CODEC.fieldOf("biome_source")
.forGetter((generator) -> generator.biomeSource)
).apply(instance, instance.stable(BlankChunkGenerator::of))
);
private static BlankChunkGenerator of(BiomeSource biomeSource) {
return new BlankChunkGenerator(biomeSource);
}
private BlankChunkGenerator(BiomeSource biomeSource) {
super(biomeSource);
}
@Override
public Codec<? extends ChunkGenerator> codec() {
return CODEC;
}
@Override
public void applyCarvers(WorldGenRegion worldGenRegion, long l, RandomState randomState, BiomeManager biomeManager, StructureManager structureManager, ChunkAccess chunkAccess, GenerationStep.Carving carving) {
}
@Override
public void buildSurface(WorldGenRegion worldGenRegion, StructureManager structureManager, RandomState randomState, ChunkAccess chunkAccess) {
}
@Override
public void spawnOriginalMobs(WorldGenRegion worldGenRegion) {
}
@Override
public int getGenDepth() {
return 0;
}
@Override
public CompletableFuture<ChunkAccess> fillFromNoise(Executor executor, Blender blender, RandomState randomState, StructureManager structureManager, ChunkAccess chunkAccess) {
return CompletableFuture.supplyAsync(() -> chunkAccess);
}
@Override
public int getSeaLevel() {
return 0;
}
@Override
public int getMinY() {
return 0;
}
@Override
public int getBaseHeight(int i, int j, Heightmap.Types types, LevelHeightAccessor levelHeightAccessor, RandomState randomState) {
return 0;
}
@Override
public NoiseColumn getBaseColumn(int i, int j, LevelHeightAccessor levelHeightAccessor, RandomState randomState) {
return new NoiseColumn(0, new BlockState[0]);
}
@Override
public void addDebugScreenInfo(List<String> list, RandomState randomState, BlockPos blockPos) {
}
}

View file

@ -0,0 +1,242 @@
package org.dimdev.dimdoors.world.pocket;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import com.mojang.datafixers.util.Pair;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.commands.TagCommand;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.TestOnly;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.util.Identifier;
import net.minecraft.util.Pair;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.World;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.api.util.math.GridUtil;
import org.dimdev.dimdoors.world.pocket.type.AbstractPocket;
import org.dimdev.dimdoors.world.pocket.type.IdReferencePocket;
import org.dimdev.dimdoors.world.pocket.type.Pocket;
public class PocketDirectory {
int gridSize; // Determines how much pockets in their dimension are spaced
int privatePocketSize;
int publicPocketSize;
Map<Integer, AbstractPocket<?>> pockets;
private SortedMap<Integer, Integer> nextIDMap;
ResourceKey<Level> worldKey;
public PocketDirectory(ResourceKey<Level> worldKey) {
this.gridSize = DimensionalDoors.getConfig().getPocketsConfig().pocketGridSize;
this.worldKey = worldKey;
this.nextIDMap = new TreeMap<>();
this.pockets = new HashMap<>();
}
@TestOnly
public PocketDirectory(ResourceKey<Level> worldKey, int gridSize) {
this.gridSize = gridSize;
this.worldKey = worldKey;
this.nextIDMap = new TreeMap<>();
this.pockets = new HashMap<>();
}
public static PocketDirectory readFromNbt(String id, CompoundTag nbt) {
PocketDirectory directory = new PocketDirectory(ResourceKey.create(Registries.DIMENSION, new ResourceLocation(id)));
// no need to parallelize
directory.gridSize = nbt.getInt("grid_size");
directory.privatePocketSize = nbt.getInt("private_pocket_size");
directory.publicPocketSize = nbt.getInt("public_pocket_size");
// same thing, too short anyways
CompoundTag nextIdMapNbt = nbt.getCompound("next_id_map");
directory.nextIDMap.putAll(nextIdMapNbt.getAllKeys().stream().collect(Collectors.toMap(Integer::parseInt, nextIdMapNbt::getInt)));
CompoundTag pocketsNbt = nbt.getCompound("pockets");
directory.pockets = pocketsNbt.getAllKeys().stream().unordered().map(key -> {
CompoundTag pocketNbt = pocketsNbt.getCompound(key);
return CompletableFuture.supplyAsync(() -> new Pair<>(Integer.parseInt(key), AbstractPocket.deserialize(pocketNbt)));
}).parallel().map(CompletableFuture::join).collect(Collectors.toConcurrentMap(Pair::getFirst, Pair::getSecond));
return directory;
}
public CompoundTag writeToNbt() {
CompoundTag nbt = new CompoundTag();
nbt.putInt("grid_size", this.gridSize);
nbt.putInt("private_pocket_size", this.privatePocketSize);
nbt.putInt("public_pocket_size", this.publicPocketSize);
CompoundTag nextIdMapNbt = new CompoundTag();
this.nextIDMap.forEach((key, value) -> nextIdMapNbt.putInt(key.toString(), value));
nbt.put("next_id_map", nextIdMapNbt);
CompoundTag pocketsNbt = new CompoundTag();
this.pockets.entrySet().parallelStream().unordered().map(entry -> CompletableFuture.supplyAsync(() -> new Pair<>(entry.getKey().toString(), entry.getValue().toNbt(new CompoundTag()))))
.map(CompletableFuture::join).sequential().forEach(pair -> pocketsNbt.put(pair.getFirst(), pair.getSecond()));
nbt.put("pockets", pocketsNbt);
return nbt;
}
/**
* Create a new blank pocket.
*
* @return The newly created pockets
*/
public <T extends Pocket> T newPocket(Pocket.PocketBuilder<?, T> builder) {
Vec3i size = builder.getExpectedSize();
int longest = Math.max(Math.max(size.getX(), size.getZ()), 1);
longest = (Math.floorDiv(longest - 1, gridSize * 16)) + 1;
int base3Size = 1;
while (longest > base3Size) {
base3Size *= 3;
}
int squaredSize = base3Size * base3Size;
int cursor = nextIDMap.headMap(base3Size+1).values().stream().mapToInt(num -> num).max().orElse(0);
cursor = cursor - Math.floorMod(cursor, squaredSize);
Pocket pocketAt = getPocket(cursor);
while (pocketAt != null) {
size = pocketAt.getSize();
longest = Math.max(size.getX(), size.getZ());
longest = (longest / (gridSize * 16)) + 1;
int pocketBase3Size = 1;
while (longest > pocketBase3Size) {
pocketBase3Size *= 3;
}
cursor += Math.max(squaredSize, pocketBase3Size * pocketBase3Size);
pocketAt = getPocket(cursor);
}
cursor = cursor + squaredSize - 1; // we actually want to use the last id of
// the assigned grid space since it is in the bottom left corner
T pocket = builder
.id(cursor)
.world(worldKey)
.range(squaredSize)
.offsetOrigin(idToCenteredPos(cursor, base3Size, builder.getExpectedSize()))
.build();
nextIDMap.put(base3Size, cursor + squaredSize);
addPocket(pocket);
IdReferencePocket.IdReferencePocketBuilder idReferenceBuilder = IdReferencePocket.builder();
for (int i = 1; i < squaredSize; i++) {
addPocket(idReferenceBuilder
.id(cursor - i)
.world(worldKey)
.referencedId(cursor)
.build());
}
return pocket;
}
private void addPocket(AbstractPocket<?> pocket) {
pockets.put(pocket.getId(), pocket);
}
// TODO: rework this method to remove references as well
public void removePocket(int id) {
this.pockets.remove(id);
}
/**
* Gets the pocket that occupies the GridPos which a certain ID represents, or null if there is no pocket at that GridPos.
*
* @return The pocket which occupies the GridPos represented by that ID, or null if there was no pocket occupying that GridPos.
*/
public Pocket getPocket(int id) {
AbstractPocket<?> pocket = this.pockets.get(id);
return pocket == null ? null : pocket.getReferencedPocket(this);
}
public <P extends Pocket> P getPocket(int id, Class<P> clazz) {
Pocket pocket = getPocket(id);
if (clazz.isInstance(pocket)) return clazz.cast(pocket);
return null;
}
public GridUtil.GridPos idToGridPos(int id) {
return GridUtil.idToGridPos(id);
}
public int gridPosToID(GridUtil.GridPos pos) {
return GridUtil.gridPosToID(pos);
}
/**
* Calculates the default BlockPos where a pocket should be based on the ID. Use this only for placing
* pockets, and use Pocket.getGridPos() for getting the position
*
* @param id The ID of the pocket
* @return The BlockPos of the pocket
*/
public BlockPos idToPos(int id) {
GridUtil.GridPos pos = this.idToGridPos(id);
return new BlockPos(pos.x * this.gridSize * 16, 0, pos.z * this.gridSize * 16);
}
public BlockPos idToCenteredPos(int id, int base3Size, Vec3i expectedSize) {
GridUtil.GridPos pos = this.idToGridPos(id);
// you actually need the "/ 2 * 16" here. "*8" would not work the same since it doesn't guarantee chunk alignment
return new BlockPos((pos.x * this.gridSize * 16) + (base3Size * this.gridSize - expectedSize.getX() / 16) / 2 * 16, 0, (pos.z * this.gridSize * 16) + (base3Size * this.gridSize - expectedSize.getZ() / 16) / 2 * 16);
}
/**
* Calculates the ID of a pocket at a certain BlockPos.
*
* @param pos The position
* @return The ID of the pocket, or -1 if there is no pocket at that location
*/
public int posToID(BlockPos pos) {
return this.gridPosToID(new GridUtil.GridPos(Math.floorDiv(pos.getX(), this.gridSize * 16), Math.floorDiv(pos.getZ(), this.gridSize * 16)));
}
public Pocket getPocketAt(BlockPos pos) { // TODO: use BlockPos
return this.getPocket(this.posToID(pos));
}
public boolean isWithinPocketBounds(BlockPos pos) {
Pocket pocket = this.getPocketAt(pos);
return pocket != null && pocket.isInBounds(pos);
}
public int getGridSize() {
return this.gridSize;
}
public int getPrivatePocketSize() {
return this.privatePocketSize;
}
public int getPublicPocketSize() {
return this.publicPocketSize;
}
public Map<Integer, AbstractPocket<?>> getPockets() {
return this.pockets;
}
}

View file

@ -0,0 +1,93 @@
package org.dimdev.dimdoors.world.pocket;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.util.Identifier;
import net.minecraft.util.Pair;
import net.minecraft.world.World;
import org.dimdev.dimdoors.world.level.registry.DimensionalRegistry;
import org.dimdev.dimdoors.world.pocket.type.Pocket;
import org.dimdev.dimdoors.world.pocket.type.PrivatePocket;
public class PrivateRegistry {
protected static class PocketInfo {
public final RegistryKey<World> world;
public final int id;
public PocketInfo(RegistryKey<World> world, int id) {
this.world = world;
this.id = id;
}
public static NbtCompound toNbt(PocketInfo info) {
NbtCompound nbt = new NbtCompound();
nbt.putString("world", info.world.getValue().toString());
nbt.putInt("id", info.id);
return nbt;
}
public static PocketInfo fromNbt(NbtCompound nbt) {
return new PocketInfo(
RegistryKey.of(RegistryKeys.WORLD, new Identifier(nbt.getString("world"))),
nbt.getInt("id")
);
}
}
private static final String DATA_NAME = "dimdoors_private_pockets";
protected BiMap<UUID, PocketInfo> privatePocketMap = HashBiMap.create(); // Player UUID -> Pocket Info TODO: fix AnnotatedNBT and use UUID rather than String
public PrivateRegistry() {
}
public void fromNbt(NbtCompound nbt) {
privatePocketMap.clear();
NbtCompound privatePocketMapNbt = nbt.getCompound("private_pocket_map");
CompletableFuture<Map<UUID, PocketInfo>> futurePrivatePocketMap = CompletableFuture.supplyAsync(() ->
privatePocketMapNbt.getKeys().stream().unordered().map(key -> {
NbtCompound pocketInfoNbt = privatePocketMapNbt.getCompound(key);
return CompletableFuture.supplyAsync(() -> new Pair<>(UUID.fromString(key), PocketInfo.fromNbt(pocketInfoNbt)));
}).parallel().map(CompletableFuture::join).collect(Collectors.toConcurrentMap(Pair::getLeft, Pair::getRight)));
futurePrivatePocketMap.join().forEach(this.privatePocketMap::put);
}
public NbtCompound toNbt(NbtCompound nbt) {
CompletableFuture<NbtCompound> futurePrivatePocketMapNbt = CompletableFuture.supplyAsync(() -> {
Map<String, NbtElement> privatePocketNbtMap = this.privatePocketMap.entrySet().parallelStream().unordered().collect(Collectors.toConcurrentMap(entry -> entry.getKey().toString(), entry -> PocketInfo.toNbt(entry.getValue())));
NbtCompound privatePocketMapNbt = new NbtCompound();
privatePocketNbtMap.forEach(privatePocketMapNbt::put);
return privatePocketMapNbt;
});
nbt.put("private_pocket_map", futurePrivatePocketMapNbt.join());
return nbt;
}
public PrivatePocket getPrivatePocket(UUID playerUUID) {
PocketInfo pocket = this.privatePocketMap.get(playerUUID);
if (pocket == null) return null;
return DimensionalRegistry.getPocketDirectory(pocket.world).getPocket(pocket.id, PrivatePocket.class);
}
public void setPrivatePocketID(UUID playerUUID, Pocket pocket) {
this.privatePocketMap.put(playerUUID, new PocketInfo(pocket.getWorld(), pocket.getId()));
}
public UUID getPrivatePocketOwner(Pocket pocket) {
return this.privatePocketMap.inverse().get(new PocketInfo(pocket.getWorld(), pocket.getId()));
}
}

View file

@ -0,0 +1,142 @@
package org.dimdev.dimdoors.world.pocket;
import com.google.common.base.MoreObjects;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkSectionPos;
import net.minecraft.world.Heightmap;
import net.minecraft.world.World;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.levelgen.Heightmap;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.api.util.Location;
import org.dimdev.dimdoors.world.ModDimensions;
import org.dimdev.dimdoors.world.level.registry.DimensionalRegistry;
import org.dimdev.dimdoors.world.pocket.type.Pocket;
import static net.minecraft.world.World.OVERWORLD;
import static net.minecraft.world.level.Level.OVERWORLD;
public class VirtualLocation {
public static Codec<VirtualLocation> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
Level.RESOURCE_KEY_CODEC.fieldOf("world").forGetter(virtualLocation -> virtualLocation.world),
Codec.INT.fieldOf("x").forGetter(virtualLocation -> virtualLocation.x),
Codec.INT.fieldOf("z").forGetter(virtualLocation -> virtualLocation.z),
Codec.INT.fieldOf("depth").forGetter(virtualLocation -> virtualLocation.depth)
).apply(instance, VirtualLocation::new)
);
private final ResourceKey<Level> world;
private final int x;
private final int z;
private final int depth;
public VirtualLocation(ResourceKey<Level> world, int x, int z, int depth) {
this.world = world;
this.x = x;
this.z = z;
this.depth = depth;
}
public static CompoundTag toNbt(VirtualLocation virtualLocation) {
CompoundTag nbt = new CompoundTag();
nbt.putString("world", virtualLocation.world.location().toString());
nbt.putInt("x", virtualLocation.x);
nbt.putInt("z", virtualLocation.z);
nbt.putInt("depth", virtualLocation.depth);
return nbt;
}
public static VirtualLocation fromNbt(CompoundTag nbt) {
return new VirtualLocation(
ResourceKey.create(Registries.DIMENSION, new ResourceLocation(nbt.getString("world"))),
nbt.getInt("x"),
nbt.getInt("z"),
nbt.getInt("depth")
);
}
public static VirtualLocation fromLocation(Location location) {
VirtualLocation virtualLocation = null;
if (ModDimensions.isPocketDimension(location.world)) {
Pocket pocket = DimensionalRegistry.getPocketDirectory(location.world).getPocketAt(location.pos);
if (pocket != null) {
virtualLocation = pocket.virtualLocation; // TODO: pockets-relative coordinates
} else {
virtualLocation = null; // TODO: door was placed in a pockets dim but outside of a pockets...
}
} else if (ModDimensions.isLimboDimension(location.getWorld())) { // TODO: convert to interface on worldprovider
virtualLocation = new VirtualLocation(location.world, location.getX(), location.getZ(), DimensionalDoors.getConfig().getDungeonsConfig().maxDungeonDepth);
} // TODO: nether coordinate transform
if (virtualLocation == null) {
return new VirtualLocation(OVERWORLD, location.getX(), location.getZ(), 5);
}
return new VirtualLocation(location.getWorldId(), location.getX(), location.getZ(), virtualLocation.getDepth());
}
public Location projectToWorld(boolean acceptLimbo) {
ServerLevel world = DimensionalDoors.getServer().getLevel(this.world);
if (!acceptLimbo && ModDimensions.isLimboDimension(world)) {
world = world.getServer().overworld();
}
float spread = DimensionalDoors.getConfig().getGeneralConfig().depthSpreadFactor * this.depth;
int newX = (int) (this.x + spread * 2 * (Math.random() - 0.5));
int newZ = (int) (this.z + spread * 2 * (Math.random() - 0.5));
//BlockPos pos = world.getTopPosition(Heightmap.Type.WORLD_SURFACE, new BlockPos(newX, 1, newZ));
BlockPos pos = getTopPos(world, newX, newZ).above();
return new Location(world, pos);
}
public static BlockPos getTopPos(Level world, int x, int z) {
int topHeight = world.getChunk(SectionPos.blockToSectionCoord(x), SectionPos.blockToSectionCoord(z)) // guarantees WorldChunk
.getHeight(Heightmap.Types.MOTION_BLOCKING, x, z);
return new BlockPos(x, topHeight, z);
}
public ResourceKey<Level> getWorld() {
return this.world;
}
public int getX() {
return this.x;
}
public int getZ() {
return this.z;
}
public int getDepth() {
return this.depth;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("world", this.world)
.add("x", this.x)
.add("z", this.z)
.add("depth", this.depth)
.toString();
}
}

View file

@ -0,0 +1,197 @@
package org.dimdev.dimdoors.world.pocket.type;
import java.util.Map;
import java.util.function.Supplier;
import dev.architectury.registry.registries.Registrar;
import dev.architectury.registry.registries.RegistrarManager;
import dev.architectury.registry.registries.RegistrySupplier;
import net.minecraft.core.Vec3i;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.registry.Registry;
import net.minecraft.registry.ResourceKey;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.SimpleRegistry;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.Vec3i;
import net.minecraft.world.Level;
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
import net.minecraft.world.level.Level;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.world.pocket.PocketDirectory;
public abstract class AbstractPocket<V extends AbstractPocket<?>> {
public static final Registrar<AbstractPocketType<? extends AbstractPocket<?>>> REGISTRY = RegistrarManager.get(DimensionalDoors.MOD_ID).<AbstractPocketType<? extends AbstractPocket<?>>>builder(DimensionalDoors.id("abstract_pocket_type")).build();
protected Integer id;
protected ResourceKey<Level> world;
public AbstractPocket(int id, ResourceKey<Level> world) {
this.id = id;
this.world = world;
}
protected AbstractPocket() {
}
public int getId() {
return id;
}
public static AbstractPocket<? extends AbstractPocket<?>> deserialize(CompoundTag nbt) {
ResourceLocation id = ResourceLocation.tryParse(nbt.getString("type"));
return REGISTRY.get(id).fromNbt(nbt);
}
public static AbstractPocketBuilder<?, ?> deserializeBuilder(CompoundTag nbt) {
ResourceLocation id = ResourceLocation.tryParse(nbt.getString("type"));
return REGISTRY.get(id).builder().fromNbt(nbt);
}
public static CompoundTag serialize(AbstractPocket<?> pocket) {
return pocket.toNbt(new CompoundTag());
}
public V fromNbt(CompoundTag nbt) {
this.id = nbt.getInt("id");
this.world = ResourceKey.create(Registries.DIMENSION, new ResourceLocation(nbt.getString("world")));
return (V) this;
}
public CompoundTag toNbt(CompoundTag nbt) {
nbt.putInt("id", id);
nbt.putString("world", world.location().toString());
getType().toNbt(nbt);
return nbt;
}
public abstract AbstractPocketType<?> getType();
public Map<String, Double> toVariableMap(Map<String, Double> variableMap) {
variableMap.put("id", (double) this.id);
return variableMap;
}
public abstract Pocket getReferencedPocket();
// for bypassing the world check in some cases
public Pocket getReferencedPocket(PocketDirectory directory) {
return getReferencedPocket();
}
public ResourceKey<Level> getWorld() {
return world;
}
public interface AbstractPocketType<T extends AbstractPocket<?>> {
RegistrySupplier<AbstractPocketType<IdReferencePocket>> ID_REFERENCE = register(DimensionalDoors.id(IdReferencePocket.KEY), IdReferencePocket::new, IdReferencePocket::builder);
RegistrySupplier<AbstractPocketType<Pocket>> POCKET = register(DimensionalDoors.id(Pocket.KEY), Pocket::new, Pocket::builder);
RegistrySupplier<AbstractPocketType<PrivatePocket>> PRIVATE_POCKET = register(DimensionalDoors.id(PrivatePocket.KEY), PrivatePocket::new, PrivatePocket::builderPrivatePocket);
RegistrySupplier<AbstractPocketType<LazyGenerationPocket>> LAZY_GENERATION_POCKET = register(DimensionalDoors.id(LazyGenerationPocket.KEY), LazyGenerationPocket::new, LazyGenerationPocket::builderLazyGenerationPocket);
T fromNbt(CompoundTag nbt);
CompoundTag toNbt(CompoundTag nbt);
T instance();
AbstractPocketBuilder<?, T> builder();
static void register() {
DimensionalDoors.apiSubscribers.forEach(d -> d.registerAbstractPocketTypes(REGISTRY));
}
static <U extends AbstractPocket<P>, P extends AbstractPocket<P>> RegistrySupplier<AbstractPocketType<U>> register(ResourceLocation id, Supplier<U> supplier, Supplier<? extends AbstractPocketBuilder<?, U>> factorySupplier) {
return REGISTRY.register(id, () -> new AbstractPocketType<U>() {
@Override
public U fromNbt(CompoundTag nbt) {
return (U) supplier.get().fromNbt(nbt);
}
@Override
public CompoundTag toNbt(CompoundTag nbt) {
nbt.putString("type", id.toString());
return nbt;
}
@Override
public U instance() {
return supplier.get();
}
@Override
public AbstractPocketBuilder<?, U> builder() {
return factorySupplier.get();
}
});
}
}
public static abstract class AbstractPocketBuilder<P extends AbstractPocketBuilder<P, T>, T extends AbstractPocket<?>> {
protected final AbstractPocketType<T> type;
private int id;
private ResourceKey<Level> world;
protected AbstractPocketBuilder(AbstractPocketType<T> type) {
this.type = type;
}
public Vec3i getExpectedSize() {
return new Vec3i(1, 1, 1);
}
public T build() {
T instance = type.instance();
instance.id = id;
instance.world = world;
return instance;
}
public P id(int id) {
this.id = id;
return getSelf();
}
public P world(ResourceKey<Level> world) {
this.world = world;
return getSelf();
}
public P getSelf() {
return (P) this;
}
abstract public P fromNbt(CompoundTag nbt);
abstract public CompoundTag toNbt(CompoundTag nbt);
/*
public P fromTag(CompoundTag tag) {
id = tag.getInt("id");
world = ResourceKey.of(Registry.DIMENSION, new ResourceLocation(tag.getString("world")));
return getSelf();
}
public CompoundTag toTag(CompoundTag tag) {
tag.putInt("id", id);
tag.putString("world", world.getValue().toString());
return tag;
}
*/
}
}

View file

@ -0,0 +1,83 @@
package org.dimdev.dimdoors.world.pocket.type;
import net.minecraft.nbt.NbtCompound;
import net.fabricmc.fabric.api.util.NbtType;
import org.dimdev.dimdoors.world.level.registry.DimensionalRegistry;
import org.dimdev.dimdoors.world.pocket.PocketDirectory;
public class IdReferencePocket extends AbstractPocket<IdReferencePocket> {
public static String KEY = "id_reference";
protected int referencedId;
@Override
public IdReferencePocket fromNbt(NbtCompound nbt) {
super.fromNbt(nbt);
this.referencedId = nbt.getInt("referenced_id");
return this;
}
@Override
public NbtCompound toNbt(NbtCompound nbt) {
nbt = super.toNbt(nbt);
nbt.putInt("referenced_id", referencedId);
return nbt;
}
@Override
public AbstractPocketType<IdReferencePocket> getType() {
return AbstractPocketType.ID_REFERENCE;
}
@Override
public Pocket getReferencedPocket() {
return getReferencedPocket(DimensionalRegistry.getPocketDirectory(getWorld()));
}
@Override
public Pocket getReferencedPocket(PocketDirectory directory) {
return directory.getPocket(referencedId);
}
public static IdReferencePocketBuilder builder() {
return new IdReferencePocketBuilder(AbstractPocketType.ID_REFERENCE);
}
public static class IdReferencePocketBuilder extends AbstractPocketBuilder<IdReferencePocketBuilder, IdReferencePocket> {
private int referencedId = Integer.MIN_VALUE;
protected IdReferencePocketBuilder(AbstractPocketType<IdReferencePocket> type) {
super(type);
}
@Override
public IdReferencePocket build() {
IdReferencePocket pocket = super.build();
pocket.referencedId = referencedId;
return pocket;
}
@Override
public IdReferencePocketBuilder fromNbt(NbtCompound nbt) {
if (nbt.contains("referenced_id", NbtType.INT)) referencedId = nbt.getInt("referenced_id");
return this;
}
@Override
public NbtCompound toNbt(NbtCompound nbt) {
if (referencedId != Integer.MIN_VALUE) nbt.putInt("referenced_id", referencedId);
return nbt;
}
public IdReferencePocketBuilder referencedId(int referencedId) {
this.referencedId = referencedId;
return this;
}
}
}

View file

@ -0,0 +1,100 @@
package org.dimdev.dimdoors.world.pocket.type;
import java.util.Map;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.util.math.BlockBox;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.Chunk;
import net.fabricmc.fabric.api.util.NbtType;
import org.dimdev.dimdoors.api.util.BlockBoxUtil;
import org.dimdev.dimdoors.pockets.generator.LazyPocketGenerator;
import org.dimdev.dimdoors.pockets.generator.PocketGenerator;
import org.dimdev.dimdoors.world.level.component.ChunkLazilyGeneratedComponent;
public class LazyGenerationPocket extends Pocket {
public static String KEY = "lazy_gen_pocket";
private LazyPocketGenerator generator;
private int toBeGennedChunkCount = 0;
public void chunkLoaded(Chunk chunk) {
if (isDoneGenerating()) return;
ChunkLazilyGeneratedComponent lazyGenned = ChunkLazilyGeneratedComponent.get(chunk);
if (lazyGenned.hasBeenLazyGenned()) return;
BlockBox chunkBox = BlockBoxUtil.getBox(chunk);
if (!chunkBox.intersects(getBox())) return;
generator.generateChunk(this, chunk);
lazyGenned.setGenned();
toBeGennedChunkCount--;
if (isDoneGenerating()) {
this.generator = null; // saving up on some ram
}
}
public boolean isDoneGenerating() {
return toBeGennedChunkCount == 0;
}
public void attachGenerator(LazyPocketGenerator generator) {
this.generator = generator;
}
public void init() {
BlockBox box = getBox();
toBeGennedChunkCount = (Math.floorDiv(box.getMaxX(), 16) - Math.floorDiv(box.getMinX(), 16) + 1) * (Math.floorDiv(box.getMaxZ(), 16) - Math.floorDiv(box.getMinZ(), 16) + 1);
}
@Override
public NbtCompound toNbt(NbtCompound nbt) {
super.toNbt(nbt);
if (generator != null) nbt.put("generator", generator.toNbt(new NbtCompound()));
if (toBeGennedChunkCount > 0) nbt.putInt("to_be_genned_chunks", toBeGennedChunkCount);
return nbt;
}
@Override
public AbstractPocketType<?> getType() {
return AbstractPocketType.LAZY_GENERATION_POCKET;
}
public static String getKEY() {
return KEY;
}
@Override
public Pocket fromNbt(NbtCompound nbt) {
super.fromNbt(nbt);
if (nbt.contains("generator", NbtType.COMPOUND)) generator = (LazyPocketGenerator) PocketGenerator.deserialize(nbt.getCompound("generator"));
if (nbt.contains("to_be_genned_chunks", NbtType.INT)) toBeGennedChunkCount = nbt.getInt("to_be_genned_chunks");
return this;
}
@Override
public Map<BlockPos, BlockEntity> getBlockEntities() {
return super.getBlockEntities();
}
public static LazyGenerationPocketBuilder<?, LazyGenerationPocket> builderLazyGenerationPocket() {
return new LazyGenerationPocketBuilder<>(AbstractPocketType.LAZY_GENERATION_POCKET);
}
public static class LazyGenerationPocketBuilder<P extends LazyGenerationPocketBuilder<P, T>, T extends LazyGenerationPocket> extends PocketBuilder<P, T> {
protected LazyGenerationPocketBuilder(AbstractPocketType<T> type) {
super(type);
}
}
}

View file

@ -0,0 +1,284 @@
package org.dimdev.dimdoors.world.pocket.type;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Vec3i;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.world.level.registry.DimensionalRegistry;
import org.dimdev.dimdoors.world.pocket.VirtualLocation;
import org.dimdev.dimdoors.world.pocket.type.addon.AddonProvider;
import org.dimdev.dimdoors.world.pocket.type.addon.PocketAddon;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Pocket extends AbstractPocket<Pocket> implements AddonProvider {
public static String KEY = "pocket";
private final Map<ResourceLocation, PocketAddon> addons = new HashMap<>();
private int range = -1;
private BoundingBox box; // TODO: make protected
public VirtualLocation virtualLocation;
public Pocket(int id, ResourceKey<Level> world, int x, int z) {
super(id, world);
int gridSize = DimensionalRegistry.getPocketDirectory(world).getGridSize() * 16;
this.box = BoundingBox.fromCorners(new Vec3i(x * gridSize, 0, z * gridSize), new Vec3i((x + 1) * gridSize, 0, (z + 1) * gridSize));
this.virtualLocation = new VirtualLocation(world, x, z, 0);
}
protected Pocket() {
}
public boolean hasAddon(ResourceLocation id) {
return addons.containsKey(id);
}
public <C extends PocketAddon> boolean addAddon(C addon) {
if (addon.applicable(this)) {
addon.addAddon(addons);
return true;
}
return false;
}
public <C extends PocketAddon> C getAddon(ResourceLocation id) {
return (C) addons.get(id);
}
public <T> List<T> getAddonsInstanceOf(Class<T> clazz) {
return addons.values().stream()
.filter(clazz::isInstance)
.map(clazz::cast)
.collect(Collectors.toList());
}
public boolean isInBounds(BlockPos pos) {
return this.box.isInside(pos);
}
public BlockPos getOrigin() {
return new BlockPos(this.box.minX(), this.box.minY(), this.box.minZ());
}
public void offsetOrigin(Vec3i vec) {
this.box.move(vec);
}
public void offsetOrigin(int x, int y, int z) {
this.box.move(x, y, z);
}
public void setSize(Vec3i size) {
setSize(size.getX(), size.getY(), size.getZ());
}
public void setSize(int x, int y, int z) {
this.box = BoundingBox.fromCorners(new Vec3i(this.box.minX(), this.box.minY(), this.box.minZ()), new Vec3i(this.box.minX() + x - 1, this.box.minY() + y - 1, this.box.minZ() + z - 1));
}
public void setRange(int range) {
if (this.range > 0) throw new UnsupportedOperationException("Cannot set range of Pocket that has already been initialized.");
this.range = range;
}
public int getRange() {
if (range < 1) throw new UnsupportedOperationException("Range of pocket has not been initialized yet.");
return range;
}
public Vec3i getSize() {
return this.box.getLength();
}
public CompoundTag toNbt(CompoundTag nbt) {
super.toNbt(nbt);
nbt.putInt("range", range);
nbt.putIntArray("box", IntStream.of(this.box.minX(), this.box.minY(), this.box.minZ(), this.box.maxX(), this.box.maxY(), this.box.maxZ()).toArray());
nbt.put("virtualLocation", VirtualLocation.toNbt(this.virtualLocation));
ListTag addonsTag = new ListTag();
addonsTag.addAll(addons.values().stream().map(addon -> addon.toNbt(new CompoundTag())).collect(Collectors.toList()));
if (addonsTag.size() > 0) nbt.put("addons", addonsTag);
return nbt;
}
@Override
public AbstractPocketType<?> getType() {
return AbstractPocketType.POCKET.get();
}
public Pocket fromNbt(CompoundTag nbt) {
super.fromNbt(nbt);
this.range = nbt.getInt("range");
int[] box = nbt.getIntArray("box");
this.box = BoundingBox.fromCorners(new Vec3i(box[0], box[1], box[2]), new Vec3i(box[3], box[4], box[5]));
this.virtualLocation = VirtualLocation.fromNbt(nbt.getCompound("virtualLocation"));
if (nbt.contains("addons", Tag.TAG_LIST)) {
for (Tag addonTag : nbt.getList("addons", Tag.TAG_COMPOUND)) {
PocketAddon addon = PocketAddon.deserialize((CompoundTag) addonTag);
addons.put(addon.getId(), addon);
}
}
return this;
}
public Map<BlockPos, BlockEntity> getBlockEntities() {
Level serverWorld = DimensionalDoors.getWorld(this.getWorld());
Map<BlockPos, BlockEntity> blockEntities = new HashMap<>();
ChunkPos.rangeClosed(new ChunkPos(new BlockPos(box.minX(), box.minY(), box.minY())), new ChunkPos(new BlockPos(box.maxX(), box.maxY(), box.maxZ()))).forEach(chunkPos -> serverWorld.getChunk(chunkPos.x, chunkPos.z).getBlockEntities().forEach((blockPos, blockEntity) -> {
if (this.box.isInside(blockPos)) blockEntities.put(blockPos, blockEntity);
}));
return blockEntities;
}
public BoundingBox getBox() {
return box;
}
public Map<String, Double> toVariableMap(Map<String, Double> variableMap) {
variableMap = super.toVariableMap(variableMap);
variableMap.put("originX", (double) this.box.minX());
variableMap.put("originY", (double) this.box.minY());
variableMap.put("originZ", (double) this.box.minZ());
variableMap.put("width", (double) this.box.getLength().getX());
variableMap.put("height", (double) this.box.getLength().getY());
variableMap.put("length", (double) this.box.getLength().getZ());
variableMap.put("depth", (double) this.virtualLocation.getDepth());
return variableMap;
}
@Override
public Pocket getReferencedPocket() {
return this;
}
public void expand(int amount) {
this.box.inflatedBy(amount);
}
public static PocketBuilder<?, Pocket> builder() {
return new PocketBuilder(AbstractPocketType.POCKET.get());
}
protected void setBox(BoundingBox box) {
this.box = box;
}
// TODO: flesh this out a bit more, stuff like box() makes little sense in how it is implemented atm
public static class PocketBuilder<P extends PocketBuilder<P, T>, T extends Pocket> extends AbstractPocketBuilder<P, T> {
private final Map<ResourceLocation, PocketAddon.PocketBuilderAddon<?>> addons = new HashMap<>();
private Vec3i origin = new Vec3i(0, 0, 0);
private Vec3i size = new Vec3i(0, 0, 0);
private Vec3i expected = new Vec3i(0, 0, 0);
private VirtualLocation virtualLocation;
private int range = -1;
protected PocketBuilder(AbstractPocketType<T> type) {
super(type);
initAddons();
}
public void initAddons() {
}
// TODO: actually utilize fromTag/ toTag methods + implement them
public P fromNbt(CompoundTag nbt) {
if (nbt.contains("addons", Tag.TAG_LIST)) {
for (Tag addonTag : nbt.getList("addons", Tag.TAG_COMPOUND)) {
PocketAddon.PocketBuilderAddon<?> addon = PocketAddon.deserializeBuilder((CompoundTag) addonTag);
addons.put(addon.getId(), addon);
}
}
return getSelf();
}
public CompoundTag toNbt(CompoundTag nbt) {
ListTag addonsTag = new ListTag();
addonsTag.addAll(addons.values().stream().map(addon -> addon.toNbt(new CompoundTag())).collect(Collectors.toList()));
if (addonsTag.size() > 0) nbt.put("addons", addonsTag);
return nbt;
}
public boolean hasAddon(ResourceLocation id) {
return addons.containsKey(id);
}
protected <C extends PocketAddon.PocketBuilderAddon<?>> boolean addAddon(C addon) {
if (addon.applicable(this)) {
addon.addAddon(addons);
return true;
}
return false;
}
public <C extends PocketAddon.PocketBuilderAddon<?>> C getAddon(ResourceLocation id) {
return (C) addons.get(id);
}
@Override
public Vec3i getExpectedSize() {
return expected;
}
public T build() {
if (range < 1) throw new RuntimeException("Cannot create pocket with range < 1");
T instance = super.build();
instance.setRange(range);
instance.setBox(BoundingBox.fromCorners(new Vec3i(origin.getX(), origin.getY(), origin.getZ()), new Vec3i(origin.getX() + size.getX(), origin.getY() + size.getY(), origin.getZ() + size.getZ())));
instance.virtualLocation = virtualLocation;
addons.values().forEach(addon -> addon.apply(instance));
return instance;
}
public P offsetOrigin(Vec3i offset) {
this.origin = new Vec3i(origin.getX() + offset.getX(), origin.getY() + offset.getY(), origin.getZ() + offset.getZ());
return getSelf();
}
public P expand(Vec3i expander) {
this.size = new Vec3i(size.getX() + expander.getX(), size.getY() + expander.getY(), size.getZ() + expander.getZ());
this.expected = new Vec3i(expected.getX() + expander.getX(), expected.getY() + expander.getY(), expected.getZ() + expander.getZ());
return getSelf();
}
public P expandExpected(Vec3i expander) {
this.expected = new Vec3i(expected.getX() + expander.getX(), expected.getY() + expander.getY(), expected.getZ() + expander.getZ());
return getSelf();
}
public P virtualLocation(VirtualLocation virtualLocation) {
this.virtualLocation = virtualLocation;
return getSelf();
}
public P range(int range) {
this.range = range;
return getSelf();
}
}
}

View file

@ -0,0 +1,62 @@
package org.dimdev.dimdoors.world.pocket.type;
import com.mojang.serialization.Codec;
import net.minecraft.world.item.DyeColor;
public enum PocketColor {
WHITE(0, DyeColor.WHITE),
ORANGE(1, DyeColor.ORANGE),
MAGENTA(2, DyeColor.MAGENTA),
LIGHT_BLUE(3, DyeColor.LIGHT_BLUE),
YELLOW(4, DyeColor.YELLOW),
LIME(5, DyeColor.LIME),
PINK(6, DyeColor.PINK),
GRAY(7, DyeColor.GRAY),
LIGHT_GRAY(8, DyeColor.LIGHT_GRAY),
CYAN(9, DyeColor.CYAN),
PURPLE(10, DyeColor.PURPLE),
BLUE(11, DyeColor.BLUE),
BROWN(12, DyeColor.BROWN),
GREEN(13, DyeColor.GREEN),
RED(14, DyeColor.RED),
BLACK(15, DyeColor.BLACK),
NONE(16, null);
private final int id;
private final DyeColor color;
public static Codec<PocketColor> CODEC = Codec.INT.xmap(PocketColor::from, PocketColor::getId);
PocketColor(int id, DyeColor color) {
this.id = id;
this.color = color;
}
public DyeColor getColor() {
return this.color;
}
public Integer getId() {
return this.id;
}
public static PocketColor from(DyeColor color) {
for (PocketColor a : PocketColor.values()) {
if (color == a.color) {
return a;
}
}
return NONE;
}
public static PocketColor from(int id) {
for (PocketColor a : PocketColor.values()) {
if (id == a.id) {
return a;
}
}
return NONE;
}
}

View file

@ -0,0 +1,33 @@
package org.dimdev.dimdoors.world.pocket.type;
import org.dimdev.dimdoors.world.pocket.type.addon.DyeableAddon;
public class PrivatePocket extends LazyGenerationPocket implements DyeableAddon.DyeablePocket {
public static String KEY = "private_pocket";
public static PrivatePocketBuilder<?, PrivatePocket> builderPrivatePocket() {
return new PrivatePocketBuilder<>(AbstractPocketType.PRIVATE_POCKET.get());
}
public static class PrivatePocketBuilder<P extends PrivatePocketBuilder<P, T>, T extends PrivatePocket> extends PocketBuilder<P, T> implements DyeableAddon.DyeablePocketBuilder<P> {
protected PrivatePocketBuilder(AbstractPocketType<T> type) {
super(type);
}
@Override
public void initAddons() {
super.initAddons();
addAddon(new DyeableAddon.DyeableBuilderAddon());
this.dyeColor(PocketColor.WHITE);
}
}
@Override
public AbstractPocketType<?> getType() {
return AbstractPocketType.PRIVATE_POCKET.get();
}
public static String getKEY() {
return KEY;
}
}

View file

@ -0,0 +1,62 @@
package org.dimdev.dimdoors.world.pocket.type.addon;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public abstract class AddonContainer<T extends ContainedAddon> implements PocketAddon {
protected ResourceLocation id;
protected List<T> addons = new ArrayList<>();
public AddonContainer() {
}
public void setId(ResourceLocation id) {
this.id = id;
}
public void addAll(Collection<T> addons) {
this.addons.addAll(addons);
}
public void add(T addon) {
this.addons.add(addon);
}
@Override
public PocketAddon fromNbt(CompoundTag nbt) {
this.id = ResourceLocation.tryParse(nbt.getString("id"));
if (nbt.contains("addons", Tag.TAG_LIST)) {
for (Tag addonTag : nbt.getList("addons", Tag.TAG_COMPOUND)) {
addons.add((T) PocketAddon.deserialize((CompoundTag) addonTag));
}
}
return this;
}
@Override
public CompoundTag toNbt(CompoundTag nbt) {
PocketAddon.super.toNbt(nbt);
ListTag addonsTag = new ListTag();
for(T addon : addons) {
addonsTag.add(addon.toNbt(new CompoundTag()));
}
nbt.put("addons", addonsTag);
return null;
}
@Override
public ResourceLocation getId() {
return id;
}
}

View file

@ -0,0 +1,16 @@
package org.dimdev.dimdoors.world.pocket.type.addon;
import net.minecraft.resources.ResourceLocation;
import org.dimdev.dimdoors.world.pocket.type.Pocket;
public interface AddonProvider {
<C extends PocketAddon> C getAddon(ResourceLocation id);
boolean hasAddon(ResourceLocation id);
<C extends PocketAddon> boolean addAddon(C addon);
default void ensureIsPocket() {
if (! (this instanceof Pocket)) throw new UnsupportedOperationException("Cannot apply pocket addons to non Pocket Object.");
}
}

View file

@ -0,0 +1,37 @@
package org.dimdev.dimdoors.world.pocket.type.addon;
import net.minecraft.network.FriendlyByteBuf;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public interface AutoSyncedAddon extends PocketAddon {
static <T extends AutoSyncedAddon> List<T> readAutoSyncedAddonList(FriendlyByteBuf buf) throws IOException {
List<T> addons = new ArrayList<>();
int addonCount = buf.readInt();
try {
for (int i = 0; i < addonCount; i++) {
addons.add((T) ((AutoSyncedAddon) PocketAddon.REGISTRY.get(buf.readResourceLocation()).instance()).read(buf));
}
} catch (NullPointerException e) {
throw new IOException(e);
}
return addons;
}
static FriendlyByteBuf writeAutoSyncedAddonList(FriendlyByteBuf buf, List<? extends AutoSyncedAddon> addons) throws IOException {
buf.writeInt(addons.size());
for (AutoSyncedAddon addon : addons) {
buf.writeResourceLocation(addon.getType().identifier());
addon.write(buf);
}
return buf;
}
// you can generally use FriendlyByteBuf#readCompoundTag for reading
AutoSyncedAddon read(FriendlyByteBuf buf) throws IOException;
// you can generally use FriendlyByteBuf#writeCompoundTag for writing
FriendlyByteBuf write(FriendlyByteBuf buf) throws IOException;
}

View file

@ -0,0 +1,23 @@
package org.dimdev.dimdoors.world.pocket.type.addon;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import java.io.IOException;
abstract public class AutoSyncedAddonContainer<T extends ContainedAddon & AutoSyncedAddon> extends AddonContainer<T> implements AutoSyncedAddon {
@Override
public AutoSyncedAddon read(FriendlyByteBuf buf) throws IOException {
id = ResourceLocation.tryParse(buf.readUtf());
addons = AutoSyncedAddon.readAutoSyncedAddonList(buf);
return this;
}
@Override
public FriendlyByteBuf write(FriendlyByteBuf buf) throws IOException {
buf.writeUtf(id.toString());
AutoSyncedAddon.writeAutoSyncedAddonList(buf, addons);
return buf;
}
}

View file

@ -0,0 +1,36 @@
package org.dimdev.dimdoors.world.pocket.type.addon;
import net.minecraft.resources.ResourceLocation;
import org.dimdev.dimdoors.world.pocket.type.Pocket;
import java.util.Map;
public interface ContainedAddon extends PocketAddon {
ResourceLocation getContainerId();
@Override
default void addAddon(Map<ResourceLocation, PocketAddon> addons) {
throw new UnsupportedOperationException("ContainedEventListenerAddons cannot be attach to a Pocket directly");
}
interface ContainedBuilderAddon<T extends ContainedAddon> extends PocketBuilderAddon<T> {
ResourceLocation getContainerId();
AddonContainer<T> supplyContainer();
@Override
default void apply(Pocket pocket) {
AddonContainer<T> container;
if (pocket.hasAddon(getContainerId())) {
container = pocket.getAddon(getContainerId());
} else {
container = supplyContainer();
pocket.addAddon(container);
}
container.add(buildAddon());
}
T buildAddon();
}
}

View file

@ -0,0 +1,174 @@
package org.dimdev.dimdoors.world.pocket.type.addon;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.api.util.EntityUtils;
import org.dimdev.dimdoors.block.AncientFabricBlock;
import org.dimdev.dimdoors.block.FabricBlock;
import org.dimdev.dimdoors.block.ModBlocks;
import org.dimdev.dimdoors.world.pocket.type.Pocket;
import org.dimdev.dimdoors.world.pocket.type.PocketColor;
import org.dimdev.dimdoors.world.pocket.type.PrivatePocket;
public class DyeableAddon implements PocketAddon {
public static ResourceLocation ID = DimensionalDoors.id("dyeable");
private static final int BLOCKS_PAINTED_PER_DYE = 1000000;
protected PocketColor dyeColor = PocketColor.WHITE;
private PocketColor nextDyeColor = PocketColor.NONE;
private int count = 0;
private static int amountOfDyeRequiredToColor(Pocket pocket) {
int outerVolume = pocket.getBox().getYSpan() * pocket.getBox().getZSpan() * pocket.getBox().getXSpan();
int innerVolume = (pocket.getBox().getYSpan() - 5) * (pocket.getBox().getZSpan() - 5) * (pocket.getBox().getXSpan() - 5);
return Math.max((outerVolume - innerVolume) / BLOCKS_PAINTED_PER_DYE, 1);
}
private void repaint(Pocket pocket, DyeColor dyeColor) {
Level serverWorld = DimensionalDoors.getWorld(pocket.getWorld());
BlockState innerWall = ModBlocks.fabricFromDye(dyeColor).getOrNull().defaultBlockState();;
BlockState outerWall = ModBlocks.ancientFabricFromDye(dyeColor).getOrNull().defaultBlockState();;
BlockPos.betweenClosedStream(pocket.getBox()).forEach(pos -> {
if (serverWorld.getBlockState(pos).getBlock() instanceof AncientFabricBlock) {
serverWorld.setBlockAndUpdate(pos, outerWall);
} else if (serverWorld.getBlockState(pos).getBlock() instanceof FabricBlock) {
serverWorld.setBlockAndUpdate(pos, innerWall);
}
});
}
public boolean addDye(Pocket pocket, Entity entity, DyeColor dyeColor) {
PocketColor color = PocketColor.from(dyeColor);
int maxDye = amountOfDyeRequiredToColor(pocket);
if (this.dyeColor == color) {
EntityUtils.chat(entity, Component.translatable("dimdoors.pockets.dyeAlreadyAbsorbed"));
return false;
}
if (this.nextDyeColor != PocketColor.NONE && this.nextDyeColor == color) {
if (this.count + 1 > maxDye) {
repaint(pocket, dyeColor);
this.dyeColor = color;
this.nextDyeColor = PocketColor.NONE;
this.count = 0;
EntityUtils.chat(entity, Component.translatable("dimdoors.pocket.pocketHasBeenDyed", dyeColor));
} else {
this.count++;
EntityUtils.chat(entity, Component.translatable("dimdoors.pocket.remainingNeededDyes", this.count, maxDye, color));
}
} else {
this.nextDyeColor = color;
this.count = 1;
EntityUtils.chat(entity, Component.translatable("dimdoors.pocket.remainingNeededDyes", this.count, maxDye, color));
}
return true;
}
@Override
public boolean applicable(Pocket pocket) {
return pocket instanceof PrivatePocket;
}
@Override
public PocketAddon fromNbt(CompoundTag nbt) {
this.dyeColor = PocketColor.from(nbt.getInt("dyeColor"));
this.nextDyeColor = PocketColor.from(nbt.getInt("nextDyeColor"));
this.count = nbt.getInt("count");
return this;
}
@Override
public CompoundTag toNbt(CompoundTag nbt) {
PocketAddon.super.toNbt(nbt);
nbt.putInt("dyeColor", this.dyeColor.getId());
nbt.putInt("nextDyeColor", this.nextDyeColor.getId());
nbt.putInt("count", this.count);
return nbt;
}
@Override
public PocketAddonType<? extends PocketAddon> getType() {
return PocketAddonType.DYEABLE_ADDON.get();
}
@Override
public ResourceLocation getId() {
return ID;
}
public interface DyeablePocketBuilder<T extends Pocket.PocketBuilder<T, ?>> extends PocketBuilderExtension<T> {
default T dyeColor(PocketColor dyeColor) {
this.<DyeableBuilderAddon>getAddon(ID).dyeColor = dyeColor;
return getSelf();
}
}
public static class DyeableBuilderAddon implements PocketBuilderAddon<DyeableAddon> {
private PocketColor dyeColor = PocketColor.NONE;
// TODO: add some Pocket#init so that we can have boolean shouldRepaintOnInit
@Override
public void apply(Pocket pocket) {
DyeableAddon addon = new DyeableAddon();
addon.dyeColor = dyeColor;
pocket.addAddon(addon);
}
@Override
public ResourceLocation getId() {
return ID;
}
@Override
public PocketBuilderAddon<DyeableAddon> fromNbt(CompoundTag nbt) {
this.dyeColor = PocketColor.from(nbt.getInt("dye_color"));
return this;
}
@Override
public CompoundTag toNbt(CompoundTag nbt) {
PocketBuilderAddon.super.toNbt(nbt);
nbt.putInt("dye_color", dyeColor.getId());
return nbt;
}
@Override
public PocketAddonType<DyeableAddon> getType() {
return PocketAddonType.DYEABLE_ADDON.get();
}
}
public interface DyeablePocket extends AddonProvider {
default boolean addDye(Entity entity, DyeColor dyeColor) {
ensureIsPocket();
if (!this.hasAddon(ID)) {
DyeableAddon addon = new DyeableAddon();
this.addAddon(addon);
return addon.addDye((Pocket) this, entity, dyeColor);
}
return this.<DyeableAddon>getAddon(ID).addDye((Pocket) this, entity, dyeColor);
}
}
}

View file

@ -0,0 +1,138 @@
package org.dimdev.dimdoors.world.pocket.type.addon;
import java.util.Map;
import java.util.function.Supplier;
import dev.architectury.registry.registries.Registrar;
import dev.architectury.registry.registries.RegistrarManager;
import dev.architectury.registry.registries.RegistrySupplier;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.SimpleRegistry;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.REsourceLocation;
import net.fabricmc.fabric.api.event.registry.FabricRegistryBuilder;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.world.pocket.type.Pocket;
import org.dimdev.dimdoors.world.pocket.type.addon.blockbreak.BlockBreakContainer;
public interface PocketAddon {
Registrar<PocketAddonType<? extends PocketAddon>> REGISTRY = RegistrarManager.get(DimensionalDoors.MOD_ID).<PocketAddonType<? extends PocketAddon>>builder(DimensionalDoors.id("pocket_applicable_addon_type")).build();
static PocketAddon deserialize(CompoundTag nbt) {
ResourceLocation id = ResourceLocation.tryParse(nbt.getString("type")); // TODO: NONE PocketAddon type;
return REGISTRY.get(id).fromNbt(nbt);
}
static PocketBuilderAddon<?> deserializeBuilder(CompoundTag nbt) {
ResourceLocation id = ResourceLocation.tryParse(nbt.getString("type")); // TODO: NONE PocketAddon type;
return REGISTRY.get(id).builderAddonInstance().fromNbt(nbt);
}
static CompoundTag serialize(PocketAddon addon) {
return addon.toNbt(new CompoundTag());
}
default boolean applicable(Pocket pocket) {
return true;
}
PocketAddon fromNbt(CompoundTag nbt);
default CompoundTag toNbt(CompoundTag nbt) {
return this.getType().toNbt(nbt);
}
PocketAddonType<? extends PocketAddon> getType();
ResourceLocation getId();
default void addAddon(Map<ResourceLocation, PocketAddon> addons) {
addons.put(getId(), this);
}
interface PocketBuilderExtension<T extends Pocket.PocketBuilder<T, ?>> {
public <C extends PocketBuilderAddon<?>> C getAddon(ResourceLocation id);
T getSelf();
}
interface PocketBuilderAddon<T extends PocketAddon> {
default boolean applicable(Pocket.PocketBuilder<?, ?> builder) {
return true;
}
// makes it possible for addons themselves to control how they are added
default void addAddon(Map<ResourceLocation, PocketBuilderAddon<?>> addons) {
addons.put(getId(), this);
}
void apply(Pocket pocket);
ResourceLocation getId();
PocketBuilderAddon<T> fromNbt(CompoundTag nbt);
default CompoundTag toNbt(CompoundTag nbt) {
return this.getType().toNbt(nbt);
}
PocketAddonType<T> getType();
}
interface PocketAddonType<T extends PocketAddon> {
RegistrySupplier<PocketAddonType<DyeableAddon>> DYEABLE_ADDON = register(DyeableAddon.ID, DyeableAddon::new, DyeableAddon.DyeableBuilderAddon::new);
RegistrySupplier<PocketAddonType<PreventBlockModificationAddon>> PREVENT_BLOCK_MODIFICATION_ADDON = register(PreventBlockModificationAddon.ID, PreventBlockModificationAddon::new, PreventBlockModificationAddon.PreventBlockModificationBuilderAddon::new);
RegistrySupplier<PocketAddonType<BlockBreakContainer>> BLOCK_BREAK_CONTAINER = register(BlockBreakContainer.ID, BlockBreakContainer::new, null);
RegistrySupplier<PocketAddonType<SkyAddon>> SKY_ADDON = register(SkyAddon.ID, SkyAddon::new, SkyAddon.SkyBuilderAddon::new);
T fromNbt(CompoundTag nbt);
CompoundTag toNbt(CompoundTag nbt);
T instance();
PocketBuilderAddon<T> builderAddonInstance();
ResourceLocation identifier();
static void register() {
DimensionalDoors.apiSubscribers.forEach(d -> d.registerPocketAddonTypes(REGISTRY));
}
static <U extends PocketAddon> RegistrySupplier<PocketAddonType<U>> register(ResourceLocation id, Supplier<U> factory, Supplier<PocketBuilderAddon<U>> addonSupplier) {
return REGISTRY.register(id, () -> new PocketAddonType<U>() {
@Override
public U fromNbt(CompoundTag nbt) {
return (U) factory.get().fromNbt(nbt);
}
@Override
public CompoundTag toNbt(CompoundTag nbt) {
nbt.putString("type", id.toString());
return nbt;
}
@Override
public U instance() {
return factory.get();
}
@Override
public PocketBuilderAddon<U> builderAddonInstance() {
if (addonSupplier == null) return null;
return addonSupplier.get();
}
@Override
public ResourceLocation identifier() {
return id;
}
});
}
}
}

View file

@ -0,0 +1,104 @@
package org.dimdev.dimdoors.world.pocket.type.addon;
import java.io.IOException;
import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.world.World;
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.api.event.UseItemOnBlockCallback;
import org.dimdev.dimdoors.world.pocket.type.Pocket;
public class PreventBlockModificationAddon implements AutoSyncedAddon, AttackBlockCallback, PlayerBlockBreakEvents.Before, UseItemOnBlockCallback {
public static ResourceLocation ID = DimensionalDoors.id("prevent_block_modification");
//AttackBlockCallback
@Override
public ActionResult interact(PlayerEntity player, World world, Hand hand, BlockPos pos, Direction direction) {
if (player.isCreative()) return ActionResult.PASS;
return ActionResult.FAIL;
}
@Override
public boolean beforeBlockBreak(World world, PlayerEntity player, BlockPos pos, BlockState state, BlockEntity blockEntity) {
if (player.isCreative()) return true;
return false;
}
@Override
public ActionResult useItemOnBlock(PlayerEntity player, World world, Hand hand, BlockHitResult hitResult) {
if (player.isCreative()) return ActionResult.PASS;
if (player.getStackInHand(hand).getItem() instanceof BlockItem) {
BlockPos blockPos = hitResult.getBlockPos();
BlockState blockState = world.getBlockState(blockPos);
ActionResult result = blockState.onUse(world, player, hand, hitResult);
if (result.isAccepted()) return result;
return ActionResult.FAIL;
}
return ActionResult.PASS;
}
@Override
public AutoSyncedAddon read(PacketByteBuf buf) throws IOException {
return this;
}
@Override
public PacketByteBuf write(PacketByteBuf buf) throws IOException {
return buf;
}
@Override
public PocketAddon fromNbt(NbtCompound nbt) {
return this;
}
@Override
public PocketAddonType<? extends PocketAddon> getType() {
return PocketAddonType.PREVENT_BLOCK_MODIFICATION_ADDON;
}
@Override
public ResourceLocation getId() {
return ID;
}
public static class PreventBlockModificationBuilderAddon implements PocketBuilderAddon<PreventBlockModificationAddon> {
@Override
public void apply(Pocket pocket) {
pocket.addAddon(new PreventBlockModificationAddon());
}
@Override
public Identifier getId() {
return ID;
}
@Override
public PocketBuilderAddon<PreventBlockModificationAddon> fromNbt(NbtCompound nbt) {
return this;
}
@Override
public PocketAddonType<PreventBlockModificationAddon> getType() {
return PocketAddonType.PREVENT_BLOCK_MODIFICATION_ADDON;
}
}
}

View file

@ -0,0 +1,124 @@
package org.dimdev.dimdoors.world.pocket.type.addon;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.world.pocket.type.Pocket;
import java.io.IOException;
public class SkyAddon implements AutoSyncedAddon {
public static ResourceLocation ID = DimensionalDoors.id("sky");
private ResourceKey<Level> world;
public boolean setWorld(ResourceKey<Level> world) {
this.world = world;
return true;
}
@Override
public PocketAddon fromNbt(CompoundTag nbt) {
this.world = ResourceKey.create(Registries.DIMENSION, ResourceLocation.tryParse(nbt.getString("world")));
return this;
}
@Override
public CompoundTag toNbt(CompoundTag nbt) {
AutoSyncedAddon.super.toNbt(nbt);
nbt.putString("world", this.world.location().toString());
return nbt;
}
@Override
public PocketAddonType<? extends PocketAddon> getType() {
return PocketAddonType.SKY_ADDON.get();
}
@Override
public ResourceLocation getId() {
return ID;
}
public ResourceKey<Level> getWorld() {
return world;
}
@Override
public AutoSyncedAddon read(FriendlyByteBuf buf) throws IOException {
this.world = ResourceKey.create(Registries.DIMENSION, buf.readResourceLocation());
return this;
}
@Override
public FriendlyByteBuf write(FriendlyByteBuf buf) throws IOException {
buf.writeResourceLocation(world.location());
return buf;
}
public interface SkyPocketBuilder<T extends Pocket.PocketBuilder<T, ?>> extends PocketBuilderExtension<T> {
default T world(ResourceKey<Level> world) {
this.<SkyBuilderAddon>getAddon(ID).world = world;
return getSelf();
}
}
public static class SkyBuilderAddon implements PocketBuilderAddon<SkyAddon> {
private ResourceKey<Level> world = Level.OVERWORLD;
@Override
public void apply(Pocket pocket) {
SkyAddon addon = new SkyAddon();
addon.world = world;
pocket.addAddon(addon);
}
@Override
public ResourceLocation getId() {
return ID;
}
@Override
public PocketBuilderAddon<SkyAddon> fromNbt(CompoundTag nbt) {
this.world = ResourceKey.create(Registries.DIMENSION, ResourceLocation.tryParse(nbt.getString("world")));
return this;
}
@Override
public CompoundTag toNbt(CompoundTag nbt) {
PocketBuilderAddon.super.toNbt(nbt);
nbt.putString("world", world.location().toString());
return nbt;
}
@Override
public PocketAddonType<SkyAddon> getType() {
return PocketAddonType.SKY_ADDON.get();
}
}
public interface SkyPocket extends AddonProvider {
default boolean sky(ResourceKey<Level> world) {
ensureIsPocket();
if (!this.hasAddon(ID)) {
SkyAddon addon = new SkyAddon();
this.addAddon(addon);
return addon.setWorld(world);
}
return this.<SkyAddon>getAddon(ID).setWorld(world);
}
}
}

View file

@ -0,0 +1,16 @@
package org.dimdev.dimdoors.world.pocket.type.addon.blockbreak;
import net.minecraft.resources.ResourceLocation;
import org.dimdev.dimdoors.DimensionalDoors;
import org.dimdev.dimdoors.world.pocket.type.addon.AutoSyncedAddonContainer;
import org.dimdev.dimdoors.world.pocket.type.addon.PocketAddon;
// TODO
public class BlockBreakContainer extends AutoSyncedAddonContainer<TryBlockBreakEventAddon> {
public static ResourceLocation ID = DimensionalDoors.id("block_break_container");
@Override
public PocketAddonType<? extends PocketAddon> getType() {
return PocketAddonType.BLOCK_BREAK_CONTAINER.get();
}
}

View file

@ -0,0 +1,45 @@
package org.dimdev.dimdoors.world.pocket.type.addon.blockbreak;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.resources.ResourceLocation;
import org.dimdev.dimdoors.world.pocket.type.addon.AutoSyncedAddon;
import org.dimdev.dimdoors.world.pocket.type.addon.ContainedAddon;
import org.dimdev.dimdoors.world.pocket.type.addon.PocketAddon;
import java.io.IOException;
// TODO
public class BlockBreakRegexBlacklistAddon implements AutoSyncedAddon, ContainedAddon { //TODO
@Override
public AutoSyncedAddon read(FriendlyByteBuf buf) throws IOException {
this.fromNbt(buf.readNbt());
return this;
}
@Override
public FriendlyByteBuf write(FriendlyByteBuf buf) throws IOException {
buf.writeNbt(this.toNbt(new CompoundTag()));
return buf;
}
@Override
public ResourceLocation getContainerId() {
return BlockBreakContainer.ID;
}
@Override
public PocketAddon fromNbt(CompoundTag nbt) {
return null;
}
@Override
public PocketAddonType<? extends PocketAddon> getType() {
return null;
}
@Override
public ResourceLocation getId() {
return null;
}
}

View file

@ -0,0 +1,11 @@
package org.dimdev.dimdoors.world.pocket.type.addon.blockbreak;
import net.fabricmc.fabric.api.event.player.AttackBlockCallback;
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
import org.dimdev.dimdoors.world.pocket.type.addon.AutoSyncedAddon;
import org.dimdev.dimdoors.world.pocket.type.addon.ContainedAddon;
// TODO
public interface TryBlockBreakEventAddon extends AttackBlockCallback, PlayerBlockBreakEvents.Before, ContainedAddon, AutoSyncedAddon {
}

View file

@ -1,35 +1,35 @@
accessWidener v1 named
# Because its package private
accessible class net/minecraft/client/render/RenderLayer$MultiPhase
accessible class net/minecraft/client/render/RenderLayer$MultiPhaseParameters
accessible class net/minecraft/client/render/RenderPhase$ShaderProgram
accessible class net/minecraft/client/render/RenderPhase$Textures
accessible method net/minecraft/entity/Entity setRotation (FF)V
#accessible class net/minecraft/client/render/RenderLayer$MultiPhase
#accessible class net/minecraft/client/render/RenderLayer$MultiPhaseParameters
#accessible class net/minecraft/client/render/RenderPhase$ShaderProgram
#accessible class net/minecraft/client/render/RenderPhase$Textures
#accessible method net/minecraft/entity/Entity setRotation (FF)V
# for MutableBlockEntityType
extendable class net/minecraft/block/entity/BlockEntityType$BlockEntityFactory
#extendable class net/minecraft/block/entity/BlockEntityType$BlockEntityFactory
# for HackyFluidState
extendable class net/minecraft/world/level/material/FluidState
accessible field net/minecraft/world/level/block/state/StateHolder propertiesCodec Lcom/mojang/serialization/MapCodec;#Lnet/minecraft/state/State;codec:Lcom/mojang/serialization/MapCodec;
# for lazy pocket gen/ getting all currently loaded chunks
accessible method net/minecraft/server/world/ThreadedAnvilChunkStorage entryIterator ()Ljava/lang/Iterable;
#accessible method net/minecraft/server/world/ThreadedAnvilChunkStorage entryIterator ()Ljava/lang/Iterable;
accessible method net/minecraft/client/render/WorldRenderer renderEndSky (Lnet/minecraft/client/util/math/MatrixStack;)V
#accessible method net/minecraft/client/render/WorldRenderer renderEndSky (Lnet/minecraft/client/util/math/MatrixStack;)V
#accessible method net/minecraft/world/biome/Biome getCategory ()Lnet/minecraft/world/biome/Biome$Category;
accessible field net/minecraft/block/Block LOGGER Lorg/slf4j/Logger;
#accessible field net/minecraft/block/Block LOGGER Lorg/slf4j/Logger;
accessible method net/minecraft/world/gen/feature/OrePlacedFeatures modifiersWithCount (ILnet/minecraft/world/gen/placementmodifier/PlacementModifier;)Ljava/util/List;
#accessible method net/minecraft/world/gen/feature/OrePlacedFeatures modifiersWithCount (ILnet/minecraft/world/gen/placementmodifier/PlacementModifier;)Ljava/util/List;
accessible class net/minecraft/data/models/BlockModelGenerators$BlockFamilyProvider
#accessible class net/minecraft/data/models/BlockModelGenerators$BlockFamilyProvider
accessible method net/minecraft/world/level/block/entity/BlockEntity saveMetadata (Lnet/minecraft/nbt/CompoundTag;)Lnet/minecraft/nbt/CompoundTag;
#accessible method net/minecraft/world/level/block/entity/BlockEntity saveMetadata (Lnet/minecraft/nbt/CompoundTag;)Lnet/minecraft/nbt/CompoundTag;
accessible method net/minecraft/commands/arguments/blocks/BlockStateParser parse (Z)Lnet/minecraft/commands/arguments/blocks/BlockStateParser;
#accessible method net/minecraft/commands/arguments/blocks/BlockStateParser parse (Z)Lnet/minecraft/commands/arguments/blocks/BlockStateParser;
accessible method net/minecraft/world/item/crafting/ShapedRecipe shrink ([Ljava/lang/String;)[Ljava/lang/String;
accessible method net/minecraft/world/item/crafting/ShapedRecipe keyFromJson (Lcom/google/gson/JsonObject;)Ljava/util/Map;