diff --git a/core-api/src/main/java/dev/compactmods/machines/api/CompactMachines.java b/core-api/src/main/java/dev/compactmods/machines/api/CompactMachines.java index 93cd8c7c..2cf98c8c 100644 --- a/core-api/src/main/java/dev/compactmods/machines/api/CompactMachines.java +++ b/core-api/src/main/java/dev/compactmods/machines/api/CompactMachines.java @@ -1,97 +1,115 @@ -package dev.compactmods.machines.api; - -import dev.compactmods.machines.api.dimension.CompactDimension; -import dev.compactmods.machines.api.dimension.MissingDimensionException; -import dev.compactmods.machines.api.room.CompactRoomGenerator; -import dev.compactmods.machines.api.room.IRoomApi; -import dev.compactmods.machines.api.room.RoomInstance; -import dev.compactmods.machines.api.room.RoomTemplate; -import dev.compactmods.machines.api.room.data.IRoomDataAttachmentAccessor; -import dev.compactmods.machines.api.room.history.IPlayerHistoryApi; -import dev.compactmods.machines.api.room.upgrade.RoomUpgradeDefinition; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.MinecraftServer; -import net.neoforged.neoforge.attachment.AttachmentHolder; -import net.neoforged.neoforge.attachment.IAttachmentHolder; -import net.neoforged.neoforge.registries.DeferredRegister; -import org.jetbrains.annotations.ApiStatus; - -import java.util.Optional; -import java.util.UUID; - -public class CompactMachines { - public final static String MOD_ID = "compactmachines"; - - public static String id(String path) { - return ResourceLocation.isValidPath(path) ? (MOD_ID + ":" + path) : MOD_ID + ":invalid"; - } - - public static ResourceLocation modRL(String path) { - return ResourceLocation.fromNamespaceAndPath(MOD_ID, path); - } - - public static DeferredRegister> roomUpgradeDR(String namespace) { - return DeferredRegister.create(RoomUpgradeDefinition.REG_KEY, namespace); - } - - public static IRoomApi roomApi() { - return Internal.ROOM_API; - } - - public static IPlayerHistoryApi playerHistoryApi() { - return Internal.PLAYER_HISTORY_API; - } - - public static Optional room(String roomCode) { - return Internal.ROOM_API.registrar().get(roomCode); - } - - /** - * Registers a new room instance and generates the structure in the compact world. - * - * @param server Server to generate room on. - * @param template - * @param owner - * @return - */ - public static RoomInstance newRoom(MinecraftServer server, RoomTemplate template, UUID owner) throws MissingDimensionException { - final var instance = CompactMachines.roomApi().registrar().createNew(template, owner); - final var compactDim = CompactDimension.forServer(server); - CompactRoomGenerator.generateRoom(compactDim, instance.boundaries().outerBounds()); - - if(!template.structures().isEmpty()) { - for(var struct : template.structures()) { - CompactRoomGenerator.populateStructure(compactDim, struct.template(), instance.boundaries().innerBounds(), struct.placement()); - } - } - - return instance; - } - - public static boolean isValidRoomCode(String roomCode) { - return Internal.ROOM_API.roomCodeValidator().test(roomCode); - } - - public static Optional existingRoomData(String code) { - return Internal.ROOM_DATA_ACCESSOR.get(code); - } - - public static IAttachmentHolder roomData(String code) { - return Internal.ROOM_DATA_ACCESSOR.getOrCreate(code); - } - - - /** - * Set up when the server or single-player instance changes. - * NOT for API consumers to use! Use the methods provided here for safety. - * - * @since 6.0.0 - */ - @ApiStatus.Internal - @Deprecated - public final class Internal { - public static IRoomApi ROOM_API; - public static IRoomDataAttachmentAccessor ROOM_DATA_ACCESSOR; - public static IPlayerHistoryApi PLAYER_HISTORY_API; - } -} +package dev.compactmods.machines.api; + +import dev.compactmods.machines.api.dimension.CompactDimension; +import dev.compactmods.machines.api.dimension.MissingDimensionException; +import dev.compactmods.machines.api.room.CompactRoomGenerator; +import dev.compactmods.machines.api.room.IRoomApi; +import dev.compactmods.machines.api.room.RoomInstance; +import dev.compactmods.machines.api.room.template.RoomTemplate; +import dev.compactmods.machines.api.room.data.IRoomDataAttachmentAccessor; +import dev.compactmods.machines.api.room.history.IPlayerHistoryApi; +import dev.compactmods.machines.api.room.upgrade.RoomUpgradeDefinition; +import dev.compactmods.machines.api.util.BlockSpaceUtil; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec2; +import net.neoforged.neoforge.attachment.IAttachmentHolder; +import net.neoforged.neoforge.registries.DeferredRegister; +import org.jetbrains.annotations.ApiStatus; + +import java.util.Optional; +import java.util.UUID; + +public class CompactMachines { + public final static String MOD_ID = "compactmachines"; + + public static String id(String path) { + return ResourceLocation.isValidPath(path) ? (MOD_ID + ":" + path) : MOD_ID + ":invalid"; + } + + public static ResourceLocation modRL(String path) { + return ResourceLocation.fromNamespaceAndPath(MOD_ID, path); + } + + public static DeferredRegister> roomUpgradeDR(String namespace) { + return DeferredRegister.create(RoomUpgradeDefinition.REG_KEY, namespace); + } + + public static IRoomApi roomApi() { + return Internal.ROOM_API; + } + + public static IPlayerHistoryApi playerHistoryApi() { + return Internal.PLAYER_HISTORY_API; + } + + public static Optional room(String roomCode) { + return Internal.ROOM_API.registrar().get(roomCode); + } + + /** + * Registers a new room instance and generates the structure in the compact world. + * + * @param server Server to generate room on. + * @param template + * @param owner + * @return + */ + public static RoomInstance newRoom(MinecraftServer server, RoomTemplate template, UUID owner) throws MissingDimensionException { + final var instance = CompactMachines.roomApi().registrar().createNew(template, owner); + final var compactDim = CompactDimension.forServer(server); + CompactRoomGenerator.generateRoom(compactDim, instance.boundaries().outerBounds()); + + if (!template.structures().isEmpty()) { + for (var struct : template.structures()) { + CompactRoomGenerator.populateStructure(compactDim, struct.template(), instance.boundaries().innerBounds(), struct.placement()); + } + } + + final var spawnManager = CompactMachines.roomApi().spawnManager(instance.code()); + template.optionalFloor().ifPresent(floorState -> { + var fixedSpawn = instance.boundaries() + .defaultSpawn() + .add(0, 1, 0); + + spawnManager.setDefaultSpawn(fixedSpawn, Vec2.ZERO); + + AABB floorBounds = BlockSpaceUtil.getWallBounds(instance.boundaries().innerBounds(), Direction.DOWN); + BlockSpaceUtil.blocksInside(floorBounds).forEach(floorBlockPos -> { + compactDim.setBlock(floorBlockPos, floorState, Block.UPDATE_ALL); + }); + }); + + return instance; + } + + public static boolean isValidRoomCode(String roomCode) { + return Internal.ROOM_API.roomCodeValidator().test(roomCode); + } + + public static Optional existingRoomData(String code) { + return Internal.ROOM_DATA_ACCESSOR.get(code); + } + + public static IAttachmentHolder roomData(String code) { + return Internal.ROOM_DATA_ACCESSOR.getOrCreate(code); + } + + + /** + * Set up when the server or single-player instance changes. + * NOT for API consumers to use! Use the methods provided here for safety. + * + * @since 6.0.0 + */ + @ApiStatus.Internal + @Deprecated + public final class Internal { + public static IRoomApi ROOM_API; + public static IRoomDataAttachmentAccessor ROOM_DATA_ACCESSOR; + public static IPlayerHistoryApi PLAYER_HISTORY_API; + } +} diff --git a/core-api/src/main/java/dev/compactmods/machines/api/room/RoomComponents.java b/core-api/src/main/java/dev/compactmods/machines/api/room/RoomComponents.java deleted file mode 100644 index 8f705f5d..00000000 --- a/core-api/src/main/java/dev/compactmods/machines/api/room/RoomComponents.java +++ /dev/null @@ -1,13 +0,0 @@ -package dev.compactmods.machines.api.room; - -import net.minecraft.core.component.DataComponentType; - -import java.util.function.UnaryOperator; - -public interface RoomComponents { - - UnaryOperator> ROOM_TEMPLATE = (builder) -> builder - .persistent(RoomTemplate.CODEC) - .networkSynchronized(RoomTemplate.STREAM_CODEC); - -} diff --git a/core-api/src/main/java/dev/compactmods/machines/api/room/data/CMRoomDataLocations.java b/core-api/src/main/java/dev/compactmods/machines/api/room/data/CMRoomDataLocations.java index c92cb47a..b477e299 100644 --- a/core-api/src/main/java/dev/compactmods/machines/api/room/data/CMRoomDataLocations.java +++ b/core-api/src/main/java/dev/compactmods/machines/api/room/data/CMRoomDataLocations.java @@ -1,25 +1,21 @@ -package dev.compactmods.machines.api.room.data; - -import dev.compactmods.machines.api.CompactMachines; -import net.minecraft.server.MinecraftServer; -import net.minecraft.world.level.storage.LevelResource; - -import java.nio.file.Path; -import java.util.function.Function; - -public interface CMRoomDataLocations { - - Function REGISTRATION_DATA = (server) -> server.getWorldPath(LevelResource.ROOT) - .resolve(CompactMachines.MOD_ID) - .resolve("data"); - - Function SPAWN_DATA = (server) -> server.getWorldPath(LevelResource.ROOT) - .resolve(CompactMachines.MOD_ID) - .resolve("data") - .resolve("spawn_data"); - - Function ROOM_DATA_ATTACHMENTS = (server) -> server.getWorldPath(LevelResource.ROOT) - .resolve(CompactMachines.MOD_ID) - .resolve("data") - .resolve("room_data"); -} +package dev.compactmods.machines.api.room.data; + +import dev.compactmods.machines.api.CompactMachines; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.storage.LevelResource; + +import java.nio.file.Path; +import java.util.function.Function; + +public interface CMRoomDataLocations { + + Function DATA_ROOT = (server) -> server.getWorldPath(LevelResource.ROOT) + .resolve(CompactMachines.MOD_ID); + + Function PLAYER_SPAWNS = (server) -> DATA_ROOT.apply(server) + .resolve("player_spawns"); + + Function ROOM_DATA_ATTACHMENTS = (server) -> DATA_ROOT.apply(server) + .resolve("room_data"); + +} diff --git a/core-api/src/main/java/dev/compactmods/machines/api/room/registration/IRoomRegistrar.java b/core-api/src/main/java/dev/compactmods/machines/api/room/registration/IRoomRegistrar.java index 5b7fb79f..fa7dd372 100644 --- a/core-api/src/main/java/dev/compactmods/machines/api/room/registration/IRoomRegistrar.java +++ b/core-api/src/main/java/dev/compactmods/machines/api/room/registration/IRoomRegistrar.java @@ -1,43 +1,42 @@ -package dev.compactmods.machines.api.room.registration; - -import dev.compactmods.machines.api.room.RoomInstance; -import dev.compactmods.machines.api.room.RoomTemplate; -import dev.compactmods.machines.api.room.registration.IRoomBuilder; -import net.minecraft.world.phys.AABB; - -import java.util.Optional; -import java.util.UUID; -import java.util.function.Consumer; -import java.util.stream.Stream; - -public interface IRoomRegistrar { - - AABB getNextBoundaries(RoomTemplate template); - - IRoomBuilder builder(); - - default RoomInstance createNew(RoomTemplate template, UUID owner) { - return createNew(template, owner, override -> {}); - } - - default RoomInstance createNew(RoomTemplate template, UUID owner, Consumer override) { - final Consumer preOverride = builder -> builder.defaultMachineColor(template.defaultMachineColor()) - .owner(owner) - .boundaries(getNextBoundaries(template)); - - // Make builder, set template defaults, then allow overrides - final var b = builder(); - preOverride.andThen(override).accept(b); - return b.build(); - } - - boolean isRegistered(String room); - - Optional get(String room); - - long count(); - - Stream allRoomCodes(); - - Stream allRooms(); -} +package dev.compactmods.machines.api.room.registration; + +import dev.compactmods.machines.api.room.RoomInstance; +import dev.compactmods.machines.api.room.template.RoomTemplate; +import net.minecraft.world.phys.AABB; + +import java.util.Optional; +import java.util.UUID; +import java.util.function.Consumer; +import java.util.stream.Stream; + +public interface IRoomRegistrar { + + AABB getNextBoundaries(RoomTemplate template); + + IRoomBuilder builder(); + + default RoomInstance createNew(RoomTemplate template, UUID owner) { + return createNew(template, owner, override -> {}); + } + + default RoomInstance createNew(RoomTemplate template, UUID owner, Consumer override) { + final Consumer preOverride = builder -> builder.defaultMachineColor(template.defaultMachineColor()) + .owner(owner) + .boundaries(getNextBoundaries(template)); + + // Make builder, set template defaults, then allow overrides + final var b = builder(); + preOverride.andThen(override).accept(b); + return b.build(); + } + + boolean isRegistered(String room); + + Optional get(String room); + + long count(); + + Stream allRoomCodes(); + + Stream allRooms(); +} diff --git a/core-api/src/main/java/dev/compactmods/machines/api/room/RoomTemplate.java b/core-api/src/main/java/dev/compactmods/machines/api/room/template/RoomTemplate.java similarity index 81% rename from core-api/src/main/java/dev/compactmods/machines/api/room/RoomTemplate.java rename to core-api/src/main/java/dev/compactmods/machines/api/room/template/RoomTemplate.java index 7c143ddb..c7552566 100644 --- a/core-api/src/main/java/dev/compactmods/machines/api/room/RoomTemplate.java +++ b/core-api/src/main/java/dev/compactmods/machines/api/room/template/RoomTemplate.java @@ -1,86 +1,93 @@ -package dev.compactmods.machines.api.room; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import dev.compactmods.machines.api.CompactMachines; -import dev.compactmods.machines.api.machine.MachineColor; -import dev.compactmods.machines.api.machine.MachineTranslations; -import net.minecraft.ChatFormatting; -import net.minecraft.core.Registry; -import net.minecraft.network.RegistryFriendlyByteBuf; -import net.minecraft.network.chat.Component; -import net.minecraft.network.codec.ByteBufCodecs; -import net.minecraft.network.codec.StreamCodec; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.TooltipFlag; -import net.minecraft.world.item.component.TooltipProvider; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; - -import java.util.Collections; -import java.util.List; -import java.util.function.Consumer; - -/** - * Template structure for creating a new Compact Machine room. These can be added and removed from the registry - * at any point, so persistent data must be stored outside these instances. - * - * @param internalDimensions The internal dimensions of the room when it is created. - * @param defaultMachineColor The color of the machine blocks created for this template. - * @param structures Information used to fill a newly-created room with structures. - */ -public record RoomTemplate(RoomDimensions internalDimensions, MachineColor defaultMachineColor, List structures) - implements TooltipProvider { - - public static final ResourceKey> REGISTRY_KEY = ResourceKey.createRegistryKey(CompactMachines.modRL("room_templates")); - - public static final ResourceLocation NO_TEMPLATE = CompactMachines.modRL("empty"); - - public static final RoomTemplate INVALID_TEMPLATE = new RoomTemplate(0, 0); - - public static Codec CODEC = RecordCodecBuilder.create(i -> i.group( - RoomDimensions.CODEC.fieldOf("dimensions").forGetter(RoomTemplate::internalDimensions), - MachineColor.CODEC.fieldOf("color").forGetter(RoomTemplate::defaultMachineColor), - RoomStructureInfo.CODEC.listOf().optionalFieldOf("structures", Collections.emptyList()) - .forGetter(RoomTemplate::structures) - ).apply(i, RoomTemplate::new)); - - public static final StreamCodec STREAM_CODEC = StreamCodec.composite( - RoomDimensions.STREAM_CODEC, RoomTemplate::internalDimensions, - MachineColor.STREAM_CODEC, RoomTemplate::defaultMachineColor, - RoomStructureInfo.STREAM_CODEC.apply(ByteBufCodecs.list()), RoomTemplate::structures, - RoomTemplate::new - ); - - public RoomTemplate(int cubicSizeInternal, int colorARGB) { - this(RoomDimensions.cubic(cubicSizeInternal), MachineColor.fromARGB(colorARGB), Collections.emptyList()); - } - - public RoomTemplate(int cubicSizeInternal, MachineColor color) { - this(RoomDimensions.cubic(cubicSizeInternal), color, Collections.emptyList()); - } - - public AABB getZeroBoundaries() { - return AABB.ofSize(Vec3.ZERO, internalDimensions.width(), internalDimensions.height(), internalDimensions.depth()) - .inflate(1) - .move(0, internalDimensions.height() / 2f, 0); - } - - public AABB getBoundariesCenteredAt(Vec3 center) { - return AABB.ofSize(center, internalDimensions.width(), internalDimensions.height(), internalDimensions.depth()) - .inflate(1); - } - - @Override - public void addToTooltip(Item.TooltipContext ctx, Consumer tooltips, TooltipFlag flags) { - final var roomDimensions = internalDimensions(); - - tooltips.accept(MachineTranslations.SIZE.apply(roomDimensions.toString())); - - if (!structures().isEmpty()) { - tooltips.accept(Component.literal("Generates " + structures().size() + " structures after creation.").withStyle(ChatFormatting.DARK_GRAY)); - } - } -} +package dev.compactmods.machines.api.room.template; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import dev.compactmods.machines.api.CompactMachines; +import dev.compactmods.machines.api.machine.MachineColor; +import dev.compactmods.machines.api.machine.MachineTranslations; +import dev.compactmods.machines.api.room.RoomDimensions; +import dev.compactmods.machines.api.room.RoomStructureInfo; +import net.minecraft.ChatFormatting; +import net.minecraft.core.Registry; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.component.TooltipProvider; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; + +/** + * Template structure for creating a new Compact Machine room. These can be added and removed from the registry + * at any point, so persistent data must be stored outside these instances. + * + * @param internalDimensions The internal dimensions of the room when it is created. + * @param defaultMachineColor The color of the machine blocks created for this template. + * @param structures Information used to fill a newly-created room with structures. + */ +public record RoomTemplate(RoomDimensions internalDimensions, MachineColor defaultMachineColor, List structures, Optional optionalFloor) + implements TooltipProvider { + + public static final ResourceKey> REGISTRY_KEY = ResourceKey.createRegistryKey(CompactMachines.modRL("room_templates")); + + public static final ResourceLocation NO_TEMPLATE = CompactMachines.modRL("empty"); + + public static final RoomTemplate INVALID_TEMPLATE = new RoomTemplate(0, 0); + + public static Codec CODEC = RecordCodecBuilder.create(i -> i.group( + RoomDimensions.CODEC.fieldOf("dimensions").forGetter(RoomTemplate::internalDimensions), + MachineColor.CODEC.fieldOf("color").forGetter(RoomTemplate::defaultMachineColor), + RoomStructureInfo.CODEC.listOf().optionalFieldOf("structures", Collections.emptyList()) + .forGetter(RoomTemplate::structures), + BlockState.CODEC.optionalFieldOf("floor").forGetter(RoomTemplate::optionalFloor) + ).apply(i, RoomTemplate::new)); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + RoomDimensions.STREAM_CODEC, RoomTemplate::internalDimensions, + MachineColor.STREAM_CODEC, RoomTemplate::defaultMachineColor, + RoomStructureInfo.STREAM_CODEC.apply(ByteBufCodecs.list()), RoomTemplate::structures, + ByteBufCodecs.optional(ByteBufCodecs.idMapper(Block.BLOCK_STATE_REGISTRY)), RoomTemplate::optionalFloor, + RoomTemplate::new + ); + + public static RoomTemplateBuilder builder() { + return new RoomTemplateBuilder(); + } + + public RoomTemplate(int cubicSizeInternal, int colorARGB) { + this(RoomDimensions.cubic(cubicSizeInternal), MachineColor.fromARGB(colorARGB), Collections.emptyList(), Optional.empty()); + } + + public AABB getZeroBoundaries() { + return AABB.ofSize(Vec3.ZERO, internalDimensions.width(), internalDimensions.height(), internalDimensions.depth()) + .inflate(1) + .move(0, internalDimensions.height() / 2f, 0); + } + + public AABB getBoundariesCenteredAt(Vec3 center) { + return AABB.ofSize(center, internalDimensions.width(), internalDimensions.height(), internalDimensions.depth()) + .inflate(1); + } + + @Override + public void addToTooltip(Item.TooltipContext ctx, Consumer tooltips, TooltipFlag flags) { + final var roomDimensions = internalDimensions(); + + tooltips.accept(MachineTranslations.SIZE.apply(roomDimensions.toString())); + + if (!structures().isEmpty()) { + tooltips.accept(Component.literal("Generates " + structures().size() + " structures after creation.").withStyle(ChatFormatting.DARK_GRAY)); + } + } +} diff --git a/core-api/src/main/java/dev/compactmods/machines/api/room/template/RoomTemplateBuilder.java b/core-api/src/main/java/dev/compactmods/machines/api/room/template/RoomTemplateBuilder.java new file mode 100644 index 00000000..141fa169 --- /dev/null +++ b/core-api/src/main/java/dev/compactmods/machines/api/room/template/RoomTemplateBuilder.java @@ -0,0 +1,62 @@ +package dev.compactmods.machines.api.room.template; + +import com.google.common.collect.ImmutableList; +import dev.compactmods.machines.api.machine.MachineColor; +import dev.compactmods.machines.api.room.RoomDimensions; +import dev.compactmods.machines.api.room.RoomStructureInfo; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.CommonColors; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.Optional; + +public class RoomTemplateBuilder { + + private RoomDimensions sizeInternal; + private MachineColor defaultMachineColor; + private ImmutableList.Builder structures = ImmutableList.builder(); + + @Nullable + private BlockState floor; + + RoomTemplateBuilder() { + this.sizeInternal = RoomDimensions.cubic(3); + this.defaultMachineColor = MachineColor.fromARGB(CommonColors.WHITE); + } + + public RoomTemplateBuilder withInternalSizeCubic(int size) { + this.sizeInternal = RoomDimensions.cubic(size); + return this; + } + + public RoomTemplateBuilder withInternalSize(int width, int depth, int height) { + this.sizeInternal = new RoomDimensions(width, depth, height); + return this; + } + + public RoomTemplateBuilder withInternalSize(RoomDimensions internalSize) { + this.sizeInternal = internalSize; + return this; + } + + public RoomTemplateBuilder defaultMachineColor(MachineColor color) { + this.defaultMachineColor = color; + return this; + } + + public RoomTemplateBuilder addStructure(ResourceLocation template, RoomStructureInfo.RoomStructurePlacement placement) { + this.structures.add(new RoomStructureInfo(template, placement)); + return this; + } + + public RoomTemplateBuilder withFloor(BlockState floor) { + this.floor = floor; + return this; + } + + public RoomTemplate build() { + return new RoomTemplate(sizeInternal, defaultMachineColor, structures.build(), Optional.ofNullable(floor)); + } +} diff --git a/core-api/src/main/java/dev/compactmods/machines/api/room/template/RoomTemplateHelper.java b/core-api/src/main/java/dev/compactmods/machines/api/room/template/RoomTemplateHelper.java new file mode 100644 index 00000000..af920666 --- /dev/null +++ b/core-api/src/main/java/dev/compactmods/machines/api/room/template/RoomTemplateHelper.java @@ -0,0 +1,36 @@ +package dev.compactmods.machines.api.room.template; + +import net.minecraft.core.Holder; +import net.minecraft.core.RegistryAccess; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.LevelReader; + +import java.util.Optional; + +public class RoomTemplateHelper { + + public static RoomTemplate getTemplate(LevelReader levelReader, ResourceLocation id) { + return getTemplateOptional(levelReader.registryAccess(), id) + .orElse(RoomTemplate.INVALID_TEMPLATE); + } + + public static RoomTemplate getTemplate(RegistryAccess registryAccess, ResourceLocation id) { + return getTemplateOptional(registryAccess, id) + .orElse(RoomTemplate.INVALID_TEMPLATE); + } + + public static Optional getTemplateOptional(RegistryAccess registryAccess, ResourceLocation id) { + return registryAccess.registryOrThrow(RoomTemplate.REGISTRY_KEY) + .getOptional(id); + } + + public static Holder.Reference getTemplateHolder(LevelReader levelReader, ResourceLocation id) { + return getTemplateHolder(levelReader.registryAccess(), id); + } + + public static Holder.Reference getTemplateHolder(RegistryAccess registryAccess, ResourceLocation id) { + return registryAccess.registryOrThrow(RoomTemplate.REGISTRY_KEY) + .getHolderOrThrow(ResourceKey.create(RoomTemplate.REGISTRY_KEY, id)); + } +} diff --git a/gradle.properties b/gradle.properties index e20999c1..78b6dbcf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,12 +1,15 @@ -# Sets default memory used for gradle commands. Can be overridden by user or command line properties. -# This is required to provide enough memory for the Minecraft decompilation process. -org.gradle.jvmargs=-Xmx3G -# org.gradle.configuration-cache=true - -neoForge.parchment.minecraftVersion=1.20.6 -neoForge.parchment.mappingsVersion=2024.05.01 - -neogradle.subsystems.conventions.runs.create-default-run-per-type=false - -# Curseforge +# Sets default memory used for gradle commands. Can be overridden by user or command line properties. +# This is required to provide enough memory for the Minecraft decompilation process. +org.gradle.jvmargs=-Xmx3G +org.gradle.daemon=true +org.gradle.parallel=true +# org.gradle.caching=true +org.gradle.configuration-cache=true + +neoForge.parchment.minecraftVersion=1.20.6 +neoForge.parchment.mappingsVersion=2024.05.01 + +neogradle.subsystems.conventions.runs.create-default-run-per-type=false + +# Curseforge cf_project=224218 \ No newline at end of file diff --git a/neoforge-datagen/build.gradle.kts b/neoforge-datagen/build.gradle.kts index 7fb233cf..46e03270 100644 --- a/neoforge-datagen/build.gradle.kts +++ b/neoforge-datagen/build.gradle.kts @@ -1,63 +1,85 @@ -import org.slf4j.event.Level - -plugins { - id("java") - id("eclipse") - id("idea") - id("maven-publish") - alias(neoforged.plugins.moddev) -} - -val modId: String = "compactmachines" - -val coreApi = project(":core-api") -val mainProject: Project = project(":neoforge-main") - -project.evaluationDependsOn(coreApi.path) -project.evaluationDependsOn(mainProject.path) - -java { - toolchain.languageVersion.set(JavaLanguageVersion.of(21)) -} - -neoForge { - version = neoforged.versions.neoforge - - this.mods.create(modId) { - sourceSet(sourceSets.main.get()) - sourceSet(coreApi.sourceSets.main.get()) - sourceSet(mainProject.sourceSets.main.get()) - } - - this.runs { - configureEach { - logLevel.set(Level.DEBUG) - } - - create("data") { - data() - - programArguments.addAll("--mod", modId) - programArguments.addAll("--all") - programArguments.addAll("--output", mainProject.file("src/generated/resources").absolutePath) - programArguments.addAll("--existing", mainProject.file("src/main/resources").absolutePath) - } - } -} - -repositories { - mavenLocal() -} - -dependencies { - compileOnly(coreApi) - compileOnly(mainProject) -} - -tasks.compileJava { - options.encoding = "UTF-8"; -} - -tasks.withType { - duplicatesStrategy = DuplicatesStrategy.EXCLUDE +import org.slf4j.event.Level + +plugins { + id("java") + id("eclipse") + id("idea") + id("maven-publish") + alias(neoforged.plugins.moddev) +} + +val modId: String = "compactmachines" + +val coreApi = project(":core-api") +val mainProject: Project = project(":neoforge-main") + +project.evaluationDependsOn(coreApi.path) +project.evaluationDependsOn(mainProject.path) + +java { + toolchain.languageVersion.set(JavaLanguageVersion.of(21)) +} + +minecraft { + this.modIdentifier = modId +} + +runs { + configureEach { + this.modSource(coreApi.sourceSets.main.get()) + this.modSource(sourceSets.main.get()) + this.modSource(mainProject.sourceSets.main.get()) + + dependencies { + runtime(libraries.feather) + runtime(libraries.jnanoid) + } + } + + this.create("data") { + this.dataGenerator() + + this.workingDirectory.set(file("runs/data")) + + // Comma-separated list of namespaces to load gametests from. Empty = all namespaces. + systemProperty("forge.enabledGameTestNamespaces", modId) + + programArguments.addAll("--mod", modId) + programArguments.addAll("--all") + programArguments.addAll("--output", mainProject.file("src/generated/resources").absolutePath) + programArguments.addAll("--existing", mainProject.file("src/main/resources").absolutePath) + } +} + +repositories { + mavenLocal() + + maven("https://maven.pkg.github.com/compactmods/feather") { + name = "Github PKG Core" + credentials { + username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR") + password = project.findProperty("gpr.token") as String? ?: System.getenv("GITHUB_TOKEN") + } + } + + // https://github.com/neoforged/NeoForge/pull/1303 + maven("https://prmaven.neoforged.net/NeoForge/pr1303") { + content { + includeModule("net.neoforged", "neoforge") + } + } +} + +dependencies { + implementation("net.neoforged:neoforge:21.0.159-pr-1303-feat-recipe-provider-lookup") + compileOnly(coreApi) + compileOnly(mainProject) +} + +tasks.compileJava { + options.encoding = "UTF-8"; +} + +tasks.withType { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE } \ No newline at end of file diff --git a/neoforge-datagen/src/main/java/dev.compactmods.machines.datagen/DataGeneration.java b/neoforge-datagen/src/main/java/dev.compactmods.machines.datagen/DataGeneration.java index 289b348f..c9c98fbf 100644 --- a/neoforge-datagen/src/main/java/dev.compactmods.machines.datagen/DataGeneration.java +++ b/neoforge-datagen/src/main/java/dev.compactmods.machines.datagen/DataGeneration.java @@ -1,59 +1,60 @@ -package dev.compactmods.machines.datagen; - -import dev.compactmods.machines.api.CompactMachines; -import dev.compactmods.machines.datagen.compat.curios.CurioEntityGenerator; -import dev.compactmods.machines.datagen.compat.curios.CurioSlotGenerator; -import dev.compactmods.machines.datagen.lang.EnglishLangGenerator; -import dev.compactmods.machines.datagen.loot.BlockLootGenerator; -import dev.compactmods.machines.datagen.tags.BlockTagGenerator; -import dev.compactmods.machines.datagen.tags.ItemTagGenerator; -import dev.compactmods.machines.datagen.tags.PointOfInterestTagGenerator; -import net.minecraft.data.loot.LootTableProvider; -import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; -import net.neoforged.bus.api.SubscribeEvent; -import net.neoforged.fml.common.EventBusSubscriber; -import net.neoforged.neoforge.data.event.GatherDataEvent; - -import java.util.Collections; -import java.util.List; - -@EventBusSubscriber(modid = CompactMachines.MOD_ID, bus = EventBusSubscriber.Bus.MOD) -public class DataGeneration { - - @SubscribeEvent - public static void gatherData(GatherDataEvent event) { - final var fileHelper = event.getExistingFileHelper(); - final var generator = event.getGenerator(); - - final var packOut = generator.getPackOutput(); - final var holderLookup = event.getLookupProvider(); - - // Server - boolean server = event.includeServer(); - generator.addProvider(server, new DatapackRegisteredStuff(packOut, holderLookup)); - generator.addProvider(server, new LootTableProvider(packOut, - Collections.emptySet(), - List.of(new LootTableProvider.SubProviderEntry(BlockLootGenerator::new, LootContextParamSets.BLOCK)), - holderLookup - )); - - generator.addProvider(server, new RecipeGenerator(packOut, holderLookup)); - - final var blocks = new BlockTagGenerator(packOut, fileHelper, holderLookup); - generator.addProvider(server, blocks); - generator.addProvider(server, new ItemTagGenerator(packOut, blocks, holderLookup)); - - // CURIOS Integration - generator.addProvider(server, new CurioSlotGenerator(packOut, holderLookup, fileHelper)); - generator.addProvider(server, new CurioEntityGenerator(packOut, holderLookup, fileHelper)); - - generator.addProvider(server, new PointOfInterestTagGenerator(packOut, holderLookup, fileHelper)); - - // Client - boolean client = event.includeClient(); - generator.addProvider(client, new StateGenerator(packOut, fileHelper)); - generator.addProvider(client, new ItemModelGenerator(packOut, fileHelper)); - - generator.addProvider(client, new EnglishLangGenerator(generator)); - } -} +package dev.compactmods.machines.datagen; + +import dev.compactmods.machines.api.CompactMachines; +import dev.compactmods.machines.datagen.compat.curios.CurioEntityGenerator; +import dev.compactmods.machines.datagen.compat.curios.CurioSlotGenerator; +import dev.compactmods.machines.datagen.lang.EnglishLangGenerator; +import dev.compactmods.machines.datagen.loot.BlockLootGenerator; +import dev.compactmods.machines.datagen.tags.BlockTagGenerator; +import dev.compactmods.machines.datagen.tags.ItemTagGenerator; +import dev.compactmods.machines.datagen.tags.PointOfInterestTagGenerator; +import net.minecraft.data.loot.LootTableProvider; +import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.data.event.GatherDataEvent; + +import java.util.Collections; +import java.util.List; + +@EventBusSubscriber(modid = CompactMachines.MOD_ID, bus = EventBusSubscriber.Bus.MOD) +public class DataGeneration { + + @SubscribeEvent + public static void gatherData(GatherDataEvent event) { + final var fileHelper = event.getExistingFileHelper(); + final var generator = event.getGenerator(); + + final var packOut = generator.getPackOutput(); + final var holderLookup = event.getLookupProvider(); + + // Server + boolean server = event.includeServer(); + + var dataRegistered = generator.addProvider(server, new DatapackRegisteredStuff(packOut, holderLookup)); + generator.addProvider(server, new LootTableProvider(packOut, + Collections.emptySet(), + List.of(new LootTableProvider.SubProviderEntry(BlockLootGenerator::new, LootContextParamSets.BLOCK)), + holderLookup + )); + + generator.addProvider(server, new RecipeGenerator(packOut, dataRegistered.getRegistryProvider())); + + final var blocks = new BlockTagGenerator(packOut, fileHelper, holderLookup); + generator.addProvider(server, blocks); + generator.addProvider(server, new ItemTagGenerator(packOut, blocks, holderLookup)); + + // CURIOS Integration + generator.addProvider(server, new CurioSlotGenerator(packOut, holderLookup, fileHelper)); + generator.addProvider(server, new CurioEntityGenerator(packOut, holderLookup, fileHelper)); + + generator.addProvider(server, new PointOfInterestTagGenerator(packOut, holderLookup, fileHelper)); + + // Client + boolean client = event.includeClient(); + generator.addProvider(client, new StateGenerator(packOut, fileHelper)); + generator.addProvider(client, new ItemModelGenerator(packOut, fileHelper)); + + generator.addProvider(client, new EnglishLangGenerator(generator)); + } +} diff --git a/neoforge-datagen/src/main/java/dev.compactmods.machines.datagen/DatapackRegisteredStuff.java b/neoforge-datagen/src/main/java/dev.compactmods.machines.datagen/DatapackRegisteredStuff.java index 1d811514..84bcc694 100644 --- a/neoforge-datagen/src/main/java/dev.compactmods.machines.datagen/DatapackRegisteredStuff.java +++ b/neoforge-datagen/src/main/java/dev.compactmods.machines.datagen/DatapackRegisteredStuff.java @@ -1,111 +1,123 @@ -package dev.compactmods.machines.datagen; - -import dev.compactmods.machines.api.room.RoomTemplate; -import dev.compactmods.machines.api.CompactMachines; -import dev.compactmods.machines.api.dimension.CompactDimension; -import dev.compactmods.machines.datagen.util.DimensionTypeBuilder; -import dev.compactmods.machines.dimension.Dimension; -import net.minecraft.core.HolderLookup; -import net.minecraft.core.RegistrySetBuilder; -import net.minecraft.core.registries.Registries; -import net.minecraft.data.PackOutput; -import net.minecraft.data.worldgen.BiomeDefaultFeatures; -import net.minecraft.data.worldgen.BootstrapContext; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.FastColor; -import net.minecraft.world.level.biome.Biome; -import net.minecraft.world.level.biome.BiomeGenerationSettings; -import net.minecraft.world.level.biome.BiomeSpecialEffects; -import net.minecraft.world.level.biome.MobSpawnSettings; -import net.minecraft.world.level.dimension.DimensionType; -import net.minecraft.world.level.dimension.LevelStem; -import net.minecraft.world.level.levelgen.FlatLevelSource; -import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; -import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; -import net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider; - -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.CompletableFuture; - -public class DatapackRegisteredStuff extends DatapackBuiltinEntriesProvider { - private static final ResourceLocation COMPACT_BIOME = CompactMachines.modRL("machine"); - private static final int DIMENSION_HEIGHT = 48; - - private static final RegistrySetBuilder BUILDER = new RegistrySetBuilder() - .add(Registries.BIOME, DatapackRegisteredStuff::generateBiomes) - .add(Registries.DIMENSION_TYPE, DatapackRegisteredStuff::generateDimensionTypes) - .add(Registries.LEVEL_STEM, DatapackRegisteredStuff::generateDimensions) - .add(RoomTemplate.REGISTRY_KEY, DatapackRegisteredStuff::addRoomTemplates); - - DatapackRegisteredStuff(PackOutput packOutput, CompletableFuture registries) { - super(packOutput, registries, BUILDER, Set.of(CompactMachines.MOD_ID)); - } - - private static void generateBiomes(BootstrapContext ctx) { - var spawnBuilder = new MobSpawnSettings.Builder(); - BiomeDefaultFeatures.plainsSpawns(spawnBuilder); - var spawns = spawnBuilder.build(); - - final Biome compactBiome = new Biome.BiomeBuilder() - .downfall(0) - .generationSettings(BiomeGenerationSettings.EMPTY) - .mobSpawnSettings(spawns) - .hasPrecipitation(false) - .temperature(0.8f) - .temperatureAdjustment(Biome.TemperatureModifier.NONE) - .specialEffects(new BiomeSpecialEffects.Builder() - .fogColor(12638463) - .waterColor(4159204) - .waterFogColor(329011) - .skyColor(0xFF000000) - .build()) - .build(); - - ctx.register(ResourceKey.create(Registries.BIOME, COMPACT_BIOME), compactBiome); - } - - private static void generateDimensionTypes(BootstrapContext ctx) { - ctx.register(CompactDimension.DIM_TYPE_KEY, new DimensionTypeBuilder() - .bedWorks(false) - .respawnAnchorWorks(false) - .fixedTime(18000L) - .natural(false) - .raids(false) - .heightBounds(0, DIMENSION_HEIGHT) - .build()); - } - - private static void generateDimensions(BootstrapContext ctx) { - final var biomes = ctx.lookup(Registries.BIOME); - final var dimTypes = ctx.lookup(Registries.DIMENSION_TYPE); - - final var cmBiome = biomes.getOrThrow(ResourceKey.create(Registries.BIOME, COMPACT_BIOME)); - - var flatSettings = new FlatLevelGeneratorSettings(Optional.empty(), cmBiome, Collections.emptyList()) - .withBiomeAndLayers( - List.of(new FlatLayerInfo(DIMENSION_HEIGHT, Dimension.BLOCK_MACHINE_VOID_AIR.get())), - Optional.empty(), - cmBiome - ); - - var stem = new LevelStem(dimTypes.getOrThrow(CompactDimension.DIM_TYPE_KEY), new FlatLevelSource(flatSettings)); - ctx.register(ResourceKey.create(Registries.LEVEL_STEM, CompactDimension.LEVEL_KEY.location()), stem); - } - - private static void addRoomTemplates(BootstrapContext ctx) { - roomTemplate(ctx, "tiny", new RoomTemplate(3, FastColor.ARGB32.color(255, 201, 91, 19))); - roomTemplate(ctx, "small", new RoomTemplate(5, FastColor.ARGB32.color(255, 212, 210, 210))); - roomTemplate(ctx, "normal", new RoomTemplate(7, FastColor.ARGB32.color(255, 251, 242, 54))); - roomTemplate(ctx, "large", new RoomTemplate(9, FastColor.ARGB32.color(255, 33, 27, 46))); - roomTemplate(ctx, "giant", new RoomTemplate(11, FastColor.ARGB32.color(255, 67, 214, 205))); - roomTemplate(ctx, "colossal", new RoomTemplate(13, FastColor.ARGB32.color(255, 66, 63, 66))); - } - - private static void roomTemplate(BootstrapContext ctx, String name, RoomTemplate template) { - ctx.register(ResourceKey.create(RoomTemplate.REGISTRY_KEY, CompactMachines.modRL(name)), template); - } -} +package dev.compactmods.machines.datagen; + +import dev.compactmods.machines.api.machine.MachineColor; +import dev.compactmods.machines.api.room.RoomDimensions; +import dev.compactmods.machines.api.room.template.RoomTemplate; +import dev.compactmods.machines.api.CompactMachines; +import dev.compactmods.machines.api.dimension.CompactDimension; +import dev.compactmods.machines.datagen.util.DimensionTypeBuilder; +import dev.compactmods.machines.dimension.Dimension; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.RegistrySetBuilder; +import net.minecraft.core.registries.Registries; +import net.minecraft.data.PackOutput; +import net.minecraft.data.worldgen.BiomeDefaultFeatures; +import net.minecraft.data.worldgen.BootstrapContext; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.CommonColors; +import net.minecraft.util.FastColor; +import net.minecraft.world.item.DyeColor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeGenerationSettings; +import net.minecraft.world.level.biome.BiomeSpecialEffects; +import net.minecraft.world.level.biome.MobSpawnSettings; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.dimension.LevelStem; +import net.minecraft.world.level.levelgen.FlatLevelSource; +import net.minecraft.world.level.levelgen.flat.FlatLayerInfo; +import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings; +import net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.CompletableFuture; + +public class DatapackRegisteredStuff extends DatapackBuiltinEntriesProvider { + private static final ResourceLocation COMPACT_BIOME = CompactMachines.modRL("machine"); + private static final int DIMENSION_HEIGHT = 48; + + private static final RegistrySetBuilder BUILDER = new RegistrySetBuilder() + .add(Registries.BIOME, DatapackRegisteredStuff::generateBiomes) + .add(Registries.DIMENSION_TYPE, DatapackRegisteredStuff::generateDimensionTypes) + .add(Registries.LEVEL_STEM, DatapackRegisteredStuff::generateDimensions) + .add(RoomTemplate.REGISTRY_KEY, DatapackRegisteredStuff::addRoomTemplates); + + DatapackRegisteredStuff(PackOutput packOutput, CompletableFuture registries) { + super(packOutput, registries, BUILDER, Set.of(CompactMachines.MOD_ID)); + } + + private static void generateBiomes(BootstrapContext ctx) { + var spawnBuilder = new MobSpawnSettings.Builder(); + BiomeDefaultFeatures.plainsSpawns(spawnBuilder); + var spawns = spawnBuilder.build(); + + final Biome compactBiome = new Biome.BiomeBuilder() + .downfall(0) + .generationSettings(BiomeGenerationSettings.EMPTY) + .mobSpawnSettings(spawns) + .hasPrecipitation(false) + .temperature(0.8f) + .temperatureAdjustment(Biome.TemperatureModifier.NONE) + .specialEffects(new BiomeSpecialEffects.Builder() + .fogColor(12638463) + .waterColor(4159204) + .waterFogColor(329011) + .skyColor(0xFF000000) + .build()) + .build(); + + ctx.register(ResourceKey.create(Registries.BIOME, COMPACT_BIOME), compactBiome); + } + + private static void generateDimensionTypes(BootstrapContext ctx) { + ctx.register(CompactDimension.DIM_TYPE_KEY, new DimensionTypeBuilder() + .bedWorks(false) + .respawnAnchorWorks(false) + .fixedTime(18000L) + .natural(false) + .raids(false) + .heightBounds(0, DIMENSION_HEIGHT) + .build()); + } + + private static void generateDimensions(BootstrapContext ctx) { + final var biomes = ctx.lookup(Registries.BIOME); + final var dimTypes = ctx.lookup(Registries.DIMENSION_TYPE); + + final var cmBiome = biomes.getOrThrow(ResourceKey.create(Registries.BIOME, COMPACT_BIOME)); + + var flatSettings = new FlatLevelGeneratorSettings(Optional.empty(), cmBiome, Collections.emptyList()) + .withBiomeAndLayers( + List.of(new FlatLayerInfo(DIMENSION_HEIGHT, Dimension.BLOCK_MACHINE_VOID_AIR.get())), + Optional.empty(), + cmBiome + ); + + var stem = new LevelStem(dimTypes.getOrThrow(CompactDimension.DIM_TYPE_KEY), new FlatLevelSource(flatSettings)); + ctx.register(ResourceKey.create(Registries.LEVEL_STEM, CompactDimension.LEVEL_KEY.location()), stem); + } + + private static void addRoomTemplates(BootstrapContext ctx) { + roomTemplate(ctx, "tiny", new RoomTemplate(3, FastColor.ARGB32.color(255, 201, 91, 19))); + roomTemplate(ctx, "small", new RoomTemplate(5, FastColor.ARGB32.color(255, 212, 210, 210))); + roomTemplate(ctx, "normal", new RoomTemplate(7, FastColor.ARGB32.color(255, 251, 242, 54))); + roomTemplate(ctx, "large", new RoomTemplate(9, FastColor.ARGB32.color(255, 33, 27, 46))); + roomTemplate(ctx, "giant", new RoomTemplate(11, FastColor.ARGB32.color(255, 67, 214, 205))); + roomTemplate(ctx, "colossal", new RoomTemplate(13, FastColor.ARGB32.color(255, 66, 63, 66))); + + roomTemplate(ctx, "soaryn", new RoomTemplate(45, DyeColor.PURPLE.getFireworkColor())); + roomTemplate(ctx, "farming", RoomTemplate.builder() + .withInternalSize(21, 21, 11) + .defaultMachineColor(MachineColor.fromARGB(CommonColors.GREEN)) + .withFloor(Blocks.GRASS_BLOCK.defaultBlockState()) + .build()); + } + + private static void roomTemplate(BootstrapContext ctx, String name, RoomTemplate template) { + ctx.register(ResourceKey.create(RoomTemplate.REGISTRY_KEY, CompactMachines.modRL(name)), template); + } +} diff --git a/neoforge-datagen/src/main/java/dev.compactmods.machines.datagen/RecipeGenerator.java b/neoforge-datagen/src/main/java/dev.compactmods.machines.datagen/RecipeGenerator.java index fdb40605..1147860a 100644 --- a/neoforge-datagen/src/main/java/dev.compactmods.machines.datagen/RecipeGenerator.java +++ b/neoforge-datagen/src/main/java/dev.compactmods.machines.datagen/RecipeGenerator.java @@ -1,113 +1,127 @@ -package dev.compactmods.machines.datagen; - -import dev.compactmods.machines.api.CompactMachines; -import dev.compactmods.machines.api.room.RoomTemplate; -import dev.compactmods.machines.machine.Machines; -import dev.compactmods.machines.room.Rooms; -import dev.compactmods.machines.shrinking.Shrinking; -import net.minecraft.core.HolderLookup; -import net.minecraft.data.PackOutput; -import net.minecraft.data.recipes.RecipeCategory; -import net.minecraft.data.recipes.RecipeOutput; -import net.minecraft.data.recipes.RecipeProvider; -import net.minecraft.data.recipes.ShapedRecipeBuilder; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.tags.TagKey; -import net.minecraft.util.FastColor; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.Items; -import net.neoforged.neoforge.common.Tags; - -import java.util.concurrent.CompletableFuture; - -public class RecipeGenerator extends RecipeProvider { - - public RecipeGenerator(PackOutput packOut, CompletableFuture holders) { - super(packOut, holders); - } - - @Override - protected void buildRecipes(RecipeOutput recipeOutput) { - ShapedRecipeBuilder.shaped(RecipeCategory.BUILDING_BLOCKS, Rooms.Items.BREAKABLE_WALL.get(), 8) - .pattern("DDD") - .pattern("D D") - .pattern("DDD") - .define('D', Items.POLISHED_DEEPSLATE) - .unlockedBy("picked_up_deepslate", RecipeProvider.has(Tags.Items.COBBLESTONES_DEEPSLATE)) - .save(recipeOutput); - - ShapedRecipeBuilder.shaped(RecipeCategory.TOOLS, Shrinking.PERSONAL_SHRINKING_DEVICE.get()) - .pattern("121") - .pattern("345") - .pattern("676") - .define('1', Tags.Items.NUGGETS_IRON) - .define('2', Tags.Items.GLASS_PANES) - .define('3', Shrinking.ENLARGING_MODULE) - .define('4', Items.ENDER_EYE) - .define('5', Shrinking.SHRINKING_MODULE) - .define('6', Tags.Items.INGOTS_IRON) - .define('7', Tags.Items.INGOTS_COPPER) - .unlockedBy("picked_up_ender_eye", RecipeProvider.has(Items.ENDER_EYE)) - .save(recipeOutput); - - ShapedRecipeBuilder.shaped(RecipeCategory.MISC, Shrinking.ENLARGING_MODULE) - .pattern("BPB") - .pattern("BEB") - .pattern("BLB") - .define('B', Items.STONE_BUTTON) - .define('P', Items.PISTON) - .define('E', Items.ENDER_EYE) - .define('L', Items.LIGHT_WEIGHTED_PRESSURE_PLATE) - .unlockedBy("picked_up_ender_eye", RecipeProvider.has(Items.ENDER_EYE)) - .save(recipeOutput); - - ShapedRecipeBuilder.shaped(RecipeCategory.MISC, Shrinking.SHRINKING_MODULE) - .pattern("BPB") - .pattern("BEB") - .pattern("BLB") - .define('B', Items.STONE_BUTTON) - .define('P', Items.STICKY_PISTON) - .define('E', Items.ENDER_EYE) - .define('L', Items.LIGHT_WEIGHTED_PRESSURE_PLATE) - .unlockedBy("picked_up_ender_eye", RecipeProvider.has(Items.ENDER_EYE)) - .save(recipeOutput); - - addMachineRecipes(recipeOutput); - } - - private void addMachineRecipes(RecipeOutput consumer) { - registerMachineRecipe(consumer, CompactMachines.modRL("tiny"), - new RoomTemplate(3, FastColor.ARGB32.color(255, 201, 91, 19)), Tags.Items.INGOTS_COPPER); - - registerMachineRecipe(consumer, CompactMachines.modRL("small"), - new RoomTemplate(5, FastColor.ARGB32.color(255, 212, 210, 210)), Tags.Items.INGOTS_IRON); - - registerMachineRecipe(consumer, CompactMachines.modRL("normal"), - new RoomTemplate(7, FastColor.ARGB32.color(255, 251, 242, 54)), Tags.Items.INGOTS_GOLD); - - registerMachineRecipe(consumer, CompactMachines.modRL("large"), - new RoomTemplate(9, FastColor.ARGB32.color(255, 33, 27, 46)), Tags.Items.GEMS_DIAMOND); - - registerMachineRecipe(consumer, CompactMachines.modRL("giant"), - new RoomTemplate(11, FastColor.ARGB32.color(255, 67, 214, 205)), Tags.Items.OBSIDIANS); - - registerMachineRecipe(consumer, CompactMachines.modRL("colossal"), - new RoomTemplate(13, FastColor.ARGB32.color(255, 66, 63, 66)), Tags.Items.INGOTS_NETHERITE); - } - - protected void registerMachineRecipe(RecipeOutput consumer, ResourceLocation temId, RoomTemplate template, TagKey catalyst) { - final var recipe = ShapedRecipeBuilder.shaped(RecipeCategory.MISC, Machines.Items.forNewRoom(temId, template)) - .pattern("WWW") - .pattern("EPS") - .pattern("WWW") - .define('W', Rooms.Items.BREAKABLE_WALL) - .define('E', Shrinking.ENLARGING_MODULE) - .define('S', Shrinking.SHRINKING_MODULE) - .define('P', catalyst); - - recipe.unlockedBy("has_recipe", RecipeProvider.has(Rooms.Items.BREAKABLE_WALL)); - - final var recipeId = CompactMachines.modRL("new_machine_" + temId.getPath()); - recipe.save(consumer, recipeId); - } -} +package dev.compactmods.machines.datagen; + +import dev.compactmods.machines.api.CompactMachines; +import dev.compactmods.machines.api.room.template.RoomTemplate; +import dev.compactmods.machines.machine.Machines; +import dev.compactmods.machines.room.Rooms; +import dev.compactmods.machines.shrinking.Shrinking; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderLookup; +import net.minecraft.data.PackOutput; +import net.minecraft.data.recipes.RecipeCategory; +import net.minecraft.data.recipes.RecipeOutput; +import net.minecraft.data.recipes.RecipeProvider; +import net.minecraft.data.recipes.ShapedRecipeBuilder; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.ItemLike; +import net.neoforged.neoforge.common.Tags; + +import java.util.concurrent.CompletableFuture; +import java.util.function.UnaryOperator; + +public class RecipeGenerator extends RecipeProvider { + + public RecipeGenerator(PackOutput packOut, CompletableFuture holders) { + super(packOut, holders); + } + + @Override + protected void buildRecipes(RecipeOutput recipeOutput, HolderLookup.Provider provider) { + ShapedRecipeBuilder.shaped(RecipeCategory.BUILDING_BLOCKS, Rooms.Items.BREAKABLE_WALL.get(), 8) + .pattern("DDD") + .pattern("D D") + .pattern("DDD") + .define('D', Items.POLISHED_DEEPSLATE) + .unlockedBy("picked_up_deepslate", RecipeProvider.has(Tags.Items.COBBLESTONES_DEEPSLATE)) + .save(recipeOutput); + + ShapedRecipeBuilder.shaped(RecipeCategory.TOOLS, Shrinking.PERSONAL_SHRINKING_DEVICE.get()) + .pattern("121") + .pattern("345") + .pattern("676") + .define('1', Tags.Items.NUGGETS_IRON) + .define('2', Tags.Items.GLASS_PANES) + .define('3', Shrinking.ENLARGING_MODULE) + .define('4', Items.ENDER_EYE) + .define('5', Shrinking.SHRINKING_MODULE) + .define('6', Tags.Items.INGOTS_IRON) + .define('7', Tags.Items.INGOTS_COPPER) + .unlockedBy("picked_up_ender_eye", RecipeProvider.has(Items.ENDER_EYE)) + .save(recipeOutput); + + ShapedRecipeBuilder.shaped(RecipeCategory.MISC, Shrinking.ENLARGING_MODULE) + .pattern("BPB") + .pattern("BEB") + .pattern("BLB") + .define('B', Items.STONE_BUTTON) + .define('P', Items.PISTON) + .define('E', Items.ENDER_EYE) + .define('L', Items.LIGHT_WEIGHTED_PRESSURE_PLATE) + .unlockedBy("picked_up_ender_eye", RecipeProvider.has(Items.ENDER_EYE)) + .save(recipeOutput); + + ShapedRecipeBuilder.shaped(RecipeCategory.MISC, Shrinking.SHRINKING_MODULE) + .pattern("BPB") + .pattern("BEB") + .pattern("BLB") + .define('B', Items.STONE_BUTTON) + .define('P', Items.STICKY_PISTON) + .define('E', Items.ENDER_EYE) + .define('L', Items.LIGHT_WEIGHTED_PRESSURE_PLATE) + .unlockedBy("picked_up_ender_eye", RecipeProvider.has(Items.ENDER_EYE)) + .save(recipeOutput); + + addMachineRecipes(recipeOutput, provider); + } + + private void addMachineRecipes(RecipeOutput consumer, HolderLookup.Provider provider) { + var allPossible = provider.lookupOrThrow(RoomTemplate.REGISTRY_KEY) + .listElements() + .toList(); + + addMachineRecipe(consumer, provider, CompactMachines.modRL("tiny"), Tags.Items.INGOTS_COPPER); + addMachineRecipe(consumer, provider, CompactMachines.modRL("small"), Tags.Items.INGOTS_IRON); + addMachineRecipe(consumer, provider, CompactMachines.modRL("normal"), Tags.Items.INGOTS_GOLD); + addMachineRecipe(consumer, provider, CompactMachines.modRL("large"), Tags.Items.GEMS_DIAMOND); + addMachineRecipe(consumer, provider, CompactMachines.modRL("giant"), Tags.Items.OBSIDIANS); + addMachineRecipe(consumer, provider, CompactMachines.modRL("colossal"), Tags.Items.INGOTS_NETHERITE); + + addMachineRecipe(consumer, provider, CompactMachines.modRL("soaryn"), Tags.Items.NETHER_STARS); + addMachineRecipe(consumer, provider, CompactMachines.modRL("farming"), Items.DIAMOND_HOE); + } + + private void addMachineRecipe(RecipeOutput consumer, HolderLookup.Provider provider, ResourceLocation id, TagKey catalyst) { + final var templateRef = provider.lookupOrThrow(RoomTemplate.REGISTRY_KEY) + .getOrThrow(ResourceKey.create(RoomTemplate.REGISTRY_KEY, id)); + + machineRecipeBuilder(consumer, templateRef, builder -> builder.define('P', catalyst)); + } + + private void addMachineRecipe(RecipeOutput consumer, HolderLookup.Provider provider, ResourceLocation id, ItemLike catalyst) { + final var templateRef = provider.lookupOrThrow(RoomTemplate.REGISTRY_KEY) + .getOrThrow(ResourceKey.create(RoomTemplate.REGISTRY_KEY, id)); + + machineRecipeBuilder(consumer, templateRef, builder -> builder.define('P', catalyst)); + } + + protected void machineRecipeBuilder(RecipeOutput consumer, Holder.Reference templateRef, UnaryOperator configure) { + final var builder = ShapedRecipeBuilder.shaped(RecipeCategory.MISC, Machines.Items.forNewRoom(templateRef)) + .pattern("WWW") + .pattern("EPS") + .pattern("WWW") + .define('W', Rooms.Items.BREAKABLE_WALL) + .define('E', Shrinking.ENLARGING_MODULE) + .define('S', Shrinking.SHRINKING_MODULE); + + configure.apply(builder); + + builder.unlockedBy("has_recipe", RecipeProvider.has(Rooms.Items.BREAKABLE_WALL)); + + final var recipeId = CompactMachines.modRL("new_machine_" + templateRef.key().location().getPath()); + builder.save(consumer, recipeId); + } +} diff --git a/neoforge-main/build.gradle.kts b/neoforge-main/build.gradle.kts index ee947a47..9c47b9b1 100644 --- a/neoforge-main/build.gradle.kts +++ b/neoforge-main/build.gradle.kts @@ -88,47 +88,29 @@ runs { programArguments.addAll("--width", "1920") programArguments.addAll("--height", "1080") } + + create("server") { + server() + workingDirectory.set(file("runs/server")) + + systemProperty("forge.enabledGameTestNamespaces", modId) + programArgument("nogui") + + environmentVariable("CM_TEST_RESOURCES", file("src/test/resources").path) + + sourceSets.add(project.sourceSets.test.get()) + } + + create("gameTestServer") { + gameTest() + workingDirectory.set(file("runs/gametest")) + + systemProperty("forge.enabledGameTestNamespaces", modId) + environmentVariable("CM_TEST_RESOURCES", file("src/test/resources").path) + + sourceSets.add(project.sourceSets.test.get()) + } } -//neoForge { -// version = neoforged.versions.neoforge -// -// this.mods.create(modId) { -// modSourceSets.add(sourceSets.main) -// modSourceSets.add(sourceSets.test) -// this.dependency(coreApi) -// } -// -// unitTest { -// enable() -// testedMod = mods.named(modId) -// } -// - -// create("server") { -// server() -// gameDirectory.set(file("runs/server")) -// -// systemProperty("forge.enabledGameTestNamespaces", modId) -// programArgument("nogui") -// -// environment.put("CM_TEST_RESOURCES", file("src/test/resources").path) -// -// sourceSet = project.sourceSets.test -// // sourceSets.add(project.sourceSets.test.get()) -// } -// -// create("gameTestServer") { -// type = "gameTestServer" -// gameDirectory.set(file("runs/gametest")) -// -// systemProperty("forge.enabledGameTestNamespaces", modId) -// environment.put("CM_TEST_RESOURCES", file("src/test/resources").path) -// -// sourceSet = project.sourceSets.test -// // sourceSets.add(project.sourceSets.test.get()) -// } -// } -//} repositories { mavenLocal() @@ -186,7 +168,6 @@ dependencies { testRuntimeOnly("org.junit.platform:junit-platform-launcher") - // Mods // compileOnly(mods.bundles.jei) // compileOnly(mods.jade) diff --git a/neoforge-main/src/main/java/dev/compactmods/machines/CMRegistries.java b/neoforge-main/src/main/java/dev/compactmods/machines/CMRegistries.java index d8a98639..af4ac371 100644 --- a/neoforge-main/src/main/java/dev/compactmods/machines/CMRegistries.java +++ b/neoforge-main/src/main/java/dev/compactmods/machines/CMRegistries.java @@ -1,72 +1,73 @@ -package dev.compactmods.machines; - -import dev.compactmods.machines.api.room.RoomTemplate; -import dev.compactmods.machines.api.CompactMachines; -import dev.compactmods.machines.shrinking.Shrinking; -import net.minecraft.commands.synchronization.ArgumentTypeInfo; -import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.entity.ai.village.poi.PoiType; -import net.minecraft.world.entity.npc.VillagerProfession; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.item.CreativeModeTab; -import net.minecraft.world.item.CreativeModeTabs; -import net.minecraft.world.item.Item; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType; -import net.neoforged.bus.api.IEventBus; -import net.neoforged.neoforge.attachment.AttachmentType; -import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent; -import net.neoforged.neoforge.registries.DataPackRegistryEvent; -import net.neoforged.neoforge.registries.DeferredRegister; -import net.neoforged.neoforge.registries.NeoForgeRegistries; - -import java.util.stream.Stream; - -public interface CMRegistries { - - // Machines, Walls, Shrinking - DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks(CompactMachines.MOD_ID); - DeferredRegister.Items ITEMS = DeferredRegister.createItems(CompactMachines.MOD_ID); - - DeferredRegister TABS = DeferredRegister.create(BuiltInRegistries.CREATIVE_MODE_TAB, CompactMachines.MOD_ID); - - DeferredRegister> BLOCK_ENTITIES = DeferredRegister.create(BuiltInRegistries.BLOCK_ENTITY_TYPE, CompactMachines.MOD_ID); - - // UIRegistration - DeferredRegister> CONTAINERS = DeferredRegister.create(BuiltInRegistries.MENU, CompactMachines.MOD_ID); - - // Commands - DeferredRegister> COMMAND_ARGUMENT_TYPES = DeferredRegister.create(BuiltInRegistries.COMMAND_ARGUMENT_TYPE, CompactMachines.MOD_ID); - - // LootFunctions - DeferredRegister> LOOT_FUNCTIONS = DeferredRegister.create(BuiltInRegistries.LOOT_FUNCTION_TYPE, CompactMachines.MOD_ID); - - // Villagers - DeferredRegister VILLAGERS = DeferredRegister.create(BuiltInRegistries.VILLAGER_PROFESSION, CompactMachines.MOD_ID); - - DeferredRegister POINTS_OF_INTEREST = DeferredRegister.create(BuiltInRegistries.POINT_OF_INTEREST_TYPE, CompactMachines.MOD_ID); - - DeferredRegister> ATTACHMENT_TYPES = DeferredRegister.create(NeoForgeRegistries.ATTACHMENT_TYPES, CompactMachines.MOD_ID); - - DeferredRegister.DataComponents DATA_COMPONENTS = DeferredRegister.createDataComponents(CompactMachines.MOD_ID); - - static Item basicItem() { - return new Item(new Item.Properties()); - } - - static void setup(IEventBus modBus) { - Stream.of(BLOCKS, ITEMS, BLOCK_ENTITIES, CONTAINERS, COMMAND_ARGUMENT_TYPES, LOOT_FUNCTIONS, - VILLAGERS, POINTS_OF_INTEREST, TABS, ATTACHMENT_TYPES, DATA_COMPONENTS - ).forEach(r -> r.register(modBus)); - - modBus.addListener((DataPackRegistryEvent.NewRegistry newRegistries) -> { - newRegistries.dataPackRegistry(RoomTemplate.REGISTRY_KEY, RoomTemplate.CODEC, RoomTemplate.CODEC); - }); - - modBus.addListener((BuildCreativeModeTabContentsEvent addToTabs) -> { - if (addToTabs.getTabKey() == CreativeModeTabs.TOOLS_AND_UTILITIES) { - addToTabs.accept(Shrinking.PERSONAL_SHRINKING_DEVICE.get()); - } - }); - } -} +package dev.compactmods.machines; + +import dev.compactmods.machines.api.room.template.RoomTemplate; +import dev.compactmods.machines.api.CompactMachines; +import dev.compactmods.machines.api.room.upgrade.RoomUpgradeDefinition; +import dev.compactmods.machines.shrinking.Shrinking; +import net.minecraft.commands.synchronization.ArgumentTypeInfo; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.entity.ai.village.poi.PoiType; +import net.minecraft.world.entity.npc.VillagerProfession; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.CreativeModeTabs; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.attachment.AttachmentType; +import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent; +import net.neoforged.neoforge.registries.DataPackRegistryEvent; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.NeoForgeRegistries; + +import java.util.stream.Stream; + +public interface CMRegistries { + + // Machines, Walls, Shrinking + DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks(CompactMachines.MOD_ID); + DeferredRegister.Items ITEMS = DeferredRegister.createItems(CompactMachines.MOD_ID); + + DeferredRegister TABS = DeferredRegister.create(BuiltInRegistries.CREATIVE_MODE_TAB, CompactMachines.MOD_ID); + + DeferredRegister> BLOCK_ENTITIES = DeferredRegister.create(BuiltInRegistries.BLOCK_ENTITY_TYPE, CompactMachines.MOD_ID); + + // UIRegistration + DeferredRegister> CONTAINERS = DeferredRegister.create(BuiltInRegistries.MENU, CompactMachines.MOD_ID); + + // Commands + DeferredRegister> COMMAND_ARGUMENT_TYPES = DeferredRegister.create(BuiltInRegistries.COMMAND_ARGUMENT_TYPE, CompactMachines.MOD_ID); + + // LootFunctions + DeferredRegister> LOOT_FUNCTIONS = DeferredRegister.create(BuiltInRegistries.LOOT_FUNCTION_TYPE, CompactMachines.MOD_ID); + + // Villagers + DeferredRegister VILLAGERS = DeferredRegister.create(BuiltInRegistries.VILLAGER_PROFESSION, CompactMachines.MOD_ID); + + DeferredRegister POINTS_OF_INTEREST = DeferredRegister.create(BuiltInRegistries.POINT_OF_INTEREST_TYPE, CompactMachines.MOD_ID); + + DeferredRegister> ATTACHMENT_TYPES = DeferredRegister.create(NeoForgeRegistries.ATTACHMENT_TYPES, CompactMachines.MOD_ID); + + DeferredRegister.DataComponents DATA_COMPONENTS = DeferredRegister.createDataComponents(CompactMachines.MOD_ID); + + static Item basicItem() { + return new Item(new Item.Properties()); + } + + static void setup(IEventBus modBus) { + Stream.of(BLOCKS, ITEMS, BLOCK_ENTITIES, CONTAINERS, COMMAND_ARGUMENT_TYPES, LOOT_FUNCTIONS, + VILLAGERS, POINTS_OF_INTEREST, TABS, ATTACHMENT_TYPES, DATA_COMPONENTS + ).forEach(r -> r.register(modBus)); + + modBus.addListener((DataPackRegistryEvent.NewRegistry newRegistries) -> { + newRegistries.dataPackRegistry(RoomTemplate.REGISTRY_KEY, RoomTemplate.CODEC, RoomTemplate.CODEC); + }); + + modBus.addListener((BuildCreativeModeTabContentsEvent addToTabs) -> { + if (addToTabs.getTabKey() == CreativeModeTabs.TOOLS_AND_UTILITIES) { + addToTabs.accept(Shrinking.PERSONAL_SHRINKING_DEVICE.get()); + } + }); + } +} diff --git a/neoforge-main/src/main/java/dev/compactmods/machines/client/creative/CreativeTabs.java b/neoforge-main/src/main/java/dev/compactmods/machines/client/creative/CreativeTabs.java index 43b0b589..e0e4713c 100644 --- a/neoforge-main/src/main/java/dev/compactmods/machines/client/creative/CreativeTabs.java +++ b/neoforge-main/src/main/java/dev/compactmods/machines/client/creative/CreativeTabs.java @@ -1,40 +1,40 @@ -package dev.compactmods.machines.client.creative; - -import dev.compactmods.machines.api.room.RoomTemplate; -import dev.compactmods.machines.api.CompactMachines; -import dev.compactmods.machines.machine.Machines; -import dev.compactmods.machines.room.Rooms; -import dev.compactmods.machines.shrinking.Shrinking; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.CreativeModeTab; - -import static dev.compactmods.machines.CMRegistries.TABS; - -public interface CreativeTabs { - - ResourceLocation MAIN_RL = CompactMachines.modRL("main"); - - static void prepare() { - TABS.register(MAIN_RL.getPath(), () -> CreativeModeTab.builder() - .icon(Machines.Items::unbound) - .title(Component.translatableWithFallback("itemGroup.compactmachines.main", "Compact Machines")) - .displayItems(CreativeTabs::fillItems) - .build()); - } - - static void fillItems(CreativeModeTab.ItemDisplayParameters params, CreativeModeTab.Output output) { - output.accept(Shrinking.PERSONAL_SHRINKING_DEVICE.get(), CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS); - output.accept(Rooms.Items.BREAKABLE_WALL.get(), CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS); - output.accept(Shrinking.SHRINKING_MODULE.get(), CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS); - output.accept(Shrinking.ENLARGING_MODULE.get(), CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS); - // output.accept(Shrinking.RESIZING_MODULE.get(), CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS); - - final var lookup = params.holders().lookupOrThrow(RoomTemplate.REGISTRY_KEY); - final var machines = lookup.listElements() - .map(k -> Machines.Items.forNewRoom(k.key().location(), k.value())) - .toList(); - - output.acceptAll(machines, CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS); - } -} +package dev.compactmods.machines.client.creative; + +import dev.compactmods.machines.api.room.template.RoomTemplate; +import dev.compactmods.machines.api.CompactMachines; +import dev.compactmods.machines.machine.Machines; +import dev.compactmods.machines.room.Rooms; +import dev.compactmods.machines.shrinking.Shrinking; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.CreativeModeTab; + +import static dev.compactmods.machines.CMRegistries.TABS; + +public interface CreativeTabs { + + ResourceLocation MAIN_RL = CompactMachines.modRL("main"); + + static void prepare() { + TABS.register(MAIN_RL.getPath(), () -> CreativeModeTab.builder() + .icon(Machines.Items::unbound) + .title(Component.translatableWithFallback("itemGroup.compactmachines.main", "Compact Machines")) + .displayItems(CreativeTabs::fillItems) + .build()); + } + + static void fillItems(CreativeModeTab.ItemDisplayParameters params, CreativeModeTab.Output output) { + output.accept(Shrinking.PERSONAL_SHRINKING_DEVICE.get(), CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS); + output.accept(Rooms.Items.BREAKABLE_WALL.get(), CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS); + output.accept(Shrinking.SHRINKING_MODULE.get(), CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS); + output.accept(Shrinking.ENLARGING_MODULE.get(), CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS); + // output.accept(Shrinking.RESIZING_MODULE.get(), CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS); + + final var lookup = params.holders().lookupOrThrow(RoomTemplate.REGISTRY_KEY); + final var machines = lookup.listElements() + .map(Machines.Items::forNewRoom) + .toList(); + + output.acceptAll(machines, CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS); + } +} diff --git a/neoforge-main/src/main/java/dev/compactmods/machines/command/argument/Suggestors.java b/neoforge-main/src/main/java/dev/compactmods/machines/command/argument/Suggestors.java index c824afcb..7ba30646 100644 --- a/neoforge-main/src/main/java/dev/compactmods/machines/command/argument/Suggestors.java +++ b/neoforge-main/src/main/java/dev/compactmods/machines/command/argument/Suggestors.java @@ -1,43 +1,43 @@ -package dev.compactmods.machines.command.argument; - -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.suggestion.SuggestionProvider; -import dev.compactmods.machines.api.CompactMachines; -import dev.compactmods.machines.api.room.RoomTemplate; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.SharedSuggestionProvider; -import net.minecraft.core.Registry; -import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; - -import java.util.Set; - -public class Suggestors { - public static final SuggestionProvider ROOM_TEMPLATES = (ctx, builder) -> - SharedSuggestionProvider.suggestResource(getRegistryValues(ctx, RoomTemplate.REGISTRY_KEY), builder); - -// public static final SuggestionProvider OWNED_ROOM_CODES = (ctx, builder) -> { -// final var owner = ctx.getSource().getPlayerOrException(); -// -// final var codes = CompactMachines.roomApi().owners() -// .findByOwner(owner.getUUID()) -// .toList(); -// -// return SharedSuggestionProvider.suggest(codes, builder); -// }; - - public static final SuggestionProvider ROOM_CODES = (ctx, builder) -> { - final var codes = CompactMachines.roomApi() - .registrar() - .allRoomCodes() - .toList(); - - return SharedSuggestionProvider.suggest(codes, builder); - }; - - private static Set getRegistryValues(CommandContext ctx, ResourceKey> keyType) { - return ctx.getSource().registryAccess() - .registryOrThrow(keyType) - .keySet(); - } -} +package dev.compactmods.machines.command.argument; + +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.SuggestionProvider; +import dev.compactmods.machines.api.CompactMachines; +import dev.compactmods.machines.api.room.template.RoomTemplate; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.SharedSuggestionProvider; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; + +import java.util.Set; + +public class Suggestors { + public static final SuggestionProvider ROOM_TEMPLATES = (ctx, builder) -> + SharedSuggestionProvider.suggestResource(getRegistryValues(ctx, RoomTemplate.REGISTRY_KEY), builder); + +// public static final SuggestionProvider OWNED_ROOM_CODES = (ctx, builder) -> { +// final var owner = ctx.getSource().getPlayerOrException(); +// +// final var codes = CompactMachines.roomApi().owners() +// .findByOwner(owner.getUUID()) +// .toList(); +// +// return SharedSuggestionProvider.suggest(codes, builder); +// }; + + public static final SuggestionProvider ROOM_CODES = (ctx, builder) -> { + final var codes = CompactMachines.roomApi() + .registrar() + .allRoomCodes() + .toList(); + + return SharedSuggestionProvider.suggest(codes, builder); + }; + + private static Set getRegistryValues(CommandContext ctx, ResourceKey> keyType) { + return ctx.getSource().registryAccess() + .registryOrThrow(keyType) + .keySet(); + } +} diff --git a/neoforge-main/src/main/java/dev/compactmods/machines/command/subcommand/CMGiveMachineSubcommand.java b/neoforge-main/src/main/java/dev/compactmods/machines/command/subcommand/CMGiveMachineSubcommand.java index ebdbecf6..6aa701a0 100644 --- a/neoforge-main/src/main/java/dev/compactmods/machines/command/subcommand/CMGiveMachineSubcommand.java +++ b/neoforge-main/src/main/java/dev/compactmods/machines/command/subcommand/CMGiveMachineSubcommand.java @@ -1,141 +1,139 @@ -package dev.compactmods.machines.command.subcommand; - -import com.mojang.brigadier.arguments.StringArgumentType; -import com.mojang.brigadier.builder.LiteralArgumentBuilder; -import com.mojang.brigadier.context.CommandContext; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import dev.compactmods.machines.api.CompactMachines; -import dev.compactmods.machines.api.room.RoomTemplate; -import dev.compactmods.machines.LoggingUtil; -import dev.compactmods.machines.api.command.CommandTranslations; -import dev.compactmods.machines.api.room.RoomTranslations; -import dev.compactmods.machines.command.argument.Suggestors; -import dev.compactmods.machines.config.ServerConfig; -import dev.compactmods.machines.machine.Machines; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.Commands; -import net.minecraft.commands.arguments.EntityArgument; -import net.minecraft.commands.arguments.ResourceLocationArgument; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.item.ItemStack; -import org.apache.logging.log4j.Logger; - -public class CMGiveMachineSubcommand { - - private static final Logger LOGGER = LoggingUtil.modLog(); - - public static LiteralArgumentBuilder make() { - final var subRoot = Commands.literal("give") - .requires(cs -> cs.hasPermission(ServerConfig.giveMachineLevel())); - - - // /cm give new [template] - subRoot.then(Commands.literal("new") - .then(Commands.argument("template", ResourceLocationArgument.id()) - .suggests(Suggestors.ROOM_TEMPLATES) - .executes(CMGiveMachineSubcommand::giveNewMachineExecutor))); - - // /cm give existing [room-code] - subRoot.then(Commands.literal("existing") - .then(Commands.argument("room", StringArgumentType.string()) - .suggests(Suggestors.ROOM_CODES) - .executes(CMGiveMachineSubcommand::giveExistingRoomExecutor))); - - // /cm give [player] - var giveSpecificPlayer = Commands.argument("player", EntityArgument.player()); - - // /cm give [player] new [template] - giveSpecificPlayer.then(Commands.literal("new") - .then(Commands.argument("template", ResourceLocationArgument.id()) - .suggests(Suggestors.ROOM_TEMPLATES) - .executes(CMGiveMachineSubcommand::giveNewMachineSpecificPlayer))); - - // /cm give [player] existing [room-code] - giveSpecificPlayer.then(Commands.literal("existing") - .then(Commands.argument("room", StringArgumentType.string()) - .suggests(Suggestors.ROOM_CODES) - .executes(CMGiveMachineSubcommand::giveExistingRoomSpecificPlayer))); - - subRoot.then(giveSpecificPlayer); - - - - - return subRoot; - } - - - private static int giveNewMachineExecutor(CommandContext ctx) throws CommandSyntaxException { - final var src = ctx.getSource(); - final var player = src.getPlayerOrException(); - final var templateId = ResourceLocationArgument.getId(ctx, "template"); - - createAndGiveNewMachine(src, templateId, player); - - return 0; - } - - private static int giveNewMachineSpecificPlayer(CommandContext ctx) throws CommandSyntaxException { - final var src = ctx.getSource(); - final var player = EntityArgument.getPlayer(ctx, "player"); - final var templateId = ResourceLocationArgument.getId(ctx, "template"); - - createAndGiveNewMachine(src, templateId, player); - - return 0; - } - - private static int giveExistingRoomExecutor(CommandContext ctx) throws CommandSyntaxException { - final var src = ctx.getSource(); - final var player = src.getPlayerOrException(); - final var roomCode = StringArgumentType.getString(ctx, "room"); - - createAndGiveExistingRoom(roomCode, player, src); - - return 0; - } - - private static int giveExistingRoomSpecificPlayer(CommandContext ctx) throws CommandSyntaxException { - final var src = ctx.getSource(); - final var player = EntityArgument.getPlayer(ctx, "player"); - final var roomCode = StringArgumentType.getString(ctx, "room"); - - createAndGiveExistingRoom(roomCode, player, src); - - return 0; - } - - private static void createAndGiveNewMachine(CommandSourceStack src, ResourceLocation templateId, ServerPlayer player) { - - final var template = src.getServer().registryAccess() - .registryOrThrow(RoomTemplate.REGISTRY_KEY) - .get(templateId); - - if(template != null) { - final var item = Machines.Items.forNewRoom(templateId, template); - if (!player.addItem(item)) { - src.sendFailure(CommandTranslations.CANNOT_GIVE_MACHINE.get()); - } else { - src.sendSuccess(() -> CommandTranslations.MACHINE_GIVEN.apply(player), true); - } - } else { - src.sendFailure(CommandTranslations.CANNOT_GIVE_MACHINE.get()); - } - } - - private static void createAndGiveExistingRoom(String roomCode, ServerPlayer player, CommandSourceStack src) { - CompactMachines.roomApi().registrar().get(roomCode).ifPresentOrElse(room -> { - ItemStack newItem = Machines.Items.boundToRoom(room.code(), room.defaultMachineColor()); - if (!player.addItem(newItem)) { - src.sendFailure(CommandTranslations.CANNOT_GIVE_MACHINE.get()); - } else { - src.sendSuccess(() -> CommandTranslations.MACHINE_GIVEN.apply(player), true); - } - }, () -> { - LOGGER.error("Error giving player a new machine block: room not found."); - src.sendFailure(RoomTranslations.UNKNOWN_ROOM_BY_CODE.apply(roomCode)); - }); - } -} - +package dev.compactmods.machines.command.subcommand; + +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import dev.compactmods.machines.api.CompactMachines; +import dev.compactmods.machines.api.room.template.RoomTemplate; +import dev.compactmods.machines.LoggingUtil; +import dev.compactmods.machines.api.command.CommandTranslations; +import dev.compactmods.machines.api.room.RoomTranslations; +import dev.compactmods.machines.api.room.template.RoomTemplateHelper; +import dev.compactmods.machines.command.argument.Suggestors; +import dev.compactmods.machines.config.ServerConfig; +import dev.compactmods.machines.machine.Machines; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.arguments.EntityArgument; +import net.minecraft.commands.arguments.ResourceLocationArgument; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.ItemStack; +import org.apache.logging.log4j.Logger; + +public class CMGiveMachineSubcommand { + + private static final Logger LOGGER = LoggingUtil.modLog(); + + public static LiteralArgumentBuilder make() { + final var subRoot = Commands.literal("give") + .requires(cs -> cs.hasPermission(ServerConfig.giveMachineLevel())); + + + // /cm give new [template] + subRoot.then(Commands.literal("new") + .then(Commands.argument("template", ResourceLocationArgument.id()) + .suggests(Suggestors.ROOM_TEMPLATES) + .executes(CMGiveMachineSubcommand::giveNewMachineExecutor))); + + // /cm give existing [room-code] + subRoot.then(Commands.literal("existing") + .then(Commands.argument("room", StringArgumentType.string()) + .suggests(Suggestors.ROOM_CODES) + .executes(CMGiveMachineSubcommand::giveExistingRoomExecutor))); + + // /cm give [player] + var giveSpecificPlayer = Commands.argument("player", EntityArgument.player()); + + // /cm give [player] new [template] + giveSpecificPlayer.then(Commands.literal("new") + .then(Commands.argument("template", ResourceLocationArgument.id()) + .suggests(Suggestors.ROOM_TEMPLATES) + .executes(CMGiveMachineSubcommand::giveNewMachineSpecificPlayer))); + + // /cm give [player] existing [room-code] + giveSpecificPlayer.then(Commands.literal("existing") + .then(Commands.argument("room", StringArgumentType.string()) + .suggests(Suggestors.ROOM_CODES) + .executes(CMGiveMachineSubcommand::giveExistingRoomSpecificPlayer))); + + subRoot.then(giveSpecificPlayer); + + + + + return subRoot; + } + + + private static int giveNewMachineExecutor(CommandContext ctx) throws CommandSyntaxException { + final var src = ctx.getSource(); + final var player = src.getPlayerOrException(); + final var templateId = ResourceLocationArgument.getId(ctx, "template"); + + createAndGiveNewMachine(src, templateId, player); + + return 0; + } + + private static int giveNewMachineSpecificPlayer(CommandContext ctx) throws CommandSyntaxException { + final var src = ctx.getSource(); + final var player = EntityArgument.getPlayer(ctx, "player"); + final var templateId = ResourceLocationArgument.getId(ctx, "template"); + + createAndGiveNewMachine(src, templateId, player); + + return 0; + } + + private static int giveExistingRoomExecutor(CommandContext ctx) throws CommandSyntaxException { + final var src = ctx.getSource(); + final var player = src.getPlayerOrException(); + final var roomCode = StringArgumentType.getString(ctx, "room"); + + createAndGiveExistingRoom(roomCode, player, src); + + return 0; + } + + private static int giveExistingRoomSpecificPlayer(CommandContext ctx) throws CommandSyntaxException { + final var src = ctx.getSource(); + final var player = EntityArgument.getPlayer(ctx, "player"); + final var roomCode = StringArgumentType.getString(ctx, "room"); + + createAndGiveExistingRoom(roomCode, player, src); + + return 0; + } + + private static void createAndGiveNewMachine(CommandSourceStack src, ResourceLocation templateId, ServerPlayer player) { + + final var template = RoomTemplateHelper.getTemplateHolder(src.getServer().registryAccess(), templateId); + if(template.isBound()) { + final var item = Machines.Items.forNewRoom(template); + if (!player.addItem(item)) { + src.sendFailure(CommandTranslations.CANNOT_GIVE_MACHINE.get()); + } else { + src.sendSuccess(() -> CommandTranslations.MACHINE_GIVEN.apply(player), true); + } + } else { + src.sendFailure(CommandTranslations.CANNOT_GIVE_MACHINE.get()); + } + } + + private static void createAndGiveExistingRoom(String roomCode, ServerPlayer player, CommandSourceStack src) { + CompactMachines.roomApi().registrar().get(roomCode).ifPresentOrElse(room -> { + ItemStack newItem = Machines.Items.boundToRoom(room.code(), room.defaultMachineColor()); + if (!player.addItem(newItem)) { + src.sendFailure(CommandTranslations.CANNOT_GIVE_MACHINE.get()); + } else { + src.sendSuccess(() -> CommandTranslations.MACHINE_GIVEN.apply(player), true); + } + }, () -> { + LOGGER.error("Error giving player a new machine block: room not found."); + src.sendFailure(RoomTranslations.UNKNOWN_ROOM_BY_CODE.apply(roomCode)); + }); + } +} + diff --git a/neoforge-main/src/main/java/dev/compactmods/machines/data/DataFileUtil.java b/neoforge-main/src/main/java/dev/compactmods/machines/data/DataFileUtil.java index 5afa5bf0..7da507c7 100644 --- a/neoforge-main/src/main/java/dev/compactmods/machines/data/DataFileUtil.java +++ b/neoforge-main/src/main/java/dev/compactmods/machines/data/DataFileUtil.java @@ -1,37 +1,41 @@ -package dev.compactmods.machines.data; - -import com.mojang.serialization.Codec; -import dev.compactmods.machines.room.RoomRegistrar; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtAccounter; -import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.NbtOps; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; - -public class DataFileUtil { - - public static void ensureDirExists(Path dir) { - if(!Files.exists(dir)) { - try { - Files.createDirectories(dir); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - } - - public static T loadFileWithCodec(File file, Codec codec) { - try (var is = new FileInputStream(file)) { - final var tag = NbtIo.readCompressed(is, NbtAccounter.unlimitedHeap()); - return codec.parse(NbtOps.INSTANCE, tag.contains("data") ? tag.getCompound("data") : new CompoundTag()) - .getOrThrow(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } -} +package dev.compactmods.machines.data; + +import com.mojang.serialization.Codec; +import dev.compactmods.machines.room.RoomRegistrar; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtAccounter; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtOps; +import net.neoforged.neoforge.common.IOUtilities; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class DataFileUtil { + + public static void ensureDirExists(Path dir) { + if (!Files.exists(dir)) { + try { + Files.createDirectories(dir); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + public static T loadFileWithCodec(File file, Codec codec) { + try { + IOUtilities.cleanupTempFiles(Path.of(file.getParent()), file.getName()); + try (var is = new FileInputStream(file)) { + final var tag = NbtIo.readCompressed(is, NbtAccounter.unlimitedHeap()); + return codec.parse(NbtOps.INSTANCE, tag.contains("data") ? tag.getCompound("data") : new CompoundTag()) + .getOrThrow(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/neoforge-main/src/main/java/dev/compactmods/machines/data/manager/CMKeyedDataFileManager.java b/neoforge-main/src/main/java/dev/compactmods/machines/data/manager/CMKeyedDataFileManager.java index f9c904da..d58aa476 100644 --- a/neoforge-main/src/main/java/dev/compactmods/machines/data/manager/CMKeyedDataFileManager.java +++ b/neoforge-main/src/main/java/dev/compactmods/machines/data/manager/CMKeyedDataFileManager.java @@ -1,68 +1,85 @@ -package dev.compactmods.machines.data.manager; - -import dev.compactmods.machines.LoggingUtil; -import dev.compactmods.machines.data.CMDataFile; -import dev.compactmods.machines.data.CodecHolder; -import dev.compactmods.machines.data.DataFileUtil; -import dev.compactmods.machines.room.RoomRegistrar; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.NbtOps; -import net.minecraft.server.MinecraftServer; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Optional; -import java.util.function.BiFunction; - -public class CMKeyedDataFileManager> implements IKeyedDataFileManager { - - protected final MinecraftServer server; - private final BiFunction creator; - private final HashMap cache; - - public CMKeyedDataFileManager(MinecraftServer server, BiFunction creator) { - this.server = server; - this.creator = creator; - this.cache = new HashMap<>(); - } - - @Override - public T data(Key key) { - return cache.computeIfAbsent(key, k -> { - var inst = creator.apply(server, k); - var dir = inst.getDataLocation(server); - DataFileUtil.ensureDirExists(dir); - final var file = dir.resolve(k.toString() + ".dat").toFile(); - return !file.exists() ? inst : DataFileUtil.loadFileWithCodec(file, inst.codec()); - }); - } - - @Override - public Optional optionalData(Key key) { - return hasData(key) ? Optional.ofNullable(data(key)) : Optional.empty(); - } - - public void save() { - cache.forEach((key, data) -> { - var fullData = new CompoundTag(); - fullData.putString("version", data.getDataVersion()); - - var fileData = data.codec() - .encodeStart(NbtOps.INSTANCE, data) - .getOrThrow(); - - fullData.put("data", fileData); - - try { - NbtIo.writeCompressed(fullData, data.getDataLocation(server).resolve(key.toString() + ".dat")); - } catch (IOException e) { - LoggingUtil.modLog().error("Failed to write data: " + e.getMessage(), e); - } - }); - } - - public boolean hasData(Key key) { - return cache.containsKey(key); - } -} +package dev.compactmods.machines.data.manager; + +import dev.compactmods.machines.LoggingUtil; +import dev.compactmods.machines.data.CMDataFile; +import dev.compactmods.machines.data.CodecHolder; +import dev.compactmods.machines.data.DataFileUtil; +import dev.compactmods.machines.room.RoomRegistrar; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtOps; +import net.minecraft.server.MinecraftServer; +import net.neoforged.neoforge.common.IOUtilities; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Optional; +import java.util.function.BiFunction; + +/** + * A codec-backed file that stores several instances of typed data, indexed by a key. + * + * @param The key used for instance lookups. + * @param + */ +public class CMKeyedDataFileManager> implements IKeyedDataFileManager { + + protected final MinecraftServer server; + private final BiFunction creator; + private final HashMap cache; + + public CMKeyedDataFileManager(MinecraftServer server, BiFunction creator) { + this.server = server; + this.creator = creator; + this.cache = new HashMap<>(); + } + + /** + * Used to get the filename for a given item, if {@code key.toString()} is not sufficient. + * + * @param key + * @return + */ + public String getFileKey(Key key) { + return key.toString(); + } + + @Override + public T data(Key key) { + return cache.computeIfAbsent(key, k -> { + var inst = creator.apply(server, k); + var dir = inst.getDataLocation(server); + DataFileUtil.ensureDirExists(dir); + final var file = dir.resolve(k.toString() + ".dat").toFile(); + return !file.exists() ? inst : DataFileUtil.loadFileWithCodec(file, inst.codec()); + }); + } + + @Override + public Optional optionalData(Key key) { + return hasData(key) ? Optional.ofNullable(data(key)) : Optional.empty(); + } + + public void save() { + cache.forEach((key, data) -> { + var fullData = new CompoundTag(); + fullData.putString("version", data.getDataVersion()); + + var fileData = data.codec() + .encodeStart(NbtOps.INSTANCE, data) + .getOrThrow(); + + fullData.put("data", fileData); + + try { + IOUtilities.writeNbtCompressed(fullData, data.getDataLocation(server).resolve(getFileKey(key) + ".dat")); + } catch (IOException e) { + LoggingUtil.modLog().error("Failed to write data: " + e.getMessage(), e); + } + }); + } + + public boolean hasData(Key key) { + return cache.containsKey(key); + } +} diff --git a/neoforge-main/src/main/java/dev/compactmods/machines/data/manager/CMSingletonDataFileManager.java b/neoforge-main/src/main/java/dev/compactmods/machines/data/manager/CMSingletonDataFileManager.java index fc77e0a9..946c6547 100644 --- a/neoforge-main/src/main/java/dev/compactmods/machines/data/manager/CMSingletonDataFileManager.java +++ b/neoforge-main/src/main/java/dev/compactmods/machines/data/manager/CMSingletonDataFileManager.java @@ -1,57 +1,60 @@ -package dev.compactmods.machines.data.manager; - -import dev.compactmods.machines.LoggingUtil; -import dev.compactmods.machines.data.CMDataFile; -import dev.compactmods.machines.data.CodecHolder; -import dev.compactmods.machines.data.DataFileUtil; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.NbtIo; -import net.minecraft.nbt.NbtOps; -import net.minecraft.server.MinecraftServer; - -import java.io.IOException; - -public class CMSingletonDataFileManager> implements IDataFileManager { - - protected final MinecraftServer server; - private final String dataKey; - private final T instance; - - public CMSingletonDataFileManager(MinecraftServer server, String dataKey, T instance) { - this.server = server; - this.dataKey = dataKey; - this.instance = instance; - } - - public T data() { - return this.instance; - } - - private void ensureFileReady() { - var dir = instance.getDataLocation(server); - DataFileUtil.ensureDirExists(dir); - } - - public void save() { - if (instance != null) { - ensureFileReady(); - - var fullData = new CompoundTag(); - fullData.putString("version", instance.getDataVersion()); - - var fileData = instance.codec() - .encodeStart(NbtOps.INSTANCE, instance) - .getOrThrow(); - - fullData.put("data", fileData); - - try { - NbtIo.writeCompressed(fullData, instance.getDataLocation(server).resolve(dataKey + ".dat")); - } catch (IOException e) { - LoggingUtil.modLog().error("Failed to write data: " + e.getMessage(), e); - } - } - } - - -} +package dev.compactmods.machines.data.manager; + +import dev.compactmods.machines.LoggingUtil; +import dev.compactmods.machines.data.CMDataFile; +import dev.compactmods.machines.data.CodecHolder; +import dev.compactmods.machines.data.DataFileUtil; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtIo; +import net.minecraft.nbt.NbtOps; +import net.minecraft.server.MinecraftServer; +import net.neoforged.neoforge.common.IOUtilities; + +import java.io.IOException; + +/** + * A codec-backed file that stores a single data instance. + * @param + */ +public class CMSingletonDataFileManager> implements IDataFileManager { + + protected final MinecraftServer server; + private final String dataKey; + private final T instance; + + public CMSingletonDataFileManager(MinecraftServer server, String dataKey, T instance) { + this.server = server; + this.dataKey = dataKey; + this.instance = instance; + } + + public T data() { + return this.instance; + } + + private void ensureFileReady() { + var dir = instance.getDataLocation(server); + DataFileUtil.ensureDirExists(dir); + } + + public void save() { + if (instance != null) { + ensureFileReady(); + + var fullData = new CompoundTag(); + fullData.putString("version", instance.getDataVersion()); + + var fileData = instance.codec() + .encodeStart(NbtOps.INSTANCE, instance) + .getOrThrow(); + + fullData.put("data", fileData); + + try { + IOUtilities.writeNbtCompressed(fullData, instance.getDataLocation(server).resolve(dataKey + ".dat")); + } catch (IOException e) { + LoggingUtil.modLog().error("Failed to write data: " + e.getMessage(), e); + } + } + } +} diff --git a/neoforge-main/src/main/java/dev/compactmods/machines/machine/Machines.java b/neoforge-main/src/main/java/dev/compactmods/machines/machine/Machines.java index dfdce612..c9ef4b88 100644 --- a/neoforge-main/src/main/java/dev/compactmods/machines/machine/Machines.java +++ b/neoforge-main/src/main/java/dev/compactmods/machines/machine/Machines.java @@ -2,10 +2,8 @@ import dev.compactmods.machines.api.item.component.MachineComponents; import dev.compactmods.machines.api.machine.MachineConstants; -import dev.compactmods.machines.api.room.RoomComponents; -import dev.compactmods.machines.api.room.RoomTemplate; +import dev.compactmods.machines.api.room.template.RoomTemplate; import dev.compactmods.machines.CMRegistries; -import dev.compactmods.machines.client.machine.MachinesClient; import dev.compactmods.machines.machine.block.BoundCompactMachineBlock; import dev.compactmods.machines.machine.block.BoundCompactMachineBlockEntity; import dev.compactmods.machines.machine.block.UnboundCompactMachineBlock; @@ -15,7 +13,6 @@ import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; import net.minecraft.core.component.DataComponentType; -import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.IntTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.Item; @@ -26,7 +23,6 @@ import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; import net.minecraft.world.level.material.PushReaction; import net.neoforged.bus.api.IEventBus; -import net.neoforged.fml.loading.FMLEnvironment; import net.neoforged.neoforge.attachment.AttachmentType; import net.neoforged.neoforge.attachment.IAttachmentHolder; import net.neoforged.neoforge.attachment.IAttachmentSerializer; @@ -38,127 +34,125 @@ import java.util.function.Supplier; public interface Machines { - BlockBehaviour.Properties MACHINE_BLOCK_PROPS = BlockBehaviour.Properties - .of() - .instrument(NoteBlockInstrument.COW_BELL) - .pushReaction(PushReaction.IGNORE) - .sound(SoundType.METAL) - .strength(8.0F, 20.0F) - .requiresCorrectToolForDrops(); - - Supplier MACHINE_ITEM_PROPS = Item.Properties::new; - - interface Blocks { - DeferredBlock UNBOUND_MACHINE = CMRegistries.BLOCKS.register("new_machine", () -> - new UnboundCompactMachineBlock(MACHINE_BLOCK_PROPS)); - - DeferredBlock BOUND_MACHINE = CMRegistries.BLOCKS.register("machine", () -> - new BoundCompactMachineBlock(MACHINE_BLOCK_PROPS)); - - static void prepare() { - } - } - - interface Items { - DeferredItem BOUND_MACHINE = CMRegistries.ITEMS.register("machine", - () -> new BoundCompactMachineItem(MACHINE_ITEM_PROPS.get())); - - DeferredItem UNBOUND_MACHINE = CMRegistries.ITEMS.register("new_machine", - () -> new UnboundCompactMachineItem(MACHINE_ITEM_PROPS.get())); - - static void prepare() { - } - - static ItemStack unbound() { - return unboundColored(0xFFFFFFFF); - } - - static ItemStack unboundColored(int color) { - final var stack = UNBOUND_MACHINE.toStack(); - stack.set(Machines.DataComponents.MACHINE_COLOR, color); - return stack; - } - - static ItemStack boundToRoom(String roomCode) { - return boundToRoom(roomCode, 0xFFFFFFFF); - } - - static ItemStack boundToRoom(String roomCode, int color) { - ItemStack stack = BOUND_MACHINE.toStack(); - stack.set(Machines.DataComponents.BOUND_ROOM_CODE, roomCode); - stack.set(Machines.DataComponents.MACHINE_COLOR, color); - return stack; - } - - static ItemStack forNewRoom(ResourceLocation templateID, RoomTemplate template) { - final var stack = UNBOUND_MACHINE.toStack(); - stack.set(Machines.DataComponents.ROOM_TEMPLATE_ID, templateID); - stack.set(Machines.DataComponents.ROOM_TEMPLATE, template); - stack.set(Machines.DataComponents.MACHINE_COLOR, template.defaultMachineColor().rgb()); - return stack; - } - } - - interface BlockEntities { - - DeferredHolder, BlockEntityType> UNBOUND_MACHINE = CMRegistries.BLOCK_ENTITIES.register(MachineConstants.UNBOUND_MACHINE_ENTITY.getPath(), () -> - BlockEntityType.Builder.of(UnboundCompactMachineEntity::new, Blocks.UNBOUND_MACHINE.get()) - .build(null)); - - DeferredHolder, BlockEntityType> MACHINE = CMRegistries.BLOCK_ENTITIES.register(MachineConstants.BOUND_MACHINE_ENTITY.getPath(), () -> - BlockEntityType.Builder.of(BoundCompactMachineBlockEntity::new, Blocks.BOUND_MACHINE.get()) - .build(null)); - - static void prepare() { - } - } - - interface DataComponents { - DeferredHolder, DataComponentType> BOUND_ROOM_CODE = CMRegistries.DATA_COMPONENTS - .registerComponentType("room_code", MachineComponents.BOUND_ROOM_CODE); - - DeferredHolder, DataComponentType> MACHINE_COLOR = CMRegistries.DATA_COMPONENTS - .registerComponentType("machine_color", MachineComponents.MACHINE_COLOR); - - DeferredHolder, DataComponentType> ROOM_TEMPLATE_ID = CMRegistries.DATA_COMPONENTS - .registerComponentType("room_template_id", MachineComponents.ROOM_TEMPLATE_ID); - - DeferredHolder, DataComponentType> ROOM_TEMPLATE = CMRegistries.DATA_COMPONENTS - .registerComponentType("room_template", RoomComponents.ROOM_TEMPLATE); - - static void prepare() { - } - } - - interface Attachments { - Supplier> MACHINE_COLOR = CMRegistries.ATTACHMENT_TYPES.register("machine_color", () -> AttachmentType - .builder(() -> 0xFFFFFFFF) - .serialize(new IAttachmentSerializer() { - @Override - public Integer read(IAttachmentHolder holder, IntTag tag, HolderLookup.Provider provider) { - return tag.getAsInt(); - } - - @Override - public @Nullable IntTag write(Integer attachment, HolderLookup.Provider provider) { - return IntTag.valueOf(attachment); - } - }) - .build()); - - static void prepare() { - } - } - - static void prepare() { - Blocks.prepare(); - Items.prepare(); - BlockEntities.prepare(); - DataComponents.prepare(); - Attachments.prepare(); - } - - static void registerEvents(IEventBus modBus) { - - } + BlockBehaviour.Properties MACHINE_BLOCK_PROPS = BlockBehaviour.Properties + .of() + .instrument(NoteBlockInstrument.COW_BELL) + .pushReaction(PushReaction.IGNORE) + .sound(SoundType.METAL) + .strength(8.0F, 20.0F) + .requiresCorrectToolForDrops(); + + Supplier MACHINE_ITEM_PROPS = Item.Properties::new; + + interface Blocks { + DeferredBlock UNBOUND_MACHINE = CMRegistries.BLOCKS.register("new_machine", () -> + new UnboundCompactMachineBlock(MACHINE_BLOCK_PROPS)); + + DeferredBlock BOUND_MACHINE = CMRegistries.BLOCKS.register("machine", () -> + new BoundCompactMachineBlock(MACHINE_BLOCK_PROPS)); + + static void prepare() { + } + } + + interface Items { + DeferredItem BOUND_MACHINE = CMRegistries.ITEMS.register("machine", + () -> new BoundCompactMachineItem(MACHINE_ITEM_PROPS.get())); + + DeferredItem UNBOUND_MACHINE = CMRegistries.ITEMS.register("new_machine", + () -> new UnboundCompactMachineItem(MACHINE_ITEM_PROPS.get())); + + static void prepare() { + } + + static ItemStack unbound() { + return unboundColored(0xFFFFFFFF); + } + + static ItemStack unboundColored(int color) { + final var stack = UNBOUND_MACHINE.toStack(); + stack.set(Machines.DataComponents.MACHINE_COLOR, color); + return stack; + } + + static ItemStack boundToRoom(String roomCode) { + return boundToRoom(roomCode, 0xFFFFFFFF); + } + + static ItemStack boundToRoom(String roomCode, int color) { + ItemStack stack = BOUND_MACHINE.toStack(); + stack.set(Machines.DataComponents.BOUND_ROOM_CODE, roomCode); + stack.set(Machines.DataComponents.MACHINE_COLOR, color); + return stack; + } + + static ItemStack forNewRoom(Holder.Reference templateHolder) { + var template = templateHolder.value(); + + final var stack = UNBOUND_MACHINE.toStack(); + stack.set(Machines.DataComponents.ROOM_TEMPLATE_ID, templateHolder.key().location()); + stack.set(Machines.DataComponents.MACHINE_COLOR, template.defaultMachineColor().rgb()); + return stack; + } + } + + interface BlockEntities { + + DeferredHolder, BlockEntityType> UNBOUND_MACHINE = CMRegistries.BLOCK_ENTITIES.register(MachineConstants.UNBOUND_MACHINE_ENTITY.getPath(), () -> + BlockEntityType.Builder.of(UnboundCompactMachineEntity::new, Blocks.UNBOUND_MACHINE.get()) + .build(null)); + + DeferredHolder, BlockEntityType> MACHINE = CMRegistries.BLOCK_ENTITIES.register(MachineConstants.BOUND_MACHINE_ENTITY.getPath(), () -> + BlockEntityType.Builder.of(BoundCompactMachineBlockEntity::new, Blocks.BOUND_MACHINE.get()) + .build(null)); + + static void prepare() { + } + } + + interface DataComponents { + DeferredHolder, DataComponentType> BOUND_ROOM_CODE = CMRegistries.DATA_COMPONENTS + .registerComponentType("room_code", MachineComponents.BOUND_ROOM_CODE); + + DeferredHolder, DataComponentType> MACHINE_COLOR = CMRegistries.DATA_COMPONENTS + .registerComponentType("machine_color", MachineComponents.MACHINE_COLOR); + + DeferredHolder, DataComponentType> ROOM_TEMPLATE_ID = CMRegistries.DATA_COMPONENTS + .registerComponentType("room_template", MachineComponents.ROOM_TEMPLATE_ID); + + static void prepare() { + } + } + + interface Attachments { + Supplier> MACHINE_COLOR = CMRegistries.ATTACHMENT_TYPES.register("machine_color", () -> AttachmentType + .builder(() -> 0xFFFFFFFF) + .serialize(new IAttachmentSerializer() { + @Override + public Integer read(IAttachmentHolder holder, IntTag tag, HolderLookup.Provider provider) { + return tag.getAsInt(); + } + + @Override + public @Nullable IntTag write(Integer attachment, HolderLookup.Provider provider) { + return IntTag.valueOf(attachment); + } + }) + .build()); + + static void prepare() { + } + } + + static void prepare() { + Blocks.prepare(); + Items.prepare(); + BlockEntities.prepare(); + DataComponents.prepare(); + Attachments.prepare(); + } + + static void registerEvents(IEventBus modBus) { + + } } diff --git a/neoforge-main/src/main/java/dev/compactmods/machines/machine/block/UnboundCompactMachineBlock.java b/neoforge-main/src/main/java/dev/compactmods/machines/machine/block/UnboundCompactMachineBlock.java index 6abfcd28..71f96f77 100644 --- a/neoforge-main/src/main/java/dev/compactmods/machines/machine/block/UnboundCompactMachineBlock.java +++ b/neoforge-main/src/main/java/dev/compactmods/machines/machine/block/UnboundCompactMachineBlock.java @@ -1,104 +1,104 @@ -package dev.compactmods.machines.machine.block; - -import dev.compactmods.machines.api.CompactMachines; -import dev.compactmods.machines.api.room.RoomTemplate; -import dev.compactmods.machines.LoggingUtil; -import dev.compactmods.machines.api.dimension.MissingDimensionException; -import dev.compactmods.machines.api.room.history.RoomEntryPoint; -import dev.compactmods.machines.api.shrinking.PSDTags; -import dev.compactmods.machines.machine.Machines; -import dev.compactmods.machines.room.RoomHelper; -import net.minecraft.core.BlockPos; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.ItemInteractionResult; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.DyeItem; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelReader; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class UnboundCompactMachineBlock extends CompactMachineBlock implements EntityBlock { - public UnboundCompactMachineBlock(Properties props) { - super(props); - } - - @Override - public ItemStack getCloneItemStack(BlockState state, HitResult target, LevelReader level, BlockPos pos, Player player) { - if (level.getBlockEntity(pos) instanceof UnboundCompactMachineEntity be) { - final var id = be.templateId(); - final var temp = be.template().orElse(RoomTemplate.INVALID_TEMPLATE); - - if (id != null && !temp.equals(RoomTemplate.INVALID_TEMPLATE)) { - var item = Machines.Items.forNewRoom(id, temp); - be.getExistingData(Machines.Attachments.MACHINE_COLOR).ifPresent(color -> { - item.set(Machines.DataComponents.MACHINE_COLOR, color); - }); - - return item; - } - } - - return Machines.Items.unbound(); - } - - @Override - public @Nullable BlockEntity newBlockEntity(@NotNull BlockPos pos, @NotNull BlockState state) { - return new UnboundCompactMachineEntity(pos, state); - } - - @Override - protected ItemInteractionResult useItemOn(ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand p_316595_, BlockHitResult p_316140_) { - - if (stack.getItem() instanceof DyeItem dye && !level.isClientSide && level instanceof ServerLevel serverLevel) { - return tryDyingMachine(serverLevel, pos, player, dye, stack); - } - - MinecraftServer server = level.getServer(); - if (stack.is(PSDTags.ITEM) && player instanceof ServerPlayer sp) { - level.getBlockEntity(pos, Machines.BlockEntities.UNBOUND_MACHINE.get()).ifPresent(unboundEntity -> { - RoomTemplate template = unboundEntity.template().orElse(RoomTemplate.INVALID_TEMPLATE); - if (!template.equals(RoomTemplate.INVALID_TEMPLATE)) { - int color = unboundEntity.getData(Machines.Attachments.MACHINE_COLOR); - - try { - // Generate a new machine room - final var newRoom = CompactMachines.newRoom(server, template, sp.getUUID()); - - // Change into a bound machine block - level.setBlock(pos, Machines.Blocks.BOUND_MACHINE.get().defaultBlockState(), Block.UPDATE_ALL); - - // Set up binding and enter - level.getBlockEntity(pos, Machines.BlockEntities.MACHINE.get()).ifPresent(ent -> { - ent.setConnectedRoom(newRoom.code()); - ent.setData(Machines.Attachments.MACHINE_COLOR, color); - - try { - RoomHelper.teleportPlayerIntoRoom(server, sp, newRoom, RoomEntryPoint.playerEnteringMachine(player)); - } catch (MissingDimensionException e) { - throw new RuntimeException(e); - } - }); - - } catch (MissingDimensionException e) { - LoggingUtil.modLog().error("Error occurred while generating new room and machine info for first player entry.", e); - } - } else { - LoggingUtil.modLog().fatal("Tried to create and enter an invalidly-registered room. Something went very wrong!"); - } - }); - } - - return super.useItemOn(stack, state, level, pos, player, p_316595_, p_316140_); - } -} +package dev.compactmods.machines.machine.block; + +import dev.compactmods.machines.api.CompactMachines; +import dev.compactmods.machines.api.room.template.RoomTemplate; +import dev.compactmods.machines.LoggingUtil; +import dev.compactmods.machines.api.dimension.MissingDimensionException; +import dev.compactmods.machines.api.room.history.RoomEntryPoint; +import dev.compactmods.machines.api.room.template.RoomTemplateHelper; +import dev.compactmods.machines.api.shrinking.PSDTags; +import dev.compactmods.machines.machine.Machines; +import dev.compactmods.machines.room.RoomHelper; +import net.minecraft.core.BlockPos; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.ItemInteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.DyeItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public class UnboundCompactMachineBlock extends CompactMachineBlock implements EntityBlock { + public UnboundCompactMachineBlock(Properties props) { + super(props); + } + + @Override + public ItemStack getCloneItemStack(BlockState state, HitResult target, LevelReader level, BlockPos pos, Player player) { + if (level.getBlockEntity(pos) instanceof UnboundCompactMachineEntity be) { + final var id = be.templateId(); + if (id != null) { + final var template = RoomTemplateHelper.getTemplateHolder(level, id); + var item = Machines.Items.forNewRoom(template); + be.getExistingData(Machines.Attachments.MACHINE_COLOR).ifPresent(color -> { + item.set(Machines.DataComponents.MACHINE_COLOR, color); + }); + + return item; + } + } + + return Machines.Items.unbound(); + } + + @Override + public @Nullable BlockEntity newBlockEntity(@NotNull BlockPos pos, @NotNull BlockState state) { + return new UnboundCompactMachineEntity(pos, state); + } + + @Override + protected ItemInteractionResult useItemOn(ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand p_316595_, BlockHitResult p_316140_) { + if (stack.getItem() instanceof DyeItem dye && !level.isClientSide && level instanceof ServerLevel serverLevel) { + return tryDyingMachine(serverLevel, pos, player, dye, stack); + } + + MinecraftServer server = level.getServer(); + if (stack.is(PSDTags.ITEM) && player instanceof ServerPlayer sp) { + level.getBlockEntity(pos, Machines.BlockEntities.UNBOUND_MACHINE.get()).ifPresent(unboundEntity -> { + + RoomTemplate template = RoomTemplateHelper.getTemplate(level, unboundEntity.templateId()); + if (!template.equals(RoomTemplate.INVALID_TEMPLATE)) { + int color = unboundEntity.getData(Machines.Attachments.MACHINE_COLOR); + + try { + // Generate a new machine room + final var newRoom = CompactMachines.newRoom(server, template, sp.getUUID()); + + // Change into a bound machine block + level.setBlock(pos, Machines.Blocks.BOUND_MACHINE.get().defaultBlockState(), Block.UPDATE_ALL); + + // Set up binding and enter + level.getBlockEntity(pos, Machines.BlockEntities.MACHINE.get()).ifPresent(ent -> { + ent.setConnectedRoom(newRoom.code()); + ent.setData(Machines.Attachments.MACHINE_COLOR, color); + + try { + RoomHelper.teleportPlayerIntoRoom(server, sp, newRoom, RoomEntryPoint.playerEnteringMachine(player)); + } catch (MissingDimensionException e) { + throw new RuntimeException(e); + } + }); + + } catch (MissingDimensionException e) { + LoggingUtil.modLog().error("Error occurred while generating new room and machine info for first player entry.", e); + } + } else { + LoggingUtil.modLog().fatal("Tried to create and enter an invalidly-registered room. Something went very wrong!"); + } + }); + } + + return super.useItemOn(stack, state, level, pos, player, p_316595_, p_316140_); + } +} diff --git a/neoforge-main/src/main/java/dev/compactmods/machines/machine/block/UnboundCompactMachineEntity.java b/neoforge-main/src/main/java/dev/compactmods/machines/machine/block/UnboundCompactMachineEntity.java index 04955b15..f484ddc0 100644 --- a/neoforge-main/src/main/java/dev/compactmods/machines/machine/block/UnboundCompactMachineEntity.java +++ b/neoforge-main/src/main/java/dev/compactmods/machines/machine/block/UnboundCompactMachineEntity.java @@ -1,74 +1,68 @@ -package dev.compactmods.machines.machine.block; - -import dev.compactmods.machines.api.machine.block.IUnboundCompactMachineBlockEntity; -import dev.compactmods.machines.api.room.RoomTemplate; -import dev.compactmods.machines.machine.Machines; -import net.minecraft.core.BlockPos; -import net.minecraft.core.HolderLookup; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Optional; - -public class UnboundCompactMachineEntity extends BlockEntity implements IUnboundCompactMachineBlockEntity { - - private @Nullable ResourceLocation templateId; - - public UnboundCompactMachineEntity(BlockPos pos, BlockState state) { - super(Machines.BlockEntities.UNBOUND_MACHINE.get(), pos, state); - this.templateId = null; - } - - @Override - public void loadAdditional(@NotNull CompoundTag nbt, HolderLookup.Provider holders) { - super.loadAdditional(nbt, holders); - if (nbt.contains(NBT_TEMPLATE_ID)) - this.templateId = ResourceLocation.parse(nbt.getString(NBT_TEMPLATE_ID)); - } - - @Override - protected void saveAdditional(@NotNull CompoundTag nbt, HolderLookup.Provider holders) { - super.saveAdditional(nbt, holders); - if (templateId != null) - nbt.putString(NBT_TEMPLATE_ID, templateId.toString()); - } - - @Override - public CompoundTag getUpdateTag(HolderLookup.Provider holders) { - CompoundTag data = super.getUpdateTag(holders); - saveAdditional(data, holders); - - if (templateId != null) - data.putString(NBT_TEMPLATE_ID, templateId.toString()); - - return data; - } - - @Override - public void handleUpdateTag(CompoundTag tag, HolderLookup.Provider lookupProvider) { - super.handleUpdateTag(tag, lookupProvider); - - if (tag.contains(NBT_TEMPLATE_ID)) - templateId = ResourceLocation.parse(tag.getString(NBT_TEMPLATE_ID)); - } - - public void setTemplate(ResourceLocation template) { - this.templateId = template; - this.setChanged(); - } - - @Nullable - public ResourceLocation templateId() { - return templateId; - } - - public Optional template() { - assert level != null; - var t = this.components().getOrDefault(Machines.DataComponents.ROOM_TEMPLATE.get(), RoomTemplate.INVALID_TEMPLATE); - return Optional.ofNullable(t); - } -} +package dev.compactmods.machines.machine.block; + +import dev.compactmods.machines.api.machine.block.IUnboundCompactMachineBlockEntity; +import dev.compactmods.machines.api.room.template.RoomTemplate; +import dev.compactmods.machines.machine.Machines; +import net.minecraft.core.BlockPos; +import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; + +public class UnboundCompactMachineEntity extends BlockEntity implements IUnboundCompactMachineBlockEntity { + + private @Nullable ResourceLocation templateId; + + public UnboundCompactMachineEntity(BlockPos pos, BlockState state) { + super(Machines.BlockEntities.UNBOUND_MACHINE.get(), pos, state); + this.templateId = null; + } + + @Override + public void loadAdditional(@NotNull CompoundTag nbt, HolderLookup.Provider holders) { + super.loadAdditional(nbt, holders); + if (nbt.contains(NBT_TEMPLATE_ID)) + this.templateId = ResourceLocation.parse(nbt.getString(NBT_TEMPLATE_ID)); + } + + @Override + protected void saveAdditional(@NotNull CompoundTag nbt, HolderLookup.Provider holders) { + super.saveAdditional(nbt, holders); + if (templateId != null) + nbt.putString(NBT_TEMPLATE_ID, templateId.toString()); + } + + @Override + public CompoundTag getUpdateTag(HolderLookup.Provider holders) { + CompoundTag data = super.getUpdateTag(holders); + saveAdditional(data, holders); + + if (templateId != null) + data.putString(NBT_TEMPLATE_ID, templateId.toString()); + + return data; + } + + @Override + public void handleUpdateTag(CompoundTag tag, HolderLookup.Provider lookupProvider) { + super.handleUpdateTag(tag, lookupProvider); + + if (tag.contains(NBT_TEMPLATE_ID)) + templateId = ResourceLocation.parse(tag.getString(NBT_TEMPLATE_ID)); + } + + public void setTemplate(ResourceLocation template) { + this.templateId = template; + this.setChanged(); + } + + @Nullable + public ResourceLocation templateId() { + return templateId; + } +} diff --git a/neoforge-main/src/main/java/dev/compactmods/machines/machine/item/UnboundCompactMachineItem.java b/neoforge-main/src/main/java/dev/compactmods/machines/machine/item/UnboundCompactMachineItem.java index a3d21091..7df27dc4 100644 --- a/neoforge-main/src/main/java/dev/compactmods/machines/machine/item/UnboundCompactMachineItem.java +++ b/neoforge-main/src/main/java/dev/compactmods/machines/machine/item/UnboundCompactMachineItem.java @@ -1,69 +1,58 @@ -package dev.compactmods.machines.machine.item; - -import dev.compactmods.machines.api.Translations; -import dev.compactmods.machines.api.machine.MachineTranslations; -import dev.compactmods.machines.api.room.RoomTemplate; -import dev.compactmods.machines.machine.Machines; -import net.minecraft.Util; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.CommonColors; -import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.TooltipFlag; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - -/** - * Represents a machine item that has not been bound to a room yet, - * but has an assigned template to use. - */ -public class UnboundCompactMachineItem extends BlockItem { - - public UnboundCompactMachineItem(Properties builder) { - super(Machines.Blocks.UNBOUND_MACHINE.get(), builder); - } - - @Override - public Component getName(ItemStack pStack) { - return Component.translatableWithFallback(getDescriptionId(pStack), "Compact Machine"); - } - - @NotNull - @Override - public String getDescriptionId(ItemStack stack) { - return Util.makeDescriptionId("machine", getTemplateId(stack)); - } - - @Override - public ItemStack getDefaultInstance() { - var stack = new ItemStack(this); - stack.set(Machines.DataComponents.ROOM_TEMPLATE_ID, RoomTemplate.NO_TEMPLATE); - stack.set(Machines.DataComponents.MACHINE_COLOR, CommonColors.WHITE); - return stack; - } - - private ResourceLocation getTemplateId(ItemStack stack) { - return stack.get(Machines.DataComponents.ROOM_TEMPLATE_ID); - } - - @Override - public void appendHoverText(ItemStack stack, TooltipContext context, List tooltip, TooltipFlag flags) { - super.appendHoverText(stack, context, tooltip, flags); - - var registries = context.registries(); - - // We need NBT data for the rest of this - boolean sneaking = Screen.hasShiftDown(); - - tooltip.add(Component.translatableWithFallback(MachineTranslations.IDs.NEW_MACHINE, "New Machine")); - - if (sneaking && registries != null) { - stack.addToTooltip(Machines.DataComponents.ROOM_TEMPLATE, context, tooltip::add, flags); - } else { - tooltip.add(Translations.HINT_HOLD_SHIFT.get()); - } - } -} +package dev.compactmods.machines.machine.item; + +import dev.compactmods.machines.api.Translations; +import dev.compactmods.machines.api.machine.MachineTranslations; +import dev.compactmods.machines.api.room.template.RoomTemplate; +import dev.compactmods.machines.machine.Machines; +import net.minecraft.Util; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.CommonColors; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Represents a machine item that has not been bound to a room yet, + * but has an assigned template to use. + */ +public class UnboundCompactMachineItem extends BlockItem { + + public UnboundCompactMachineItem(Properties builder) { + super(Machines.Blocks.UNBOUND_MACHINE.get(), builder); + } + + @Override + public Component getName(ItemStack pStack) { + return Component.translatableWithFallback(getDescriptionId(pStack), "Compact Machine"); + } + + @NotNull + @Override + public String getDescriptionId(ItemStack stack) { + return Util.makeDescriptionId("machine", getTemplateId(stack)); + } + + @Override + public ItemStack getDefaultInstance() { + var stack = new ItemStack(this); + stack.set(Machines.DataComponents.ROOM_TEMPLATE_ID, RoomTemplate.NO_TEMPLATE); + stack.set(Machines.DataComponents.MACHINE_COLOR, CommonColors.WHITE); + return stack; + } + + private ResourceLocation getTemplateId(ItemStack stack) { + return stack.get(Machines.DataComponents.ROOM_TEMPLATE_ID); + } + + @Override + public void appendHoverText(ItemStack stack, TooltipContext context, List tooltip, TooltipFlag flags) { + super.appendHoverText(stack, context, tooltip, flags); + + tooltip.add(Component.translatableWithFallback(MachineTranslations.IDs.NEW_MACHINE, "New Machine")); + } +} diff --git a/neoforge-main/src/main/java/dev/compactmods/machines/player/PlayerEntryPointHistoryManager.java b/neoforge-main/src/main/java/dev/compactmods/machines/player/PlayerEntryPointHistoryManager.java index dfed95bf..41268b47 100644 --- a/neoforge-main/src/main/java/dev/compactmods/machines/player/PlayerEntryPointHistoryManager.java +++ b/neoforge-main/src/main/java/dev/compactmods/machines/player/PlayerEntryPointHistoryManager.java @@ -1,211 +1,210 @@ -package dev.compactmods.machines.player; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import dev.compactmods.feather.MemoryGraph; -import dev.compactmods.feather.edge.impl.EmptyEdge; -import dev.compactmods.feather.node.Node; -import dev.compactmods.feather.traversal.GraphNodeTransformationFunction; -import dev.compactmods.machines.api.CompactMachines; -import dev.compactmods.machines.api.dimension.CompactDimension; -import dev.compactmods.machines.api.room.history.IPlayerEntryPointHistoryManager; -import dev.compactmods.machines.api.room.history.PlayerRoomHistoryEntry; -import dev.compactmods.machines.api.room.history.RoomEntryPoint; -import dev.compactmods.machines.api.room.history.RoomEntryResult; -import dev.compactmods.machines.data.CodecHolder; -import dev.compactmods.machines.data.CMDataFile; -import dev.compactmods.machines.room.graph.node.RoomReferenceNode; -import net.minecraft.core.UUIDUtil; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.player.Player; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.jetbrains.annotations.NotNull; - -import java.nio.file.Path; -import java.time.Instant; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -public class PlayerEntryPointHistoryManager implements CodecHolder, CMDataFile, IPlayerEntryPointHistoryManager { - - private static final Logger LOGS = LogManager.getLogger(); - - public static final Codec CODEC = RecordCodecBuilder.create(inst -> inst.group( - Codec.INT.fieldOf("max_depth").forGetter(x -> x.maxDepth), - Codec.unboundedMap(UUIDUtil.STRING_CODEC, PlayerRoomHistoryEntry.CODEC.listOf()) - .fieldOf("history") - .forGetter(PlayerEntryPointHistoryManager::playerRoomHistory) - ).apply(inst, PlayerEntryPointHistoryManager::new)); - - private final MemoryGraph graph; - private final int maxDepth; - - private final HashMap roomNodes; - private final HashMap playerNodes; - private final HashMap latestEntryPoints; - - private static final GraphNodeTransformationFunction> PLAYER_TO_HISTORY = - (graph, input) -> graph.outboundEdges(input, PlayerEntryPointNode.class) - .flatMap(e -> graph.outboundEdges(e.target().get(), RoomReferenceNode.class, PlayerRoomEntryEdge.class)) - .map(PlayerEntryPointHistoryManager::fromEdge) - .sorted(Comparator.comparing(PlayerRoomHistoryEntry::instant).reversed()); - - private static final GraphNodeTransformationFunction> PLAYER_TO_HISTORY_NODES = - (graph, input) -> graph.outboundEdges(input, PlayerEntryPointNode.class) - .flatMap(e -> graph.outboundEdges(e.target().get(), RoomReferenceNode.class, PlayerRoomEntryEdge.class)) - .sorted(Comparator.comparing(PlayerRoomEntryEdge::entryTime).reversed()) - .map(e -> e.source().get()); - - public PlayerEntryPointHistoryManager(int maxDepth) { - this(maxDepth, Collections.emptyMap()); - } - - private PlayerEntryPointHistoryManager(int maxDepth, Map> history) { - this.graph = new MemoryGraph(); - this.maxDepth = maxDepth; - this.roomNodes = new HashMap<>(); - this.playerNodes = new HashMap<>(); - this.latestEntryPoints = new HashMap<>(); - - for(var entry : history.entrySet()) { - LOGS.debug("Loading history for player: " + entry.getKey()); - entry.getValue() - .stream() - .sorted(Comparator.comparing(PlayerRoomHistoryEntry::instant)) - .forEach(hist -> enterRoom(entry.getKey(), hist)); - } - } - - @Override - public Path getDataLocation(MinecraftServer server) { - return CompactDimension.getDataDirectory(server) - .resolve("data") - .resolve("player_spawns"); - } - - private static PlayerRoomHistoryEntry fromEdge(PlayerRoomEntryEdge edge) { - return new PlayerRoomHistoryEntry(edge.target().get().code(), edge.entryTime(), edge.source().get().data()); - } - - public void popHistory(Player player, int steps) { - final var playerNode = playerNodes.get(player.getUUID()); - if (playerNode == null) return; - - var historyNodes = graph.transformFunc(PLAYER_TO_HISTORY_NODES, playerNode) - .limit(steps) - .collect(Collectors.toSet()); - - historyNodes.forEach(graph::removeNode); - - final var newLatest = graph.transformFunc(PLAYER_TO_HISTORY_NODES, playerNode).findFirst(); - newLatest.ifPresentOrElse( - l -> latestEntryPoints.replace(player.getUUID(), l), - () -> latestEntryPoints.remove(player.getUUID())); - } - - public Optional lastHistory(Player player) { - final var lastEntry = latestEntryPoints.get(player.getUUID()); - return graph.outboundEdges(lastEntry, RoomReferenceNode.class, PlayerRoomEntryEdge.class) - .max(Comparator.comparing(PlayerRoomEntryEdge::entryTime)) - .map(PlayerEntryPointHistoryManager::fromEdge); - } - - public Stream history(Player player) { - return history(player.getUUID()); - } - - public Stream history(UUID player) { - final var playerNode = playerNodes.get(player); - if (playerNode == null) - return Stream.empty(); - - return graph.transformFunc(PLAYER_TO_HISTORY, playerNode); - } - - private Map> playerRoomHistory() { - return playerNodes.keySet() - .stream() - .collect(Collectors.toMap(pid -> pid, pid -> history(pid).toList())); - } - - public RoomEntryResult enterRoom(UUID player, PlayerRoomHistoryEntry history) { - if (!CompactMachines.isValidRoomCode(history.roomCode())) - return RoomEntryResult.FAILED_ROOM_INVALID; - - PlayerReferenceNode playerNode = getOrCreatePlayer(player); - - long depth = graph.outboundEdges(playerNode, PlayerEntryPointNode.class).count(); - if (depth >= maxDepth) - return RoomEntryResult.FAILED_TOO_FAR_DOWN; - - RoomReferenceNode roomNode = getOrCreateRoom(history.roomCode()); - - PlayerEntryPointNode entryNode = new PlayerEntryPointNode(UUID.randomUUID(), history.entryPoint()); - if (latestEntryPoints.containsKey(player)) { - final var prev = latestEntryPoints.replace(player, entryNode); - if (prev != null) - graph.connectNodes(prev, entryNode, new EmptyEdge<>(prev, entryNode)); - } else { - latestEntryPoints.put(player, entryNode); - } - - // PlayerReferenceNode ---> RoomEntryPointNode - // RoomEntryPointNode -[PlayerRoomEntryEdge]-> RoomReferenceNode - graph.connectNodes(playerNode, entryNode, new EmptyEdge<>(playerNode, entryNode)); - graph.connectNodes(entryNode, roomNode, new PlayerRoomEntryEdge(entryNode, roomNode, history.instant())); - - return RoomEntryResult.SUCCESS; - } - - public RoomEntryResult enterRoom(Player player, String roomCode, RoomEntryPoint entryPoint) { - return enterRoom(player.getUUID(), new PlayerRoomHistoryEntry(roomCode, Instant.now(), entryPoint)); - } - - @NotNull - private RoomReferenceNode getOrCreateRoom(String roomCode) { - return roomNodes.computeIfAbsent(roomCode, (code) -> { - var node = new RoomReferenceNode(roomCode); - graph.addNode(node); - return node; - }); - } - - @NotNull - private PlayerReferenceNode getOrCreatePlayer(UUID player) { - return playerNodes.computeIfAbsent(player, (o) -> { - var node = new PlayerReferenceNode(UUID.randomUUID(), player); - graph.addNode(node); - return node; - }); - } - - public void clearHistory(ServerPlayer player) { - if (!playerNodes.containsKey(player.getUUID())) - return; - - final var playerNode = playerNodes.get(player.getUUID()); - final var list = graph.successors(playerNode) - .filter(PlayerEntryPointNode.class::isInstance) - .toList(); - - for (Node node : list) { - graph.removeNode(node); - } - - latestEntryPoints.remove(player.getUUID()); - } - - @Override - public Codec codec() { - return CODEC; - } -} +package dev.compactmods.machines.player; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import dev.compactmods.feather.MemoryGraph; +import dev.compactmods.feather.edge.impl.EmptyEdge; +import dev.compactmods.feather.node.Node; +import dev.compactmods.feather.traversal.GraphNodeTransformationFunction; +import dev.compactmods.machines.api.CompactMachines; +import dev.compactmods.machines.api.dimension.CompactDimension; +import dev.compactmods.machines.api.room.data.CMRoomDataLocations; +import dev.compactmods.machines.api.room.history.IPlayerEntryPointHistoryManager; +import dev.compactmods.machines.api.room.history.PlayerRoomHistoryEntry; +import dev.compactmods.machines.api.room.history.RoomEntryPoint; +import dev.compactmods.machines.api.room.history.RoomEntryResult; +import dev.compactmods.machines.data.CodecHolder; +import dev.compactmods.machines.data.CMDataFile; +import dev.compactmods.machines.room.graph.node.RoomReferenceNode; +import net.minecraft.core.UUIDUtil; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.player.Player; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; + +import java.nio.file.Path; +import java.time.Instant; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class PlayerEntryPointHistoryManager implements CodecHolder, CMDataFile, IPlayerEntryPointHistoryManager { + + private static final Logger LOGS = LogManager.getLogger(); + + public static final Codec CODEC = RecordCodecBuilder.create(inst -> inst.group( + Codec.INT.fieldOf("max_depth").forGetter(x -> x.maxDepth), + Codec.unboundedMap(UUIDUtil.STRING_CODEC, PlayerRoomHistoryEntry.CODEC.listOf()) + .fieldOf("history") + .forGetter(PlayerEntryPointHistoryManager::playerRoomHistory) + ).apply(inst, PlayerEntryPointHistoryManager::new)); + + private final MemoryGraph graph; + private final int maxDepth; + + private final HashMap roomNodes; + private final HashMap playerNodes; + private final HashMap latestEntryPoints; + + private static final GraphNodeTransformationFunction> PLAYER_TO_HISTORY = + (graph, input) -> graph.outboundEdges(input, PlayerEntryPointNode.class) + .flatMap(e -> graph.outboundEdges(e.target().get(), RoomReferenceNode.class, PlayerRoomEntryEdge.class)) + .map(PlayerEntryPointHistoryManager::fromEdge) + .sorted(Comparator.comparing(PlayerRoomHistoryEntry::instant).reversed()); + + private static final GraphNodeTransformationFunction> PLAYER_TO_HISTORY_NODES = + (graph, input) -> graph.outboundEdges(input, PlayerEntryPointNode.class) + .flatMap(e -> graph.outboundEdges(e.target().get(), RoomReferenceNode.class, PlayerRoomEntryEdge.class)) + .sorted(Comparator.comparing(PlayerRoomEntryEdge::entryTime).reversed()) + .map(e -> e.source().get()); + + public PlayerEntryPointHistoryManager(int maxDepth) { + this(maxDepth, Collections.emptyMap()); + } + + private PlayerEntryPointHistoryManager(int maxDepth, Map> history) { + this.graph = new MemoryGraph(); + this.maxDepth = maxDepth; + this.roomNodes = new HashMap<>(); + this.playerNodes = new HashMap<>(); + this.latestEntryPoints = new HashMap<>(); + + for(var entry : history.entrySet()) { + LOGS.debug("Loading history for player: " + entry.getKey()); + entry.getValue() + .stream() + .sorted(Comparator.comparing(PlayerRoomHistoryEntry::instant)) + .forEach(hist -> enterRoom(entry.getKey(), hist)); + } + } + + @Override + public Path getDataLocation(MinecraftServer server) { + return CMRoomDataLocations.PLAYER_SPAWNS.apply(server); + } + + private static PlayerRoomHistoryEntry fromEdge(PlayerRoomEntryEdge edge) { + return new PlayerRoomHistoryEntry(edge.target().get().code(), edge.entryTime(), edge.source().get().data()); + } + + public void popHistory(Player player, int steps) { + final var playerNode = playerNodes.get(player.getUUID()); + if (playerNode == null) return; + + var historyNodes = graph.transformFunc(PLAYER_TO_HISTORY_NODES, playerNode) + .limit(steps) + .collect(Collectors.toSet()); + + historyNodes.forEach(graph::removeNode); + + final var newLatest = graph.transformFunc(PLAYER_TO_HISTORY_NODES, playerNode).findFirst(); + newLatest.ifPresentOrElse( + l -> latestEntryPoints.replace(player.getUUID(), l), + () -> latestEntryPoints.remove(player.getUUID())); + } + + public Optional lastHistory(Player player) { + final var lastEntry = latestEntryPoints.get(player.getUUID()); + return graph.outboundEdges(lastEntry, RoomReferenceNode.class, PlayerRoomEntryEdge.class) + .max(Comparator.comparing(PlayerRoomEntryEdge::entryTime)) + .map(PlayerEntryPointHistoryManager::fromEdge); + } + + public Stream history(Player player) { + return history(player.getUUID()); + } + + public Stream history(UUID player) { + final var playerNode = playerNodes.get(player); + if (playerNode == null) + return Stream.empty(); + + return graph.transformFunc(PLAYER_TO_HISTORY, playerNode); + } + + private Map> playerRoomHistory() { + return playerNodes.keySet() + .stream() + .collect(Collectors.toMap(pid -> pid, pid -> history(pid).toList())); + } + + public RoomEntryResult enterRoom(UUID player, PlayerRoomHistoryEntry history) { + if (!CompactMachines.isValidRoomCode(history.roomCode())) + return RoomEntryResult.FAILED_ROOM_INVALID; + + PlayerReferenceNode playerNode = getOrCreatePlayer(player); + + long depth = graph.outboundEdges(playerNode, PlayerEntryPointNode.class).count(); + if (depth >= maxDepth) + return RoomEntryResult.FAILED_TOO_FAR_DOWN; + + RoomReferenceNode roomNode = getOrCreateRoom(history.roomCode()); + + PlayerEntryPointNode entryNode = new PlayerEntryPointNode(UUID.randomUUID(), history.entryPoint()); + if (latestEntryPoints.containsKey(player)) { + final var prev = latestEntryPoints.replace(player, entryNode); + if (prev != null) + graph.connectNodes(prev, entryNode, new EmptyEdge<>(prev, entryNode)); + } else { + latestEntryPoints.put(player, entryNode); + } + + // PlayerReferenceNode ---> RoomEntryPointNode + // RoomEntryPointNode -[PlayerRoomEntryEdge]-> RoomReferenceNode + graph.connectNodes(playerNode, entryNode, new EmptyEdge<>(playerNode, entryNode)); + graph.connectNodes(entryNode, roomNode, new PlayerRoomEntryEdge(entryNode, roomNode, history.instant())); + + return RoomEntryResult.SUCCESS; + } + + public RoomEntryResult enterRoom(Player player, String roomCode, RoomEntryPoint entryPoint) { + return enterRoom(player.getUUID(), new PlayerRoomHistoryEntry(roomCode, Instant.now(), entryPoint)); + } + + @NotNull + private RoomReferenceNode getOrCreateRoom(String roomCode) { + return roomNodes.computeIfAbsent(roomCode, (code) -> { + var node = new RoomReferenceNode(roomCode); + graph.addNode(node); + return node; + }); + } + + @NotNull + private PlayerReferenceNode getOrCreatePlayer(UUID player) { + return playerNodes.computeIfAbsent(player, (o) -> { + var node = new PlayerReferenceNode(UUID.randomUUID(), player); + graph.addNode(node); + return node; + }); + } + + public void clearHistory(ServerPlayer player) { + if (!playerNodes.containsKey(player.getUUID())) + return; + + final var playerNode = playerNodes.get(player.getUUID()); + final var list = graph.successors(playerNode) + .filter(PlayerEntryPointNode.class::isInstance) + .toList(); + + for (Node node : list) { + graph.removeNode(node); + } + + latestEntryPoints.remove(player.getUUID()); + } + + @Override + public Codec codec() { + return CODEC; + } +} diff --git a/neoforge-main/src/main/java/dev/compactmods/machines/room/RoomRegistrar.java b/neoforge-main/src/main/java/dev/compactmods/machines/room/RoomRegistrar.java index dcf161dc..344660de 100644 --- a/neoforge-main/src/main/java/dev/compactmods/machines/room/RoomRegistrar.java +++ b/neoforge-main/src/main/java/dev/compactmods/machines/room/RoomRegistrar.java @@ -5,7 +5,7 @@ import dev.compactmods.machines.api.room.data.CMRoomDataLocations; import dev.compactmods.machines.data.CMDataFile; import dev.compactmods.machines.api.room.RoomInstance; -import dev.compactmods.machines.api.room.RoomTemplate; +import dev.compactmods.machines.api.room.template.RoomTemplate; import dev.compactmods.machines.api.room.registration.IRoomRegistrar; import dev.compactmods.machines.api.room.registration.IRoomBuilder; import dev.compactmods.feather.MemoryGraph; @@ -19,6 +19,7 @@ import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.NotNull; +import java.io.File; import java.nio.file.Path; import java.util.HashMap; import java.util.List; @@ -120,7 +121,13 @@ private void registerDirty(RoomRegistrationNode node) { @Override public Path getDataLocation(MinecraftServer server) { - return CMRoomDataLocations.REGISTRATION_DATA.apply(server); + return CMRoomDataLocations.DATA_ROOT.apply(server); + } + + public static File getFile(MinecraftServer server) { + return CMRoomDataLocations.DATA_ROOT.apply(server) + .resolve("room_registrations.dat") + .toFile(); } @Override diff --git a/neoforge-main/src/main/java/dev/compactmods/machines/room/spawn/SpawnManager.java b/neoforge-main/src/main/java/dev/compactmods/machines/room/spawn/SpawnManager.java index fa2338a0..1f532f90 100644 --- a/neoforge-main/src/main/java/dev/compactmods/machines/room/spawn/SpawnManager.java +++ b/neoforge-main/src/main/java/dev/compactmods/machines/room/spawn/SpawnManager.java @@ -1,102 +1,102 @@ -package dev.compactmods.machines.room.spawn; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import com.mojang.serialization.codecs.UnboundedMapCodec; -import dev.compactmods.machines.api.room.data.CMRoomDataLocations; -import dev.compactmods.machines.data.CMDataFile; -import dev.compactmods.machines.api.room.spatial.IRoomBoundaries; -import dev.compactmods.machines.api.room.spawn.IRoomSpawn; -import dev.compactmods.machines.api.room.spawn.IRoomSpawnManager; -import dev.compactmods.machines.api.room.spawn.IRoomSpawns; -import dev.compactmods.machines.data.CodecHolder; -import net.minecraft.core.UUIDUtil; -import net.minecraft.server.MinecraftServer; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec2; -import net.minecraft.world.phys.Vec3; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.nio.file.Path; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.UUID; - -public class SpawnManager implements IRoomSpawnManager, CodecHolder, CMDataFile { - - private final Logger LOGS = LogManager.getLogger(); - - private static final UnboundedMapCodec PLAYER_SPAWNS_CODEC = Codec.unboundedMap(UUIDUtil.STRING_CODEC, RoomSpawn.CODEC); - private static final Codec CODEC = RecordCodecBuilder.create(inst -> inst.group( - Codec.STRING.fieldOf("roomCode").forGetter(x -> x.roomCode), - PLAYER_SPAWNS_CODEC.fieldOf("player_spawns").forGetter(x -> x.playerSpawns), - RoomSpawn.CODEC.fieldOf("default_spawn").forGetter(x -> x.defaultSpawn) - ).apply(inst, SpawnManager::new)); - - private final String roomCode; - private RoomSpawn defaultSpawn; - private final Map playerSpawns; - private AABB roomBounds; - - public SpawnManager(String roomCode) { - this(roomCode, Collections.emptyMap(), null); - this.defaultSpawn = null; - } - - public SpawnManager(String roomCode, IRoomBoundaries roomBounds) { - this(roomCode, Collections.emptyMap(), new RoomSpawn(roomBounds.defaultSpawn(), Vec2.ZERO)); - this.roomBounds = roomBounds.innerBounds(); - } - - public SpawnManager(String roomCode, Map playerSpawns, RoomSpawn defaultSpawn) { - this.roomCode = roomCode; - this.playerSpawns = new HashMap<>(playerSpawns); - this.defaultSpawn = defaultSpawn; - } - - @Override - public void resetPlayerSpawn(UUID player) { - playerSpawns.remove(player); - } - - @Override - public void setDefaultSpawn(Vec3 position, Vec2 rotation) { - defaultSpawn = new RoomSpawn(position, rotation); - } - - @Override - public IRoomSpawns spawns() { - final var ps = new HashMap(); - playerSpawns.forEach(ps::putIfAbsent); - return new RoomSpawns(defaultSpawn, ps); - } - - @Override - public void setPlayerSpawn(UUID player, Vec3 location, Vec2 rotation) { - if(!roomBounds.contains(location)) - return; - - playerSpawns.put(player, new RoomSpawn(location, rotation)); - } - - @Override - public Path getDataLocation(MinecraftServer server) { - return CMRoomDataLocations.SPAWN_DATA.apply(server); - } - - @Override - public Codec codec() { - return null; - } - - private record RoomSpawns(RoomSpawn defaultSpawn, Map playerSpawnsSnapshot) implements IRoomSpawns { - - @Override - public Optional forPlayer(UUID player) { - return Optional.ofNullable(playerSpawnsSnapshot.get(player)); - } - } -} +package dev.compactmods.machines.room.spawn; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import com.mojang.serialization.codecs.UnboundedMapCodec; +import dev.compactmods.machines.api.room.data.CMRoomDataLocations; +import dev.compactmods.machines.data.CMDataFile; +import dev.compactmods.machines.api.room.spatial.IRoomBoundaries; +import dev.compactmods.machines.api.room.spawn.IRoomSpawn; +import dev.compactmods.machines.api.room.spawn.IRoomSpawnManager; +import dev.compactmods.machines.api.room.spawn.IRoomSpawns; +import dev.compactmods.machines.data.CodecHolder; +import net.minecraft.core.UUIDUtil; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec2; +import net.minecraft.world.phys.Vec3; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.nio.file.Path; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +public class SpawnManager implements IRoomSpawnManager, CodecHolder, CMDataFile { + + private final Logger LOGS = LogManager.getLogger(); + + private static final UnboundedMapCodec PLAYER_SPAWNS_CODEC = Codec.unboundedMap(UUIDUtil.STRING_CODEC, RoomSpawn.CODEC); + private static final Codec CODEC = RecordCodecBuilder.create(inst -> inst.group( + Codec.STRING.fieldOf("roomCode").forGetter(x -> x.roomCode), + PLAYER_SPAWNS_CODEC.fieldOf("player_spawns").forGetter(x -> x.playerSpawns), + RoomSpawn.CODEC.fieldOf("default_spawn").forGetter(x -> x.defaultSpawn) + ).apply(inst, SpawnManager::new)); + + private final String roomCode; + private RoomSpawn defaultSpawn; + private final Map playerSpawns; + private AABB roomBounds; + + public SpawnManager(String roomCode) { + this(roomCode, Collections.emptyMap(), null); + this.defaultSpawn = null; + } + + public SpawnManager(String roomCode, IRoomBoundaries roomBounds) { + this(roomCode, Collections.emptyMap(), new RoomSpawn(roomBounds.defaultSpawn(), Vec2.ZERO)); + this.roomBounds = roomBounds.innerBounds(); + } + + public SpawnManager(String roomCode, Map playerSpawns, RoomSpawn defaultSpawn) { + this.roomCode = roomCode; + this.playerSpawns = new HashMap<>(playerSpawns); + this.defaultSpawn = defaultSpawn; + } + + @Override + public void resetPlayerSpawn(UUID player) { + playerSpawns.remove(player); + } + + @Override + public void setDefaultSpawn(Vec3 position, Vec2 rotation) { + defaultSpawn = new RoomSpawn(position, rotation); + } + + @Override + public IRoomSpawns spawns() { + final var ps = new HashMap(); + playerSpawns.forEach(ps::putIfAbsent); + return new RoomSpawns(defaultSpawn, ps); + } + + @Override + public void setPlayerSpawn(UUID player, Vec3 location, Vec2 rotation) { + if(!roomBounds.contains(location)) + return; + + playerSpawns.put(player, new RoomSpawn(location, rotation)); + } + + @Override + public Path getDataLocation(MinecraftServer server) { + return CMRoomDataLocations.PLAYER_SPAWNS.apply(server); + } + + @Override + public Codec codec() { + return null; + } + + private record RoomSpawns(RoomSpawn defaultSpawn, Map playerSpawnsSnapshot) implements IRoomSpawns { + + @Override + public Optional forPlayer(UUID player) { + return Optional.ofNullable(playerSpawnsSnapshot.get(player)); + } + } +} diff --git a/neoforge-main/src/main/java/dev/compactmods/machines/server/CompactMachinesServer.java b/neoforge-main/src/main/java/dev/compactmods/machines/server/CompactMachinesServer.java index 14e21808..355997c2 100644 --- a/neoforge-main/src/main/java/dev/compactmods/machines/server/CompactMachinesServer.java +++ b/neoforge-main/src/main/java/dev/compactmods/machines/server/CompactMachinesServer.java @@ -1,159 +1,155 @@ -package dev.compactmods.machines.server; - -import dev.compactmods.machines.LoggingUtil; -import dev.compactmods.machines.api.CompactMachines; -import dev.compactmods.machines.api.dimension.CompactDimension; -import dev.compactmods.machines.api.room.IRoomApi; -import dev.compactmods.machines.api.room.data.CMRoomDataLocations; -import dev.compactmods.machines.api.room.data.IRoomDataAttachmentAccessor; -import dev.compactmods.machines.api.room.registration.IRoomRegistrar; -import dev.compactmods.machines.api.room.history.IPlayerEntryPointHistoryManager; -import dev.compactmods.machines.api.room.history.IPlayerHistoryApi; -import dev.compactmods.machines.api.room.spatial.IRoomChunkManager; -import dev.compactmods.machines.api.room.spatial.IRoomChunks; -import dev.compactmods.machines.api.room.spawn.IRoomSpawnManager; -import dev.compactmods.machines.api.room.spawn.IRoomSpawnManagers; -import dev.compactmods.machines.data.DataFileUtil; -import dev.compactmods.machines.data.manager.CMKeyedDataFileManager; -import dev.compactmods.machines.data.manager.CMSingletonDataFileManager; -import dev.compactmods.machines.data.room.RoomDataAttachments; -import dev.compactmods.machines.player.PlayerEntryPointHistoryManager; -import dev.compactmods.machines.room.RoomRegistrar; -import dev.compactmods.machines.room.spatial.GraphChunkManager; -import dev.compactmods.machines.room.spawn.RoomSpawnManagers; -import net.minecraft.server.MinecraftServer; -import net.minecraft.world.level.Level; -import net.neoforged.fml.common.Mod; -import net.neoforged.neoforge.attachment.IAttachmentHolder; -import net.neoforged.neoforge.common.NeoForge; -import net.neoforged.neoforge.event.level.LevelEvent; -import net.neoforged.neoforge.event.server.ServerStartingEvent; -import net.neoforged.neoforge.event.server.ServerStoppingEvent; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Nullable; - -import java.util.Optional; -import java.util.function.Predicate; - -@Mod(value = CompactMachines.MOD_ID) -public class CompactMachinesServer { - - private static @Nullable MinecraftServer CURRENT_SERVER; - - private static RoomRegistrar ROOM_REGISTRAR; - private static PlayerEntryPointHistoryManager PLAYER_HISTORY; - - private static CMSingletonDataFileManager ROOM_REGISTRAR_DATA; - private static CMSingletonDataFileManager PLAYER_HISTORY_DATA; - private static CMKeyedDataFileManager ROOM_DATA_ATTACHMENTS; - - public CompactMachinesServer() { - NeoForge.EVENT_BUS.addListener(CompactMachinesServer::serverStarting); - NeoForge.EVENT_BUS.addListener(CompactMachinesServer::serverStopping); - NeoForge.EVENT_BUS.addListener(CompactMachinesServer::levelSaved); - } - - public static void serverStarting(final ServerStartingEvent evt) { - final var modLog = LoggingUtil.modLog(); - - modLog.debug("Setting up room API and data..."); - MinecraftServer server = evt.getServer(); - - - if (CompactMachinesServer.CURRENT_SERVER != null) { - save(); - } - - // Set up room data attachments for Neo - ROOM_DATA_ATTACHMENTS = new CMKeyedDataFileManager<>(server, RoomDataAttachments::new); - - PLAYER_HISTORY = new PlayerEntryPointHistoryManager(5); - PLAYER_HISTORY_DATA = new CMSingletonDataFileManager<>(server, "player_entrypoint_history", PLAYER_HISTORY); - - // Set up room API - var file = CMRoomDataLocations.REGISTRATION_DATA.apply(server) - .resolve("room_registrations.dat") - .toFile(); - - ROOM_REGISTRAR = file.exists() ? DataFileUtil.loadFileWithCodec(file, RoomRegistrar.CODEC) : new RoomRegistrar(); - ROOM_REGISTRAR_DATA = new CMSingletonDataFileManager<>(server, "room_registrations", ROOM_REGISTRAR); - - final IRoomSpawnManagers spawnManager = new RoomSpawnManagers(ROOM_REGISTRAR); - - final var gcm = new GraphChunkManager(); - ROOM_REGISTRAR.allRooms().forEach(inst -> gcm.calculateChunks(inst.code(), inst.boundaries())); - - setupInternalApiStuff(spawnManager, gcm); - - CURRENT_SERVER = server; - - modLog.debug("Completed setting up room API and data."); - } - - @SuppressWarnings("deprecation") - private static void setupInternalApiStuff(IRoomSpawnManagers spawnManager, GraphChunkManager gcm) { - CompactMachines.Internal.ROOM_API = new IRoomApi() { - @Override - public Predicate roomCodeValidator() { - return ROOM_REGISTRAR::isRegistered; - } - - @Override - public IRoomRegistrar registrar() { - return ROOM_REGISTRAR; - } - - @Override - public IRoomSpawnManager spawnManager(String roomCode) { - return spawnManager.get(roomCode); - } - - @Override - public IRoomChunkManager chunkManager() { - return gcm; - } - - @Override - public IRoomChunks chunks(String roomCode) { - return gcm.get(roomCode); - } - }; - - CompactMachines.Internal.PLAYER_HISTORY_API = new IPlayerHistoryApi() { - @Override - public IPlayerEntryPointHistoryManager entryPoints() { - return PLAYER_HISTORY; - } - }; - - CompactMachines.Internal.ROOM_DATA_ACCESSOR = new IRoomDataAttachmentAccessor() { - @Override - public Optional get(String roomCode) { - return ROOM_DATA_ATTACHMENTS.optionalData(roomCode); - } - - @Override - public IAttachmentHolder getOrCreate(String roomCode) { - return ROOM_DATA_ATTACHMENTS.data(roomCode); - } - }; - } - - public static void save() { - if (CURRENT_SERVER != null) { - ROOM_REGISTRAR_DATA.save(); - ROOM_DATA_ATTACHMENTS.save(); - PLAYER_HISTORY_DATA.save(); - } - } - - public static void serverStopping(final ServerStoppingEvent evt) { - save(); - } - - public static void levelSaved(final LevelEvent.Save level) { - if (level.getLevel() instanceof Level l && CompactDimension.isLevelCompact(l)) { - save(); - } - } -} +package dev.compactmods.machines.server; + +import dev.compactmods.machines.LoggingUtil; +import dev.compactmods.machines.api.CompactMachines; +import dev.compactmods.machines.api.dimension.CompactDimension; +import dev.compactmods.machines.api.room.IRoomApi; +import dev.compactmods.machines.api.room.data.CMRoomDataLocations; +import dev.compactmods.machines.api.room.data.IRoomDataAttachmentAccessor; +import dev.compactmods.machines.api.room.registration.IRoomRegistrar; +import dev.compactmods.machines.api.room.history.IPlayerEntryPointHistoryManager; +import dev.compactmods.machines.api.room.history.IPlayerHistoryApi; +import dev.compactmods.machines.api.room.spatial.IRoomChunkManager; +import dev.compactmods.machines.api.room.spatial.IRoomChunks; +import dev.compactmods.machines.api.room.spawn.IRoomSpawnManager; +import dev.compactmods.machines.api.room.spawn.IRoomSpawnManagers; +import dev.compactmods.machines.data.DataFileUtil; +import dev.compactmods.machines.data.manager.CMKeyedDataFileManager; +import dev.compactmods.machines.data.manager.CMSingletonDataFileManager; +import dev.compactmods.machines.data.room.RoomDataAttachments; +import dev.compactmods.machines.player.PlayerEntryPointHistoryManager; +import dev.compactmods.machines.room.RoomRegistrar; +import dev.compactmods.machines.room.spatial.GraphChunkManager; +import dev.compactmods.machines.room.spawn.RoomSpawnManagers; +import net.minecraft.server.MinecraftServer; +import net.minecraft.world.level.Level; +import net.neoforged.fml.common.Mod; +import net.neoforged.neoforge.attachment.IAttachmentHolder; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.level.LevelEvent; +import net.neoforged.neoforge.event.server.ServerStartingEvent; +import net.neoforged.neoforge.event.server.ServerStoppingEvent; +import org.jetbrains.annotations.Nullable; + +import java.util.Optional; +import java.util.function.Predicate; + +@Mod(value = CompactMachines.MOD_ID) +public class CompactMachinesServer { + + private static @Nullable MinecraftServer CURRENT_SERVER; + + private static RoomRegistrar ROOM_REGISTRAR; + private static PlayerEntryPointHistoryManager PLAYER_HISTORY; + + private static CMSingletonDataFileManager ROOM_REGISTRAR_DATA; + private static CMSingletonDataFileManager PLAYER_HISTORY_DATA; + private static CMKeyedDataFileManager ROOM_DATA_ATTACHMENTS; + + public CompactMachinesServer() { + NeoForge.EVENT_BUS.addListener(CompactMachinesServer::serverStarting); + NeoForge.EVENT_BUS.addListener(CompactMachinesServer::serverStopping); + NeoForge.EVENT_BUS.addListener(CompactMachinesServer::levelSaved); + } + + public static void serverStarting(final ServerStartingEvent evt) { + final var modLog = LoggingUtil.modLog(); + + modLog.debug("Setting up room API and data..."); + MinecraftServer server = evt.getServer(); + + + if (CompactMachinesServer.CURRENT_SERVER != null) { + save(); + } + + // Set up room data attachments for Neo + ROOM_DATA_ATTACHMENTS = new CMKeyedDataFileManager<>(server, RoomDataAttachments::new); + + PLAYER_HISTORY = new PlayerEntryPointHistoryManager(5); + PLAYER_HISTORY_DATA = new CMSingletonDataFileManager<>(server, "player_entrypoint_history", PLAYER_HISTORY); + + // Set up room API + var file = RoomRegistrar.getFile(server); + ROOM_REGISTRAR = file.exists() ? DataFileUtil.loadFileWithCodec(file, RoomRegistrar.CODEC) : new RoomRegistrar(); + ROOM_REGISTRAR_DATA = new CMSingletonDataFileManager<>(server, "room_registrations", ROOM_REGISTRAR); + + final IRoomSpawnManagers spawnManager = new RoomSpawnManagers(ROOM_REGISTRAR); + + final var gcm = new GraphChunkManager(); + ROOM_REGISTRAR.allRooms().forEach(inst -> gcm.calculateChunks(inst.code(), inst.boundaries())); + + setupInternalApiStuff(spawnManager, gcm); + + CURRENT_SERVER = server; + + modLog.debug("Completed setting up room API and data."); + } + + @SuppressWarnings("deprecation") + private static void setupInternalApiStuff(IRoomSpawnManagers spawnManager, GraphChunkManager gcm) { + CompactMachines.Internal.ROOM_API = new IRoomApi() { + @Override + public Predicate roomCodeValidator() { + return ROOM_REGISTRAR::isRegistered; + } + + @Override + public IRoomRegistrar registrar() { + return ROOM_REGISTRAR; + } + + @Override + public IRoomSpawnManager spawnManager(String roomCode) { + return spawnManager.get(roomCode); + } + + @Override + public IRoomChunkManager chunkManager() { + return gcm; + } + + @Override + public IRoomChunks chunks(String roomCode) { + return gcm.get(roomCode); + } + }; + + CompactMachines.Internal.PLAYER_HISTORY_API = new IPlayerHistoryApi() { + @Override + public IPlayerEntryPointHistoryManager entryPoints() { + return PLAYER_HISTORY; + } + }; + + CompactMachines.Internal.ROOM_DATA_ACCESSOR = new IRoomDataAttachmentAccessor() { + @Override + public Optional get(String roomCode) { + return ROOM_DATA_ATTACHMENTS.optionalData(roomCode); + } + + @Override + public IAttachmentHolder getOrCreate(String roomCode) { + return ROOM_DATA_ATTACHMENTS.data(roomCode); + } + }; + } + + public static void save() { + if (CURRENT_SERVER != null) { + ROOM_REGISTRAR_DATA.save(); + ROOM_DATA_ATTACHMENTS.save(); + PLAYER_HISTORY_DATA.save(); + } + } + + public static void serverStopping(final ServerStoppingEvent evt) { + save(); + } + + public static void levelSaved(final LevelEvent.Save level) { + if (level.getLevel() instanceof Level l && CompactDimension.isLevelCompact(l)) { + save(); + } + } +} diff --git a/neoforge-main/src/test/java/dev/compactmods/machines/test/gametest/worldgen/RoomGenerationTests.java b/neoforge-main/src/test/java/dev/compactmods/machines/test/gametest/worldgen/RoomGenerationTests.java index 0da156fd..b9dd9274 100644 --- a/neoforge-main/src/test/java/dev/compactmods/machines/test/gametest/worldgen/RoomGenerationTests.java +++ b/neoforge-main/src/test/java/dev/compactmods/machines/test/gametest/worldgen/RoomGenerationTests.java @@ -1,126 +1,126 @@ -package dev.compactmods.machines.test.gametest.worldgen; - -import dev.compactmods.machines.api.room.CompactRoomGenerator; -import dev.compactmods.machines.api.room.RoomTemplate; -import dev.compactmods.machines.api.CompactMachines; -import dev.compactmods.machines.api.util.BlockSpaceUtil; -import dev.compactmods.machines.test.gametest.core.CompactGameTestHelper; -import dev.compactmods.machines.test.gametest.core.EmptyTestSizes; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.gametest.framework.GameTest; -import net.minecraft.gametest.framework.GameTestGenerator; -import net.minecraft.gametest.framework.TestFunction; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.CommonColors; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.block.Rotation; -import net.minecraft.world.phys.AABB; -import net.neoforged.testframework.annotation.ForEachTest; -import net.neoforged.testframework.annotation.TestHolder; -import net.neoforged.testframework.gametest.EmptyTemplate; -import org.apache.logging.log4j.LogManager; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -@ForEachTest(groups = "room_generation") -public class RoomGenerationTests { - - @TestHolder - @GameTestGenerator - public static Collection roomTests() { - List funcs = new ArrayList<>(); - - makeAndAddRoomTemplateTest(funcs, CompactMachines.modRL("3_cubed"), new RoomTemplate(3, CommonColors.WHITE)); - makeAndAddRoomTemplateTest(funcs, CompactMachines.modRL("5_cubed"), new RoomTemplate(5, CommonColors.WHITE)); - makeAndAddRoomTemplateTest(funcs, CompactMachines.modRL("7_cubed"), new RoomTemplate(7, CommonColors.WHITE)); - makeAndAddRoomTemplateTest(funcs, CompactMachines.modRL("9_cubed"), new RoomTemplate(9, CommonColors.WHITE)); - makeAndAddRoomTemplateTest(funcs, CompactMachines.modRL("11_cubed"), new RoomTemplate(11, CommonColors.WHITE)); - makeAndAddRoomTemplateTest(funcs, CompactMachines.modRL("13_cubed"), new RoomTemplate(13, CommonColors.WHITE)); - - return funcs; - } - - private static void makeAndAddRoomTemplateTest(List funcs, ResourceLocation id, RoomTemplate template) { - funcs.add(new TestFunction( - "room_generation", - "builtin_roomgen_" + id.getPath(), - CompactMachines.modRL("empty_15_cubed").toString(), - Rotation.NONE, - 200, - 0, - true, - testHelper -> templateTest(new CompactGameTestHelper(testHelper.testInfo), template) - )); - } - - private static void templateTest(CompactGameTestHelper testHelper, RoomTemplate template) { - final AABB localBounds = testHelper.localBounds(); - final AABB worldBounds = testHelper.getBounds(); - final BlockPos testCenter = BlockPos.containing(localBounds.getCenter()); - - CompactRoomGenerator.generateRoom(testHelper.getLevel(), template.getBoundariesCenteredAt(worldBounds.getCenter())); - - testHelper.setBlock(testCenter, Blocks.RED_STAINED_GLASS); - testHelper.succeed(); - } - - @TestHolder - @GameTest - @EmptyTemplate(EmptyTestSizes.FIFTEEN_CUBED) - public static void checkOffsetsNormalTest(final CompactGameTestHelper testHelper) { - final var logs = LogManager.getLogger(); - - AABB localBounds = testHelper.localBounds(); - - var center = BlockPos.containing(localBounds.getCenter()); - testHelper.setBlock(center, Blocks.GOLD_BLOCK.defaultBlockState()); - - for(var dir : Direction.values()) { - var ob = BlockSpaceUtil.centerWallBlockPos(localBounds, dir); - testHelper.setBlock(ob, Blocks.ORANGE_STAINED_GLASS); - } - - BlockSpaceUtil.forAllCorners(localBounds).forEach(pos -> { - testHelper.setBlock(pos, Blocks.BLACK_STAINED_GLASS); - }); - - testHelper.succeed(); - } - - @TestHolder - @GameTest - @EmptyTemplate(EmptyTestSizes.FIFTEEN_CUBED) - public static void checkRoomGeneratorNormal(final CompactGameTestHelper testHelper) { - - AABB localBounds = testHelper.localBounds(); - - var center = BlockPos.containing(localBounds.getCenter()); - testHelper.setBlock(center, Blocks.GOLD_BLOCK.defaultBlockState()); - - BlockSpaceUtil.forAllCorners(localBounds.deflate(5)) - .forEach(bp -> testHelper.setBlock(bp, Blocks.IRON_BLOCK)); - - testHelper.succeed(); - } - - @TestHolder - @GameTest - @EmptyTemplate(EmptyTestSizes.FIFTEEN_CUBED) - public static void checkRoomGeneratorWeirdShape(final CompactGameTestHelper testHelper) { - - AABB localBounds = testHelper.localBounds(); - - final var roomDims = AABB.ofSize(localBounds.getCenter(), 5, 5, 9) - .move(testHelper.absolutePos(BlockPos.ZERO)); - - CompactRoomGenerator.generateRoom(testHelper.getLevel(), roomDims); - - var center = BlockPos.containing(localBounds.getCenter()); - testHelper.setBlock(center, Blocks.GOLD_BLOCK.defaultBlockState()); - - testHelper.succeed(); - } -} +package dev.compactmods.machines.test.gametest.worldgen; + +import dev.compactmods.machines.api.room.CompactRoomGenerator; +import dev.compactmods.machines.api.room.template.RoomTemplate; +import dev.compactmods.machines.api.CompactMachines; +import dev.compactmods.machines.api.util.BlockSpaceUtil; +import dev.compactmods.machines.test.gametest.core.CompactGameTestHelper; +import dev.compactmods.machines.test.gametest.core.EmptyTestSizes; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestGenerator; +import net.minecraft.gametest.framework.TestFunction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.CommonColors; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.phys.AABB; +import net.neoforged.testframework.annotation.ForEachTest; +import net.neoforged.testframework.annotation.TestHolder; +import net.neoforged.testframework.gametest.EmptyTemplate; +import org.apache.logging.log4j.LogManager; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +@ForEachTest(groups = "room_generation") +public class RoomGenerationTests { + + @TestHolder + @GameTestGenerator + public static Collection roomTests() { + List funcs = new ArrayList<>(); + + makeAndAddRoomTemplateTest(funcs, CompactMachines.modRL("3_cubed"), new RoomTemplate(3, CommonColors.WHITE)); + makeAndAddRoomTemplateTest(funcs, CompactMachines.modRL("5_cubed"), new RoomTemplate(5, CommonColors.WHITE)); + makeAndAddRoomTemplateTest(funcs, CompactMachines.modRL("7_cubed"), new RoomTemplate(7, CommonColors.WHITE)); + makeAndAddRoomTemplateTest(funcs, CompactMachines.modRL("9_cubed"), new RoomTemplate(9, CommonColors.WHITE)); + makeAndAddRoomTemplateTest(funcs, CompactMachines.modRL("11_cubed"), new RoomTemplate(11, CommonColors.WHITE)); + makeAndAddRoomTemplateTest(funcs, CompactMachines.modRL("13_cubed"), new RoomTemplate(13, CommonColors.WHITE)); + + return funcs; + } + + private static void makeAndAddRoomTemplateTest(List funcs, ResourceLocation id, RoomTemplate template) { + funcs.add(new TestFunction( + "room_generation", + "builtin_roomgen_" + id.getPath(), + CompactMachines.modRL("empty_15_cubed").toString(), + Rotation.NONE, + 200, + 0, + true, + testHelper -> templateTest(new CompactGameTestHelper(testHelper.testInfo), template) + )); + } + + private static void templateTest(CompactGameTestHelper testHelper, RoomTemplate template) { + final AABB localBounds = testHelper.localBounds(); + final AABB worldBounds = testHelper.getBounds(); + final BlockPos testCenter = BlockPos.containing(localBounds.getCenter()); + + CompactRoomGenerator.generateRoom(testHelper.getLevel(), template.getBoundariesCenteredAt(worldBounds.getCenter())); + + testHelper.setBlock(testCenter, Blocks.RED_STAINED_GLASS); + testHelper.succeed(); + } + + @TestHolder + @GameTest + @EmptyTemplate(EmptyTestSizes.FIFTEEN_CUBED) + public static void checkOffsetsNormalTest(final CompactGameTestHelper testHelper) { + final var logs = LogManager.getLogger(); + + AABB localBounds = testHelper.localBounds(); + + var center = BlockPos.containing(localBounds.getCenter()); + testHelper.setBlock(center, Blocks.GOLD_BLOCK.defaultBlockState()); + + for(var dir : Direction.values()) { + var ob = BlockSpaceUtil.centerWallBlockPos(localBounds, dir); + testHelper.setBlock(ob, Blocks.ORANGE_STAINED_GLASS); + } + + BlockSpaceUtil.forAllCorners(localBounds).forEach(pos -> { + testHelper.setBlock(pos, Blocks.BLACK_STAINED_GLASS); + }); + + testHelper.succeed(); + } + + @TestHolder + @GameTest + @EmptyTemplate(EmptyTestSizes.FIFTEEN_CUBED) + public static void checkRoomGeneratorNormal(final CompactGameTestHelper testHelper) { + + AABB localBounds = testHelper.localBounds(); + + var center = BlockPos.containing(localBounds.getCenter()); + testHelper.setBlock(center, Blocks.GOLD_BLOCK.defaultBlockState()); + + BlockSpaceUtil.forAllCorners(localBounds.deflate(5)) + .forEach(bp -> testHelper.setBlock(bp, Blocks.IRON_BLOCK)); + + testHelper.succeed(); + } + + @TestHolder + @GameTest + @EmptyTemplate(EmptyTestSizes.FIFTEEN_CUBED) + public static void checkRoomGeneratorWeirdShape(final CompactGameTestHelper testHelper) { + + AABB localBounds = testHelper.localBounds(); + + final var roomDims = AABB.ofSize(localBounds.getCenter(), 5, 5, 9) + .move(testHelper.absolutePos(BlockPos.ZERO)); + + CompactRoomGenerator.generateRoom(testHelper.getLevel(), roomDims); + + var center = BlockPos.containing(localBounds.getCenter()); + testHelper.setBlock(center, Blocks.GOLD_BLOCK.defaultBlockState()); + + testHelper.succeed(); + } +} diff --git a/neoforge-main/testmods/buildinggadgets2-1.1.0.jar b/neoforge-main/testmods/buildinggadgets2-1.1.0.jar deleted file mode 100644 index f124185f..00000000 Binary files a/neoforge-main/testmods/buildinggadgets2-1.1.0.jar and /dev/null differ diff --git a/neoforge-main/testmods/jei-1.20.4-neoforge-17.3.0.49.jar b/neoforge-main/testmods/jei-1.20.4-neoforge-17.3.0.49.jar deleted file mode 100644 index 806f73bb..00000000 Binary files a/neoforge-main/testmods/jei-1.20.4-neoforge-17.3.0.49.jar and /dev/null differ diff --git a/neoforge-main/testmods/laserio-1.7.2.jar b/neoforge-main/testmods/laserio-1.7.2.jar deleted file mode 100644 index 3e3a8010..00000000 Binary files a/neoforge-main/testmods/laserio-1.7.2.jar and /dev/null differ diff --git a/neoforge-main/testmods/mininggadgets-1.16.0.jar b/neoforge-main/testmods/mininggadgets-1.16.0.jar deleted file mode 100644 index 594ffd2c..00000000 Binary files a/neoforge-main/testmods/mininggadgets-1.16.0.jar and /dev/null differ diff --git a/settings.gradle.kts b/settings.gradle.kts index faf6785e..c7b33b56 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -82,5 +82,5 @@ plugins { include(":core-api") include(":neoforge-main") -// include(":neoforge-datagen") +include(":neoforge-datagen")