framework for akashic libraries
This commit is contained in:
parent
767dd9983d
commit
433391c8d0
10 changed files with 486 additions and 7 deletions
|
@ -12,6 +12,7 @@ import net.minecraft.network.chat.Component
|
|||
import net.minecraft.network.chat.Style
|
||||
import net.minecraft.network.chat.TextComponent
|
||||
import net.minecraft.network.chat.TranslatableComponent
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.phys.Vec3
|
||||
|
||||
|
@ -109,9 +110,8 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
throw MishapInvalidSpellDatumType(payload)
|
||||
}
|
||||
|
||||
|
||||
@JvmStatic
|
||||
fun DeserializeFromNBT(nbt: CompoundTag, ctx: CastingContext): SpellDatum<*> {
|
||||
fun DeserializeFromNBT(nbt: CompoundTag, world: ServerLevel): SpellDatum<*> {
|
||||
val keys = nbt.allKeys
|
||||
if (keys.size != 1)
|
||||
throw IllegalArgumentException("Expected exactly one kv pair: $nbt")
|
||||
|
@ -120,7 +120,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
TAG_ENTITY -> {
|
||||
val subtag = nbt.getCompound(key)
|
||||
val uuid = subtag.getUUID(TAG_ENTITY_UUID) // and throw away name
|
||||
val entity = ctx.world.getEntity(uuid)
|
||||
val entity = world.getEntity(uuid)
|
||||
// If the entity died or something return Unit
|
||||
SpellDatum(if (entity == null || !entity.isAlive) Widget.NULL else entity)
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
val out = ArrayList<SpellDatum<*>>(arr.size)
|
||||
for (subtag in arr) {
|
||||
// this is safe because otherwise we wouldn't have been able to get the list before
|
||||
out.add(DeserializeFromNBT(subtag as CompoundTag, ctx))
|
||||
out.add(DeserializeFromNBT(subtag as CompoundTag, world))
|
||||
}
|
||||
SpellDatum(out)
|
||||
}
|
||||
|
@ -145,6 +145,16 @@ class SpellDatum<T : Any> private constructor(val payload: T) {
|
|||
}
|
||||
}
|
||||
|
||||
@Deprecated(
|
||||
"use the [Level] overload", ReplaceWith(
|
||||
"DeserializeFromNBT(nbt, ctx.world)",
|
||||
"at.petrak.hexcasting.api.spell.SpellDatum.Companion.DeserializeFromNBT"
|
||||
)
|
||||
)
|
||||
@JvmStatic
|
||||
fun DeserializeFromNBT(nbt: CompoundTag, ctx: CastingContext): SpellDatum<*> =
|
||||
DeserializeFromNBT(nbt, ctx.world)
|
||||
|
||||
@JvmStatic
|
||||
fun DisplayFromTag(nbt: CompoundTag): Component {
|
||||
val keys = nbt.allKeys
|
||||
|
|
|
@ -8,6 +8,7 @@ import at.petrak.hexcasting.api.spell.SpellDatum;
|
|||
import at.petrak.hexcasting.client.entity.WallScrollRenderer;
|
||||
import at.petrak.hexcasting.client.particles.ConjureParticle;
|
||||
import at.petrak.hexcasting.common.blocks.HexBlocks;
|
||||
import at.petrak.hexcasting.common.blocks.akashic.BlockEntityAkashicBookshelf;
|
||||
import at.petrak.hexcasting.common.blocks.circles.BlockEntitySlate;
|
||||
import at.petrak.hexcasting.common.entities.HexEntities;
|
||||
import at.petrak.hexcasting.common.items.HexItems;
|
||||
|
@ -141,6 +142,8 @@ public class RegisterClientStuff {
|
|||
@SubscribeEvent
|
||||
public static void registerRenderers(EntityRenderersEvent.RegisterRenderers evt) {
|
||||
evt.registerBlockEntityRenderer(HexBlocks.SLATE_TILE.get(), BlockEntitySlate.Renderer::new);
|
||||
evt.registerBlockEntityRenderer(HexBlocks.AKASHIC_BOOKSHELF_TILE.get(),
|
||||
BlockEntityAkashicBookshelf.Renderer::new);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package at.petrak.hexcasting.common.blocks;
|
||||
|
||||
import at.petrak.hexcasting.HexMod;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
public class HexBlockTags {
|
||||
public static final TagKey<Block> AKASHIC_FLOODFILLER = BlockTags.create(modLoc("akashic_floodfiller"));
|
||||
|
||||
private static ResourceLocation modLoc(String name) {
|
||||
return new ResourceLocation(HexMod.MOD_ID, name);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,10 @@ package at.petrak.hexcasting.common.blocks;
|
|||
|
||||
import at.petrak.hexcasting.HexMod;
|
||||
import at.petrak.hexcasting.api.circle.BlockAbstractImpetus;
|
||||
import at.petrak.hexcasting.common.blocks.akashic.BlockAkashicBookshelf;
|
||||
import at.petrak.hexcasting.common.blocks.akashic.BlockAkashicRecord;
|
||||
import at.petrak.hexcasting.common.blocks.akashic.BlockEntityAkashicBookshelf;
|
||||
import at.petrak.hexcasting.common.blocks.akashic.BlockEntityAkashicRecord;
|
||||
import at.petrak.hexcasting.common.blocks.circles.BlockEmptyImpetus;
|
||||
import at.petrak.hexcasting.common.blocks.circles.BlockEntitySlate;
|
||||
import at.petrak.hexcasting.common.blocks.circles.BlockSlate;
|
||||
|
@ -53,6 +57,10 @@ public class HexBlocks {
|
|||
.instabreak();
|
||||
}
|
||||
|
||||
private static BlockBehaviour.Properties woody() {
|
||||
return BlockBehaviour.Properties.of(Material.WOOD).strength(3f, 4f);
|
||||
}
|
||||
|
||||
public static final RegistryObject<BlockSlate> SLATE = BLOCKS.register("slate",
|
||||
() -> new BlockSlate(slateish()));
|
||||
|
||||
|
@ -78,6 +86,11 @@ public class HexBlocks {
|
|||
public static final RegistryObject<BlockRedstoneDirectrix> DIRECTRIX_REDSTONE = blockItem("directrix_redstone",
|
||||
() -> new BlockRedstoneDirectrix(slateish()));
|
||||
|
||||
public static final RegistryObject<BlockAkashicRecord> AKASHIC_RECORD = blockItem("akashic_record",
|
||||
() -> new BlockAkashicRecord(woody()));
|
||||
public static final RegistryObject<BlockAkashicBookshelf> AKASHIC_BOOKSHELF = blockItem("akashic_bookshelf",
|
||||
() -> new BlockAkashicBookshelf(woody()));
|
||||
|
||||
// Decoration?!
|
||||
public static final RegistryObject<Block> SLATE_BLOCK = blockItem("slate_block",
|
||||
() -> new Block(slateish().strength(2f, 4f)));
|
||||
|
@ -118,6 +131,13 @@ public class HexBlocks {
|
|||
() -> BlockEntityType.Builder.of(BlockEntityStoredPlayerImpetus::new, IMPETUS_STOREDPLAYER.get())
|
||||
.build(null));
|
||||
|
||||
public static final RegistryObject<BlockEntityType<BlockEntityAkashicRecord>> AKASHIC_RECORD_TILE = BLOCK_ENTITIES.register(
|
||||
"akashic_record_tile",
|
||||
() -> BlockEntityType.Builder.of(BlockEntityAkashicRecord::new, AKASHIC_RECORD.get()).build(null));
|
||||
public static final RegistryObject<BlockEntityType<BlockEntityAkashicBookshelf>> AKASHIC_BOOKSHELF_TILE = BLOCK_ENTITIES.register(
|
||||
"akashic_bookshelf_tile",
|
||||
() -> BlockEntityType.Builder.of(BlockEntityAkashicBookshelf::new, AKASHIC_BOOKSHELF.get()).build(null));
|
||||
|
||||
|
||||
private static boolean never(Object... args) {
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package at.petrak.hexcasting.common.blocks.akashic;
|
||||
|
||||
import at.petrak.hexcasting.common.blocks.HexBlockTags;
|
||||
import at.petrak.hexcasting.common.blocks.HexBlocks;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
public class BlockAkashicBookshelf extends Block {
|
||||
public BlockAkashicBookshelf(Properties p_49795_) {
|
||||
super(p_49795_);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlace(BlockState pState, Level world, BlockPos pos, BlockState pOldState, boolean pIsMoving) {
|
||||
if (world.getBlockEntity(pos) instanceof BlockEntityAkashicBookshelf tile) {
|
||||
var recordPos = BlockEntityAkashicRecord.floodFillFor(pos, world,
|
||||
(here, bs) -> bs.is(HexBlockTags.AKASHIC_FLOODFILLER),
|
||||
(here, bs) -> bs.is(HexBlocks.AKASHIC_RECORD.get()));
|
||||
if (recordPos != null) {
|
||||
tile.recordPos = recordPos;
|
||||
tile.setChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) {
|
||||
if (pLevel.getBlockEntity(pPos) instanceof BlockEntityAkashicBookshelf tile &&
|
||||
tile.recordPos != null && pLevel.getBlockEntity(tile.recordPos) instanceof BlockEntityAkashicRecord rec) {
|
||||
rec.removeFloodfillerAt(pPos);
|
||||
}
|
||||
|
||||
super.onRemove(pState, pLevel, pPos, pNewState, pIsMoving);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package at.petrak.hexcasting.common.blocks.akashic;
|
||||
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
public class BlockAkashicRecord extends Block {
|
||||
public BlockAkashicRecord(Properties p_49795_) {
|
||||
super(p_49795_);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
package at.petrak.hexcasting.common.blocks.akashic;
|
||||
|
||||
import at.petrak.hexcasting.client.RenderLib;
|
||||
import at.petrak.hexcasting.common.blocks.HexBlocks;
|
||||
import at.petrak.hexcasting.common.blocks.circles.BlockSlate;
|
||||
import at.petrak.hexcasting.hexmath.HexPattern;
|
||||
import at.petrak.paucal.api.PaucalBlockEntity;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Quaternion;
|
||||
import com.mojang.math.Vector3f;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.block.BlockRenderDispatcher;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
|
||||
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.Vec2;
|
||||
|
||||
public class BlockEntityAkashicBookshelf extends PaucalBlockEntity {
|
||||
public static final String TAG_RECORD_POS = "record_pos";
|
||||
public static final String TAG_PATTERN = "pattern";
|
||||
|
||||
// This is only not null if this stores any data.
|
||||
public BlockPos recordPos = null;
|
||||
public HexPattern pattern = null;
|
||||
|
||||
public BlockEntityAkashicBookshelf(BlockPos pWorldPosition, BlockState pBlockState) {
|
||||
super(HexBlocks.AKASHIC_BOOKSHELF_TILE.get(), pWorldPosition, pBlockState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveModData(CompoundTag compoundTag) {
|
||||
if (this.recordPos != null && this.pattern != null) {
|
||||
compoundTag.put(TAG_RECORD_POS, NbtUtils.writeBlockPos(this.recordPos));
|
||||
compoundTag.put(TAG_PATTERN, this.pattern.serializeToNBT());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadModData(CompoundTag compoundTag) {
|
||||
if (compoundTag.contains(TAG_RECORD_POS) && compoundTag.contains(TAG_PATTERN)) {
|
||||
this.recordPos = NbtUtils.readBlockPos(compoundTag.getCompound(TAG_RECORD_POS));
|
||||
this.pattern = HexPattern.DeserializeFromNBT(compoundTag.getCompound(TAG_PATTERN));
|
||||
}
|
||||
}
|
||||
|
||||
public static class Renderer implements BlockEntityRenderer<BlockEntityAkashicBookshelf> {
|
||||
private final BlockRenderDispatcher dispatcher;
|
||||
|
||||
public Renderer(BlockEntityRendererProvider.Context ctx) {
|
||||
this.dispatcher = ctx.getBlockRenderDispatcher();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(BlockEntityAkashicBookshelf tile, float pPartialTick, PoseStack ps,
|
||||
MultiBufferSource buffer, int light, int overlay) {
|
||||
if (tile.pattern == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var bs = tile.getBlockState();
|
||||
|
||||
var oldShader = RenderSystem.getShader();
|
||||
RenderSystem.setShader(GameRenderer::getPositionColorShader);
|
||||
RenderSystem.enableDepthTest();
|
||||
|
||||
ps.pushPose();
|
||||
|
||||
ps.translate(0.5, 0.5, 0.5);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ps.pushPose();
|
||||
|
||||
ps.mulPose(new Quaternion(Vector3f.YP, Mth.HALF_PI * i, false));
|
||||
ps.mulPose(new Quaternion(Vector3f.ZP, Mth.PI, false));
|
||||
|
||||
// and now Z is out?
|
||||
ps.translate(0, 0, 0.5);
|
||||
ps.scale(1 / 16f, 1 / 16f, 1 / 16f);
|
||||
ps.translate(0, 0, 0.01);
|
||||
|
||||
// yoink code from the pattern greeble
|
||||
// Do two passes: one with a random size to find a good COM and one with the real calculation
|
||||
var com1 = tile.pattern.getCenter(1);
|
||||
var lines1 = tile.pattern.toLines(1, Vec2.ZERO);
|
||||
|
||||
var maxDx = -1f;
|
||||
var maxDy = -1f;
|
||||
for (var dot : lines1) {
|
||||
var dx = Mth.abs(dot.x - com1.x);
|
||||
if (dx > maxDx) {
|
||||
maxDx = dx;
|
||||
}
|
||||
var dy = Mth.abs(dot.y - com1.y);
|
||||
if (dy > maxDy) {
|
||||
maxDy = dy;
|
||||
}
|
||||
}
|
||||
var scale = Math.min(3.8f, Math.min(16 / 2.5f / maxDx, 16 / 2.5f / maxDy));
|
||||
|
||||
var com2 = tile.pattern.getCenter(scale);
|
||||
var lines2 = tile.pattern.toLines(scale, com2.negated());
|
||||
// For some reason it is mirrored left to right and i can't seem to posestack-fu it into shape
|
||||
for (int j = 0; j < lines2.size(); j++) {
|
||||
var v = lines2.get(j);
|
||||
lines2.set(i, new Vec2(-v.x, v.y));
|
||||
}
|
||||
|
||||
var isLit = bs.getValue(BlockSlate.ENERGIZED);
|
||||
var zappy = RenderLib.makeZappy(lines2, 10f, isLit ? 2.5f : 0.5f, isLit ? 0.1f : 0f);
|
||||
|
||||
int outer = isLit ? 0xff_64c8ff : 0xff_d2c8c8;
|
||||
int inner = isLit ? RenderLib.screenCol(outer) : 0xc8_322b33;
|
||||
RenderLib.drawLineSeq(ps.last().pose(), zappy, 1f, 0f, outer, outer);
|
||||
RenderLib.drawLineSeq(ps.last().pose(), zappy, 0.4f, 0.01f, inner, inner);
|
||||
|
||||
ps.popPose();
|
||||
}
|
||||
|
||||
ps.popPose();
|
||||
RenderSystem.setShader(() -> oldShader);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
package at.petrak.hexcasting.common.blocks.akashic;
|
||||
|
||||
import at.petrak.hexcasting.api.spell.SpellDatum;
|
||||
import at.petrak.hexcasting.common.blocks.HexBlockTags;
|
||||
import at.petrak.hexcasting.common.blocks.HexBlocks;
|
||||
import at.petrak.hexcasting.hexmath.HexDir;
|
||||
import at.petrak.hexcasting.hexmath.HexPattern;
|
||||
import at.petrak.paucal.api.PaucalBlockEntity;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
public class BlockEntityAkashicRecord extends PaucalBlockEntity {
|
||||
public static final String TAG_LOOKUP = "lookup",
|
||||
TAG_POS = "pos",
|
||||
TAG_DATUM = "datum",
|
||||
TAG_DIR = "dir";
|
||||
|
||||
// Hex pattern signatures to pos and iota.
|
||||
// Note this is NOT a record of the entire floodfill! Just bookshelves.
|
||||
|
||||
// When deserializing on the server we have the actual iotae...
|
||||
private Map<String, ServerEntry> serverEntries;
|
||||
// on the client we just have their displays
|
||||
private Map<String, ClientEntry> clientEntries;
|
||||
|
||||
public BlockEntityAkashicRecord(BlockPos pWorldPosition, BlockState pBlockState) {
|
||||
super(HexBlocks.AKASHIC_RECORD_TILE.get(), pWorldPosition, pBlockState);
|
||||
}
|
||||
|
||||
public void removeFloodfillerAt(BlockPos pos) {
|
||||
// lmao just recalc everything
|
||||
this.revalidateAllBookshelves();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the block position of the place it gets stored, or null if there was no room.
|
||||
* <p>
|
||||
* Will never clobber anything.
|
||||
*/
|
||||
public @Nullable BlockPos addNewDatum(HexPattern key, SpellDatum<?> datum) {
|
||||
if (this.serverEntries == null) {
|
||||
throw new IllegalCallerException("should only have SpellDatums on the server");
|
||||
}
|
||||
if (this.serverEntries.containsKey(key.anglesSignature())) {
|
||||
return null; // would clobber
|
||||
}
|
||||
|
||||
var openPos = floodFillFor(this.worldPosition, this.level,
|
||||
(pos, bs) -> bs.is(HexBlockTags.AKASHIC_FLOODFILLER),
|
||||
(pos, bs) -> this.level.getBlockEntity(pos) instanceof BlockEntityAkashicBookshelf tile
|
||||
&& tile.recordPos == null);
|
||||
if (openPos != null) {
|
||||
var tile = (BlockEntityAkashicBookshelf) this.level.getBlockEntity(openPos);
|
||||
tile.recordPos = this.worldPosition;
|
||||
tile.pattern = key;
|
||||
tile.setChanged();
|
||||
|
||||
this.serverEntries.put(key.anglesSignature(), new ServerEntry(openPos, key.startDir(), datum));
|
||||
this.setChanged();
|
||||
return openPos;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable SpellDatum<?> lookupPattern(HexPattern key) {
|
||||
if (this.serverEntries == null) {
|
||||
throw new IllegalCallerException("should only have SpellDatums on the server");
|
||||
}
|
||||
|
||||
var entry = this.serverEntries.get(key.anglesSignature());
|
||||
if (entry == null) {
|
||||
return null;
|
||||
} else {
|
||||
return entry.datum;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the entry was actually removed.
|
||||
*/
|
||||
public boolean clearKey(HexPattern key) {
|
||||
if (this.serverEntries == null) {
|
||||
throw new IllegalCallerException("should only have SpellDatums on the server");
|
||||
}
|
||||
return this.serverEntries.remove(key.anglesSignature()) != null;
|
||||
}
|
||||
|
||||
private void revalidateAllBookshelves() {
|
||||
// floodfill for all known positions
|
||||
var validPoses = new HashSet<BlockPos>();
|
||||
{
|
||||
var todo = new ArrayDeque<BlockPos>();
|
||||
todo.add(this.worldPosition);
|
||||
while (!todo.isEmpty()) {
|
||||
var here = todo.remove();
|
||||
|
||||
for (var dir : Direction.values()) {
|
||||
var neighbor = here.relative(dir);
|
||||
if (validPoses.add(neighbor)) {
|
||||
var bs = this.level.getBlockState(neighbor);
|
||||
if (bs.is(HexBlockTags.AKASHIC_FLOODFILLER)) {
|
||||
todo.add(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var lookup = this.getLookup();
|
||||
var sigs = lookup.keySet();
|
||||
for (var sig : sigs) {
|
||||
var entry = lookup.get(sig);
|
||||
if (!validPoses.contains(entry.getPos())) {
|
||||
// oh no!
|
||||
lookup.remove(sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, ? extends PosAndDirHaver> getLookup() {
|
||||
if (this.serverEntries != null) {
|
||||
return this.serverEntries;
|
||||
} else if (this.clientEntries != null) {
|
||||
return this.clientEntries;
|
||||
} else {
|
||||
// uh oh
|
||||
throw new IllegalStateException("both server and client entries were null");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveModData(CompoundTag compoundTag) {
|
||||
var lookupTag = new CompoundTag();
|
||||
if (this.clientEntries != null) {
|
||||
this.clientEntries.forEach((sig, entry) -> {
|
||||
var t = new CompoundTag();
|
||||
t.put(TAG_POS, NbtUtils.writeBlockPos(entry.pos));
|
||||
t.put(TAG_DATUM, entry.original);
|
||||
t.putByte(TAG_DIR, (byte) entry.startDir.ordinal());
|
||||
lookupTag.put(sig, t);
|
||||
});
|
||||
} else if (this.serverEntries != null) {
|
||||
this.serverEntries.forEach((sig, entry) -> {
|
||||
var t = new CompoundTag();
|
||||
t.put(TAG_POS, NbtUtils.writeBlockPos(entry.pos));
|
||||
t.put(TAG_DATUM, entry.datum.serializeToNBT());
|
||||
t.putByte(TAG_DIR, (byte) entry.startDir.ordinal());
|
||||
lookupTag.put(sig, t);
|
||||
});
|
||||
}
|
||||
compoundTag.put(TAG_LOOKUP, lookupTag);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadModData(CompoundTag compoundTag) {
|
||||
var lookupTag = compoundTag.getCompound(TAG_LOOKUP);
|
||||
var sigs = lookupTag.getAllKeys();
|
||||
|
||||
if (this.level instanceof ClientLevel) {
|
||||
this.clientEntries = new HashMap<>();
|
||||
for (var sig : sigs) {
|
||||
var entryTag = lookupTag.getCompound(sig);
|
||||
var pos = NbtUtils.readBlockPos(entryTag.getCompound(TAG_POS));
|
||||
var dir = HexDir.values()[entryTag.getByte(TAG_DIR)];
|
||||
var display = SpellDatum.DisplayFromTag(entryTag.getCompound(TAG_DATUM));
|
||||
this.clientEntries.put(sig, new ClientEntry(pos, dir, display, entryTag));
|
||||
}
|
||||
} else if (this.level instanceof ServerLevel sworld) {
|
||||
this.serverEntries = new HashMap<>();
|
||||
for (var sig : sigs) {
|
||||
var entryTag = lookupTag.getCompound(sig);
|
||||
var pos = NbtUtils.readBlockPos(entryTag.getCompound(TAG_POS));
|
||||
var dir = HexDir.values()[entryTag.getByte(TAG_DIR)];
|
||||
var datum = SpellDatum.DeserializeFromNBT(entryTag.getCompound(TAG_DATUM), sworld);
|
||||
this.serverEntries.put(sig, new ServerEntry(pos, dir, datum));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private interface PosAndDirHaver {
|
||||
BlockPos getPos();
|
||||
|
||||
HexDir getDir();
|
||||
}
|
||||
|
||||
private record ServerEntry(BlockPos pos, HexDir startDir, SpellDatum<?> datum) implements PosAndDirHaver {
|
||||
@Override
|
||||
public BlockPos getPos() {
|
||||
return this.pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HexDir getDir() {
|
||||
return this.startDir;
|
||||
}
|
||||
}
|
||||
|
||||
private record ClientEntry(BlockPos pos, HexDir startDir, Component display,
|
||||
CompoundTag original) implements PosAndDirHaver {
|
||||
@Override
|
||||
public BlockPos getPos() {
|
||||
return this.pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HexDir getDir() {
|
||||
return this.startDir;
|
||||
}
|
||||
}
|
||||
|
||||
public static @Nullable BlockPos floodFillFor(BlockPos start, Level world,
|
||||
BiPredicate<BlockPos, BlockState> isValid, BiPredicate<BlockPos, BlockState> isTarget) {
|
||||
var seenBlocks = new HashSet<BlockPos>();
|
||||
var todo = new ArrayDeque<BlockPos>();
|
||||
todo.add(start);
|
||||
|
||||
while (!todo.isEmpty()) {
|
||||
var here = todo.remove();
|
||||
|
||||
for (var dir : Direction.values()) {
|
||||
var neighbor = here.relative(dir);
|
||||
if (seenBlocks.add(neighbor)) {
|
||||
var bs = world.getBlockState(neighbor);
|
||||
if (isTarget.test(neighbor, bs)) {
|
||||
return neighbor;
|
||||
} else if (isValid.test(neighbor, bs)) {
|
||||
todo.add(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package at.petrak.hexcasting.datagen;
|
||||
|
||||
import at.petrak.hexcasting.HexMod;
|
||||
import at.petrak.hexcasting.common.blocks.HexBlockTags;
|
||||
import at.petrak.hexcasting.common.blocks.HexBlocks;
|
||||
import net.minecraft.data.DataGenerator;
|
||||
import net.minecraft.data.tags.BlockTagsProvider;
|
||||
|
@ -8,8 +9,8 @@ import net.minecraft.tags.BlockTags;
|
|||
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class HexBlockTags extends BlockTagsProvider {
|
||||
public HexBlockTags(DataGenerator pGenerator,
|
||||
public class HexBlockTagProvider extends BlockTagsProvider {
|
||||
public HexBlockTagProvider(DataGenerator pGenerator,
|
||||
@Nullable ExistingFileHelper existingFileHelper) {
|
||||
super(pGenerator, HexMod.MOD_ID, existingFileHelper);
|
||||
}
|
||||
|
@ -26,7 +27,13 @@ public class HexBlockTags extends BlockTagsProvider {
|
|||
tag(BlockTags.MINEABLE_WITH_SHOVEL)
|
||||
.add(HexBlocks.AMETHYST_DUST_BLOCK.get());
|
||||
|
||||
tag(BlockTags.MINEABLE_WITH_HOE)
|
||||
.add(HexBlocks.AKASHIC_RECORD.get(), HexBlocks.AKASHIC_BOOKSHELF.get());
|
||||
|
||||
tag(BlockTags.CRYSTAL_SOUND_BLOCKS)
|
||||
.add(HexBlocks.CONJURED.get(), HexBlocks.AMETHYST_TILES.get(), HexBlocks.SCONCE.get());
|
||||
|
||||
tag(HexBlockTags.AKASHIC_FLOODFILLER)
|
||||
.add(HexBlocks.AKASHIC_BOOKSHELF.get());
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@ public class HexDataGenerators {
|
|||
gen.addProvider(new HexRecipes(gen));
|
||||
gen.addProvider(new HexLootModifiers(gen));
|
||||
gen.addProvider(new HexAdvancements(gen, efh));
|
||||
gen.addProvider(new HexBlockTags(gen, efh));
|
||||
gen.addProvider(new HexBlockTagProvider(gen, efh));
|
||||
gen.addProvider(new HexLootTables(gen));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue