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 no longer automatically downloads sources/javadoc jars for dependencies, so we need to explicitly enable the behavior.
idea { idea {
module { module {
downloadSources = false downloadSources = true
downloadJavadoc = true downloadJavadoc = true
} }
} }

View file

@ -1,80 +1,23 @@
package dev.exhq.ajarc; package dev.exhq.ajarc;
import dev.exhq.ajarc.config.Config; import dev.exhq.ajarc.config.Config;
import dev.exhq.ajarc.items.Register; import dev.exhq.ajarc.register.Register;
import org.slf4j.Logger; import org.slf4j.Logger;
import com.mojang.logging.LogUtils; 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.IEventBus;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.ModContainer; import net.neoforged.fml.ModContainer;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.common.Mod; import net.neoforged.fml.common.Mod;
import net.neoforged.fml.config.ModConfig; 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) @Mod(Ajar.MODID)
public class Ajar public class Ajar {
{ public static final String MODID = "ajarc";
public static final String MODID = "ajarc"; public static final Logger LOGGER = LogUtils.getLogger();
private static final Logger LOGGER = LogUtils.getLogger();
public Ajar(IEventBus modEventBus, ModContainer modContainer)
{
modEventBus.addListener(this::commonSetup);
public Ajar(IEventBus modEventBus, ModContainer modContainer) {
Register.registerAll(modEventBus); Register.registerAll(modEventBus);
modContainer.registerConfig(ModConfig.Type.COMMON, Config.SPEC); 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());
}
}
} }

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. // 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 // Demonstrates how to use Neo's config APIs
@EventBusSubscriber(modid = Ajar.MODID, bus = EventBusSubscriber.Bus.MOD) @EventBusSubscriber(modid = Ajar.MODID, bus = EventBusSubscriber.Bus.MOD)
public class Config public class Config {
{ private static final ModConfigSpec.Builder BUILDER = new ModConfigSpec.Builder();
private static final ModConfigSpec.Builder BUILDER = new ModConfigSpec.Builder();
private static final ModConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER private static final ModConfigSpec.BooleanValue LOG_DIRT_BLOCK = BUILDER
.comment("Whether to log the dirt block on common setup") .comment("Whether to log the dirt block on common setup")
.define("logDirtBlock", true); .define("logDirtBlock", true);
private static final ModConfigSpec.IntValue MAGIC_NUMBER = BUILDER private static final ModConfigSpec.IntValue MAGIC_NUMBER = BUILDER
.comment("A magic number") .comment("A magic number")
.defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE); .defineInRange("magicNumber", 42, 0, Integer.MAX_VALUE);
public static final ModConfigSpec.ConfigValue<String> MAGIC_NUMBER_INTRODUCTION = BUILDER public static final ModConfigSpec.ConfigValue<String> MAGIC_NUMBER_INTRODUCTION = BUILDER
.comment("What you want the introduction message to be for the magic number") .comment("What you want the introduction message to be for the magic number")
.define("magicNumberIntroduction", "The magic number is... "); .define("magicNumberIntroduction", "The magic number is... ");
// a list of strings that are treated as resource locations for items // a list of strings that are treated as resource locations for items
private static final ModConfigSpec.ConfigValue<List<? extends String>> ITEM_STRINGS = BUILDER private static final ModConfigSpec.ConfigValue<List<? extends String>> ITEM_STRINGS = BUILDER
.comment("A list of items to log on common setup.") .comment("A list of items to log on common setup.")
.defineListAllowEmpty("items", List.of("minecraft:iron_ingot"), Config::validateItemName); .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 boolean logDirtBlock;
public static int magicNumber; public static int magicNumber;
public static String magicNumberIntroduction; public static String magicNumberIntroduction;
public static Set<Item> items; public static Set<Item> items;
private static boolean validateItemName(final Object obj) private static boolean validateItemName(final Object obj) {
{ return obj instanceof String itemName && BuiltInRegistries.ITEM.containsKey(ResourceLocation.parse(itemName));
return obj instanceof String itemName && BuiltInRegistries.ITEM.containsKey(ResourceLocation.parse(itemName)); }
}
@SubscribeEvent @SubscribeEvent
static void onLoad(final ModConfigEvent event) static void onLoad(final ModConfigEvent event) {
{ logDirtBlock = LOG_DIRT_BLOCK.get();
logDirtBlock = LOG_DIRT_BLOCK.get(); magicNumber = MAGIC_NUMBER.get();
magicNumber = MAGIC_NUMBER.get(); magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get();
magicNumberIntroduction = MAGIC_NUMBER_INTRODUCTION.get();
// convert the list of strings into a set of items // convert the list of strings into a set of items
items = ITEM_STRINGS.get().stream() items = ITEM_STRINGS.get().stream()
.map(itemName -> BuiltInRegistries.ITEM.get(ResourceLocation.parse(itemName))) .map(itemName -> BuiltInRegistries.ITEM.get(ResourceLocation.parse(itemName)))
.collect(Collectors.toSet()); .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; 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.core.registries.Registries;
import net.minecraft.network.chat.Component; import net.minecraft.network.chat.Component;
import net.minecraft.world.food.FoodProperties; import net.minecraft.world.food.FoodProperties;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.CreativeModeTabs;
import net.minecraft.world.item.Item; 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.block.state.BlockBehaviour;
import net.minecraft.world.level.material.MapColor; import net.minecraft.world.level.material.MapColor;
import net.neoforged.bus.api.IEventBus; import net.neoforged.bus.api.IEventBus;
@ -20,6 +21,7 @@ import net.neoforged.neoforge.registries.DeferredRegister;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier;
import static dev.exhq.ajarc.Ajar.MODID; 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.Items ITEMS = registry(DeferredRegister.createItems(MODID));
public static final DeferredRegister<CreativeModeTab> CREATIVE_MODE_TABS = public static final DeferredRegister<CreativeModeTab> CREATIVE_MODE_TABS =
registry(DeferredRegister.create(Registries.CREATIVE_MODE_TAB, MODID)); 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>
/// <editor-fold desc="Registration helpers" defaultstate="collapsed"> /// <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)); "example_block", NeaBlock::new, BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_GREEN));
public static final DeferredBlock<NeaBlock> OTHER_COMPUTER_BLOCK = block( public static final DeferredBlock<NeaBlock> OTHER_COMPUTER_BLOCK = block(
"other_block", NeaBlock::new, BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_RED)); "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>
/// <editor-fold desc="Items"> /// <editor-fold desc="Items">