File system

This commit is contained in:
Linnea Gräf 2024-07-16 02:25:20 +02:00
parent 1c6023be65
commit d7ade1a759
No known key found for this signature in database
GPG key ID: AA563E93EB628D91
12 changed files with 258 additions and 108 deletions

View file

@ -167,7 +167,7 @@ tasks.withType(JavaCompile).configureEach {
// IDEA no longer automatically downloads sources/javadoc jars for dependencies, so we need to explicitly enable the behavior.
idea {
module {
downloadSources = false
downloadSources = true
downloadJavadoc = true
}
}

View file

@ -1,80 +1,23 @@
package dev.exhq.ajarc;
import dev.exhq.ajarc.config.Config;
import dev.exhq.ajarc.items.Register;
import dev.exhq.ajarc.register.Register;
import org.slf4j.Logger;
import com.mojang.logging.LogUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.CreativeModeTabs;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.material.MapColor;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.ModContainer;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.common.Mod;
import net.neoforged.fml.config.ModConfig;
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent;
import net.neoforged.neoforge.event.server.ServerStartingEvent;
import net.neoforged.neoforge.registries.DeferredBlock;
import net.neoforged.neoforge.registries.DeferredHolder;
import net.neoforged.neoforge.registries.DeferredItem;
import net.neoforged.neoforge.registries.DeferredRegister;
// The value here should match an entry in the META-INF/neoforge.mods.toml file
@Mod(Ajar.MODID)
public class Ajar
{
public static final String MODID = "ajarc";
private static final Logger LOGGER = LogUtils.getLogger();
public Ajar(IEventBus modEventBus, ModContainer modContainer)
{
modEventBus.addListener(this::commonSetup);
public class Ajar {
public static final String MODID = "ajarc";
public static final Logger LOGGER = LogUtils.getLogger();
public Ajar(IEventBus modEventBus, ModContainer modContainer) {
Register.registerAll(modEventBus);
modContainer.registerConfig(ModConfig.Type.COMMON, Config.SPEC);
}
private void commonSetup(final FMLCommonSetupEvent event)
{
// Some common setup code
LOGGER.info("HELLO FROM COMMON SETUP");
if (Config.logDirtBlock)
LOGGER.info("DIRT BLOCK >> {}", BuiltInRegistries.BLOCK.getKey(Blocks.DIRT));
LOGGER.info(Config.magicNumberIntroduction + Config.magicNumber);
Config.items.forEach((item) -> LOGGER.info("ITEM >> {}", item.toString()));
}
@EventBusSubscriber(modid = MODID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT)
public static class ClientModEvents
{
@SubscribeEvent
public static void onClientSetup(FMLClientSetupEvent event)
{
// Some client setup code
LOGGER.info("HELLO FROM CLIENT SETUP");
LOGGER.info("MINECRAFT NAME >> {}", Minecraft.getInstance().getUser().getName());
}
}
modContainer.registerConfig(ModConfig.Type.COMMON, Config.SPEC);
}
}

View file

@ -0,0 +1,27 @@
package dev.exhq.ajarc.computer;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.HashMap;
import java.util.Map;
public record AjarDirectory(
Map<String, AjarFile> listing
) implements AjarFile {
public static final MapCodec<AjarDirectory> CODEC = RecordCodecBuilder.mapCodec(
builder ->
builder.group(Codec.unboundedMap(Codec.STRING, Codec.lazyInitialized(() -> AjarFile.CODEC))
.fieldOf("listing").forGetter(AjarDirectory::listing))
.apply(builder, AjarDirectory::new));
public static AjarDirectory ofEmpty() {
return new AjarDirectory(new HashMap<>());
}
@Override
public Type getType() {
return Type.DIRECTORY;
}
}

View file

@ -0,0 +1,30 @@
package dev.exhq.ajarc.computer;
import com.mojang.serialization.Codec;
import net.minecraft.util.StringRepresentable;
import org.jetbrains.annotations.NotNull;
public sealed interface AjarFile permits AjarDirectory, AjarRegularFile, AjarSymlinkFile {
Codec<AjarFile> CODEC = Type.CODEC.dispatch(
"type",
AjarFile::getType,
type -> switch (type) {
case SYMLINK -> AjarSymlinkFile.CODEC;
case DIRECTORY -> AjarDirectory.CODEC;
case REGULAR_FILE -> AjarRegularFile.CODEC;
});
Type getType();
enum Type implements StringRepresentable {
SYMLINK,
DIRECTORY,
REGULAR_FILE;
public static final Codec<Type> CODEC = StringRepresentable.fromEnum(Type::values);
@Override
public @NotNull String getSerializedName() {
return name();
}
}
}

View file

@ -0,0 +1,18 @@
package dev.exhq.ajarc.computer;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
public record AjarFileSystem(
AjarDirectory root
) {
public static final MapCodec<AjarFileSystem> CODEC =
RecordCodecBuilder.mapCodec(
builder ->
builder.group(AjarDirectory.CODEC.fieldOf("root").forGetter(AjarFileSystem::root))
.apply(builder, AjarFileSystem::new));
public static AjarFileSystem ofBlank() {
return new AjarFileSystem(AjarDirectory.ofEmpty());
}
}

View file

@ -0,0 +1,35 @@
package dev.exhq.ajarc.computer;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
public record AjarRegularFile(
byte[] content
) implements AjarFile {
public static final MapCodec<AjarRegularFile> CODEC = RecordCodecBuilder.mapCodec(
builder -> builder.group(Codec.BYTE_BUFFER.xmap(AjarRegularFile::bufferToArray, ByteBuffer::wrap)
.fieldOf("content").forGetter(AjarRegularFile::content))
.apply(builder, AjarRegularFile::new)
);
private static byte[] bufferToArray(ByteBuffer buffer) {
var remaining = buffer.remaining();
var array = new byte[remaining];
buffer.get(array);
return array;
}
public String getTextContent() {
return new String(content, StandardCharsets.UTF_8);
}
@Override
public Type getType() {
return Type.REGULAR_FILE;
}
}

View file

@ -0,0 +1,19 @@
package dev.exhq.ajarc.computer;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
public record AjarSymlinkFile(
String target
) implements AjarFile {
public static final MapCodec<AjarSymlinkFile> CODEC =
RecordCodecBuilder.mapCodec(builder -> builder
.group(Codec.STRING.fieldOf("target").forGetter(AjarSymlinkFile::target))
.apply(builder, AjarSymlinkFile::new));
@Override
public Type getType() {
return Type.SYMLINK;
}
}

View file

@ -0,0 +1,35 @@
package dev.exhq.ajarc.computer;
import dev.exhq.ajarc.register.NeaBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
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 org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class ComputerBlock extends NeaBlock implements EntityBlock {
public ComputerBlock(Properties properties) {
super(properties);
}
@Nullable
@Override
public BlockEntity newBlockEntity(@NotNull BlockPos pPos, @NotNull BlockState pState) {
return new ComputerBlockEntity(pPos, pState);
}
@Override
protected @NotNull InteractionResult useWithoutItem(
@NotNull BlockState pState, @NotNull Level pLevel,
@NotNull BlockPos pPos, @NotNull Player pPlayer,
@NotNull BlockHitResult pHitResult) {
if (pLevel.isClientSide()) return InteractionResult.SUCCESS;
return InteractionResult.CONSUME;
}
}

View file

@ -0,0 +1,38 @@
package dev.exhq.ajarc.computer;
import dev.exhq.ajarc.Ajar;
import dev.exhq.ajarc.register.Register;
import net.minecraft.core.BlockPos;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.NotNull;
public class ComputerBlockEntity extends BlockEntity {
public ComputerBlockEntity(BlockPos pPos, BlockState pBlockState) {
super(Register.COMPUTER_BLOCK_ENTITY.get(), pPos, pBlockState);
}
private AjarFileSystem fileSystem = AjarFileSystem.ofBlank();
@Override
protected void loadAdditional(@NotNull CompoundTag pTag, @NotNull HolderLookup.Provider pRegistries) {
super.loadAdditional(pTag, pRegistries);
var compound = pTag.getCompound("fileSystem");
fileSystem = AjarFileSystem.CODEC.codec()
.parse(NbtOps.INSTANCE, compound)
.resultOrPartial(Ajar.LOGGER::error)
.orElseGet(AjarFileSystem::ofBlank);
}
@Override
protected void saveAdditional(@NotNull CompoundTag pTag, HolderLookup.@NotNull Provider pRegistries) {
super.saveAdditional(pTag, pRegistries);
pTag.put("fileSystem",
AjarFileSystem.CODEC
.codec().encodeStart(NbtOps.INSTANCE, fileSystem)
.getOrThrow());
}
}

View file

@ -16,49 +16,46 @@ import net.neoforged.neoforge.common.ModConfigSpec;
// An example config class. This is not required, but it's a good idea to have one to keep your config organized.
// Demonstrates how to use Neo's config APIs
@EventBusSubscriber(modid = Ajar.MODID, bus = EventBusSubscriber.Bus.MOD)
public class Config
{
private static final ModConfigSpec.Builder BUILDER = new ModConfigSpec.Builder();
public class Config {
private static final ModConfigSpec.Builder BUILDER = new ModConfigSpec.Builder();
private static final ModConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER
.comment("Whether to log the dirt block on common setup")
.define("logDirtBlock", true);
private static final ModConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER
.comment("Whether to log the dirt block on common setup")
.define("logDirtBlock", true);
private static final ModConfigSpec.IntValue MAGIC_NUMBER = BUILDER
.comment("A magic number")
.defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE);
private static final ModConfigSpec.IntValue MAGIC_NUMBER = BUILDER
.comment("A magic number")
.defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE);
public static final ModConfigSpec.ConfigValue<String> MAGIC_NUMBER_INTRODUCTION = BUILDER
.comment("What you want the introduction message to be for the magic number")
.define("magicNumberIntroduction", "The magic number is... ");
public static final ModConfigSpec.ConfigValue<String> MAGIC_NUMBER_INTRODUCTION = BUILDER
.comment("What you want the introduction message to be for the magic number")
.define("magicNumberIntroduction", "The magic number is... ");
// a list of strings that are treated as resource locations for items
private static final ModConfigSpec.ConfigValue<List<? extends String>> ITEM_STRINGS = BUILDER
.comment("A list of items to log on common setup.")
.defineListAllowEmpty("items", List.of("minecraft:iron_ingot"), Config::validateItemName);
// a list of strings that are treated as resource locations for items
private static final ModConfigSpec.ConfigValue<List<? extends String>> ITEM_STRINGS = BUILDER
.comment("A list of items to log on common setup.")
.defineListAllowEmpty("items", List.of("minecraft:iron_ingot"), Config::validateItemName);
public static final ModConfigSpec SPEC = BUILDER.build();
public static final ModConfigSpec SPEC = BUILDER.build();
public static boolean logDirtBlock;
public static int magicNumber;
public static String magicNumberIntroduction;
public static Set<Item> items;
public static boolean logDirtBlock;
public static int magicNumber;
public static String magicNumberIntroduction;
public static Set<Item> items;
private static boolean validateItemName(final Object obj)
{
return obj instanceof String itemName && BuiltInRegistries.ITEM.containsKey(ResourceLocation.parse(itemName));
}
private static boolean validateItemName(final Object obj) {
return obj instanceof String itemName && BuiltInRegistries.ITEM.containsKey(ResourceLocation.parse(itemName));
}
@SubscribeEvent
static void onLoad(final ModConfigEvent event)
{
logDirtBlock = LOG_DIRT_BLOCK.get();
magicNumber = MAGIC_NUMBER.get();
magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get();
@SubscribeEvent
static void onLoad(final ModConfigEvent event) {
logDirtBlock = LOG_DIRT_BLOCK.get();
magicNumber = MAGIC_NUMBER.get();
magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get();
// convert the list of strings into a set of items
items = ITEM_STRINGS.get().stream()
.map(itemName -> BuiltInRegistries.ITEM.get(ResourceLocation.parse(itemName)))
.collect(Collectors.toSet());
}
// convert the list of strings into a set of items
items = ITEM_STRINGS.get().stream()
.map(itemName -> BuiltInRegistries.ITEM.get(ResourceLocation.parse(itemName)))
.collect(Collectors.toSet());
}
}

View file

@ -1,4 +1,4 @@
package dev.exhq.ajarc.items.blocks;
package dev.exhq.ajarc.register;
import net.minecraft.world.level.block.Block;

View file

@ -1,14 +1,15 @@
package dev.exhq.ajarc.items;
package dev.exhq.ajarc.register;
import dev.exhq.ajarc.items.blocks.NeaBlock;
import dev.exhq.ajarc.computer.ComputerBlock;
import dev.exhq.ajarc.computer.ComputerBlockEntity;
import net.minecraft.core.Holder;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.CreativeModeTabs;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.material.MapColor;
import net.neoforged.bus.api.IEventBus;
@ -20,6 +21,7 @@ import net.neoforged.neoforge.registries.DeferredRegister;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
import static dev.exhq.ajarc.Ajar.MODID;
@ -40,7 +42,8 @@ public class Register {
public static final DeferredRegister.Items ITEMS = registry(DeferredRegister.createItems(MODID));
public static final DeferredRegister<CreativeModeTab> CREATIVE_MODE_TABS =
registry(DeferredRegister.create(Registries.CREATIVE_MODE_TAB, MODID));
public static final DeferredRegister<BlockEntityType<?>> BLOCK_ENTITIES =
registry(DeferredRegister.create(Registries.BLOCK_ENTITY_TYPE, MODID));
/// </editor-fold>
/// <editor-fold desc="Registration helpers" defaultstate="collapsed">
@ -58,7 +61,12 @@ public class Register {
"example_block", NeaBlock::new, BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_GREEN));
public static final DeferredBlock<NeaBlock> OTHER_COMPUTER_BLOCK = block(
"other_block", NeaBlock::new, BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_RED));
public static final DeferredBlock<ComputerBlock> COMPUTER_BLOCK = block("computer", ComputerBlock::new, BlockBehaviour.Properties.of());
public static final Supplier<BlockEntityType<ComputerBlockEntity>> COMPUTER_BLOCK_ENTITY =
BLOCK_ENTITIES
.register("computer",
() -> BlockEntityType.Builder.of(ComputerBlockEntity::new, COMPUTER_BLOCK.get())
.build(null));
/// </editor-fold>
/// <editor-fold desc="Items">