diff --git a/src/client/java/modchest/REServerModClient.java b/src/client/java/modchest/REServerModClient.java index 277899d..ffee1a5 100644 --- a/src/client/java/modchest/REServerModClient.java +++ b/src/client/java/modchest/REServerModClient.java @@ -1,25 +1,78 @@ package modchest; import modchest.assets.OverlayAssetListener; +import modchest.assets.overlay.OffsetterRegistry; +import modchest.assets.overlay.ZeroOffsetter; import modchest.block.custom.gridCodecs; +import modchest.block.custom.gridPreviewOutline; +import modchest.gui.gridScreen; import modchest.networking.modNetworkingClient; +import modchest.transform.gridTransform; import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry; +import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; +import net.fabricmc.fabric.api.client.screenhandler.v1.ScreenRegistry; +import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; +import net.fabricmc.fabric.api.object.builder.v1.client.model.FabricModelPredicateProviderRegistry; +import net.fabricmc.fabric.api.renderer.v1.render.RenderContext.QuadTransform; +import net.fabricmc.fabric.api.resource.ResourceManagerHelper; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.texture.SpriteAtlasTexture; import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.resource.ResourceType; import net.minecraft.util.Identifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.mojang.serialization.Codec; + public class REServerModClient implements ClientModInitializer { public static gridCodecs CODECS; public static OverlayAssetListener CLIENT_OVERLAYS; public static final Logger LOGGER = LoggerFactory.getLogger("modchest"); // Erster Error Logger + + @SuppressWarnings("deprecation") @Override public void onInitializeClient() { - // This entrypoint is suitable for setting up client-specific logic, such as rendering. - + final Identifier zeroId = REServerMod.META.id("zero"); + OffsetterRegistry.register(zeroId, Codec.unit(new ZeroOffsetter(zeroId))); + REServerModClient.CODECS = new gridCodecs(); - modNetworkingClient.registerC2SPackets(); //Identifier unter denen der Client zuhoert werden registriert + QuadTransformRegistry.INSTANCE.register(REServerMod.META.id("grid_transform"), gridTransform.SOURCE); + + ScreenRegistry.register(REServerMod.META.GRID_SCREEN_HANDLER_TYPE, gridScreen.FACTORY); + + ClientSpriteRegistryCallback.event(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE).register((atlas, registry) -> { + final int textureStart = "textures/".length(); + final int pngLen = ".png".length(); + for (final Identifier id : MinecraftClient.getInstance().getResourceManager().findResources("textures/grid", + s -> s.endsWith(".png"))) { + registry.register(new Identifier(id.getNamespace(), + id.getPath().substring(textureStart, id.getPath().length() - pngLen))); + } + }); + + CLIENT_OVERLAYS = new OverlayAssetListener(); + ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(CLIENT_OVERLAYS); + + ModelLoadingRegistry.INSTANCE.registerModelProvider( + (resourceManager, out) -> out + .accept(new ModelIdentifier(REServerMod.META.id("hammer_none"), "inventory"))); + + FabricModelPredicateProviderRegistry.register( + REServerMod.ITEMS.HAMMER, + REServerMod.META.id("hammer_mode"), + (stack, world, entity) -> Optional.ofNullable(stack.getTag()) + .map(t -> t.getString("mode")) + .flatMap(Hammer.CopyMode::fromString) + .orElse(Hammer.CopyMode.DEFAULT).id); + + WorldRenderEvents.AFTER_ENTITIES.register(gridPreviewOutline::renderPreviewOutline); + + // This entrypoint is suitable for setting up client-specific logic, such as rendering. + + modNetworkingClient.registerC2SPackets(); // Identifier unter denen der Client zuhoert werden registriert LOGGER.info("Modchest-Client successfully loaded!"); } diff --git a/src/client/java/modchest/assets/OverlayAssetListener.java b/src/client/java/modchest/assets/OverlayAssetListener.java index 99d0d8f..d8fa57d 100644 --- a/src/client/java/modchest/assets/OverlayAssetListener.java +++ b/src/client/java/modchest/assets/OverlayAssetListener.java @@ -18,10 +18,11 @@ import com.google.gson.JsonElement; import com.mojang.serialization.DataResult; import com.mojang.serialization.JsonOps; +import modchest.REServerMod; +import modchest.assets.overlay.Overlay; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.resource.SimpleResourceReloadListener; -import net.minecraft.client.gui.screen.Overlay; import net.minecraft.resource.ResourceManager; import net.minecraft.util.Identifier; import net.minecraft.util.Pair; @@ -41,10 +42,12 @@ public class OverlayAssetListener implements SimpleResourceReloadListener { overlayInfoMap.clear(); - return resourceManager.findResources("modchest/overlays", s -> s.endsWith(".json")); + return manager.findResources("modchest/overlays", s -> s.endsWith(".json")); }, executor); } + + private DataResult parseOverlayAndDependencies(final ResourceManager resourceManager, final Identifier rootOverlayId) { final Set loadedDependencies = new HashSet<>(); @@ -60,8 +63,12 @@ public class OverlayAssetListener implements SimpleResourceReloadListener loadedDependencies, final Identifier overlayId) { final JsonElement element; try { - element = new Gson().fromJson( - new BufferedReader(new InputStreamReader(resourceManager.getResource(overlayId).getInputStream())), + element = new Gson().fromJson(new BufferedReader(new InputStreamReader(resourceManager.get(overlayId).getInputStream()), JsonElement.class); + + + )} + + /*new BufferedReader(new InputStreamReader(resourceManager.getResource(overlayId).getInputStream())), JsonElement.class); } catch (final IOException e) { return DataResult.error("Exception while loading an overlay:"); @@ -83,20 +90,21 @@ public class OverlayAssetListener implements SimpleResourceReloadListener Unit.INSTANCE); - } + }*/ @Override public CompletableFuture apply(Collection data, ResourceManager manager, Profiler profiler, Executor executor) { return CompletableFuture.runAsync(() -> { - for (final Identifier id : identifiers) { + for (final Identifier id : data) { final DataResult result = parseOverlayAndDependencies(manager, id); - result.get().ifRight(partial -> META.LOGGER - .warn("Error while parsing overlay \"" + id + "\": " + partial.message())); + result.get().ifRight(partial -> REServerMod.META.LOGGER.warning("Error while parsing overlay \"" + id + "\": " + partial.message())); } }, executor); } + private final Identifier id = REServerMod.META.id("assets/overlay"); + @Override public Identifier getFabricId() { return id; diff --git a/src/client/java/modchest/assets/overlay/Offsetter.java b/src/client/java/modchest/assets/overlay/Offsetter.java index 50e86f5..d52ccba 100644 --- a/src/client/java/modchest/assets/overlay/Offsetter.java +++ b/src/client/java/modchest/assets/overlay/Offsetter.java @@ -4,7 +4,7 @@ import java.util.Optional; import java.util.function.Function; import java.util.function.Supplier; import modchest.util.ToOptional; - +import modchest.REServerMod; import modchest.util.Float4; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @@ -16,7 +16,7 @@ public interface Offsetter extends ToOptional { public Identifier getId(); - Identifier NONE_ID = META.id("none"); + Identifier NONE_ID = REServerMod.META.id("none"); Offsetter NONE = new Offsetter() { @Override diff --git a/src/client/java/modchest/assets/overlay/OffsetterRegistry.java b/src/client/java/modchest/assets/overlay/OffsetterRegistry.java index 98fbc02..edc4cc6 100644 --- a/src/client/java/modchest/assets/overlay/OffsetterRegistry.java +++ b/src/client/java/modchest/assets/overlay/OffsetterRegistry.java @@ -17,6 +17,7 @@ public class OffsetterRegistry { private static final Map>> registeredOffsetters = new HashMap<>(); + @SuppressWarnings("unused") private static void register(final Identifier id, final Codec codec) { registeredOffsetters.put(id, new Identifiable<>(codec, id)); } diff --git a/src/client/java/modchest/assets/overlay/Offsetters.java b/src/client/java/modchest/assets/overlay/Offsetters.java index e2aea18..6416050 100644 --- a/src/client/java/modchest/assets/overlay/Offsetters.java +++ b/src/client/java/modchest/assets/overlay/Offsetters.java @@ -1,20 +1,19 @@ package modchest.assets.overlay; -import org.jetbrains.annotations.Nullable; - import java.util.Optional; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import modchest.REServerModClient; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; @Environment(EnvType.CLIENT) public class Offsetters { public static final Codec CODEC = RecordCodecBuilder.create(inst -> inst.group( - CODECS.OFFSETTER.optionalFieldOf("u").forGetter(o -> o.u.toOptional()), - CODECS.OFFSETTER.optionalFieldOf("v").forGetter(o -> o.v.toOptional()) + REServerModClient.CODECS.OFFSETTER.optionalFieldOf("u").forGetter(o -> o.u.toOptional()), + REServerModClient.CODECS.OFFSETTER.optionalFieldOf("v").forGetter(o -> o.v.toOptional()) ).apply(inst, Offsetters::new)); public static final Offsetters NONE = new Offsetters(); diff --git a/src/client/java/modchest/assets/overlay/Overlay.java b/src/client/java/modchest/assets/overlay/Overlay.java index ffb2d9b..c8b1200 100644 --- a/src/client/java/modchest/assets/overlay/Overlay.java +++ b/src/client/java/modchest/assets/overlay/Overlay.java @@ -9,6 +9,7 @@ import org.jetbrains.annotations.Nullable; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import modchest.REServerModClient; import modchest.assets.Parent; import modchest.assets.Parent.Some; import modchest.transform.TransformResult; @@ -97,7 +98,7 @@ public abstract class Overlay implements ToOptional { @Override public TransformResult apply(MutableQuadView mqv, Float4 us, Float4 vs, Direction dir) { final Float4 finalUs = sidedOffsetters().applyUs(us, dir); - float Float4 finalVs = sidedOffsetters().applyVs(vs, dir); + final Float4 finalVs = sidedOffsetters().applyVs(vs, dir); return textureSource().apply(mqv, finalUs, finalVs, dir); } @@ -106,7 +107,7 @@ public abstract class Overlay implements ToOptional { if (textureSource != TextureSource.NONE) { return textureSource; } else { - return parent.run(parent -> CLIENT_OVERLAYS.getOverlayFor(parent).textureSource(), TextureSource.NONE); + return parent.run(parent -> REServerModClient.CLIENT_OVERLAYS.getOverlayFor(parent).textureSource(), TextureSource.NONE); } } @@ -115,7 +116,7 @@ public abstract class Overlay implements ToOptional { if (coloredLike.isPresent()) { return coloredLike; } else { - return parent.run(parent -> CLIENT_OVERLAYS.getOverlayFor(parent).coloredLike(), Optional.empty()); + return parent.run(parent -> REServerModClient.CLIENT_OVERLAYS.getOverlayFor(parent).coloredLike(), Optional.empty()); } } @@ -124,7 +125,7 @@ public abstract class Overlay implements ToOptional { if (sideOffsetters != SidedOffsetters.NONE) { return sidedOffsetters; } else { - return parent.run(parent -> CLIENT_OVERLAYS.getOverlayFor(parent).sidedOffsetters(), + return parent.run(parent -> REServerModClient.CLIENT_OVERLAYS.getOverlayFor(parent).sidedOffsetters(), SidedOffsetters.NONE); } } diff --git a/src/client/java/modchest/assets/overlay/SidedOffsetters.java b/src/client/java/modchest/assets/overlay/SidedOffsetters.java index c95dd6d..762a74c 100644 --- a/src/client/java/modchest/assets/overlay/SidedOffsetters.java +++ b/src/client/java/modchest/assets/overlay/SidedOffsetters.java @@ -7,9 +7,9 @@ import java.util.function.Supplier; import com.mojang.serialization.Codec; +import modchest.REServerModClient; import modchest.util.Float4; import modchest.util.ToOptional; -import modchest.util.initializer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.util.math.Direction; @@ -21,26 +21,27 @@ public abstract class SidedOffsetters { public static final Codec CODEC = Some.CODEC.xmap(some -> some, base -> (Some) base); public static final Base NONE = new Base() { - + @Override public Optional toOptional() { return Optional.empty(); } @Override - public Float4 applyUs(final Float4 origUs, Direction dir) { - return origUs; - } - - @Override - public Float4 applyVs(final Float4 origVs, Direction dir) { - return origVs; - } - - @Override - public T match(Function some, Supplier none) { + public T match(Function some, Supplier none) { return none.get(); } + + @Override + public Float4 applyUs(Float4 origUs, Direction dir) { + return origUs; + } + + @Override + public Float4 applyVs(Float4 origVs, Direction dir) { + return origVs; + } + }; public interface Base extends ToOptional { @@ -50,7 +51,7 @@ public abstract class SidedOffsetters { } public static class Some implements Base, ToOptional.Some { - public static final Codec CODEC = CODECS.sidedMapOf(Offsetters.CODEC) + public static final Codec CODEC = REServerModClient.CODECS.sideMapOf(Offsetters.CODEC) .xmap(SidedOffsetters.Some::new, so -> so.map); private final Map map; diff --git a/src/client/java/modchest/assets/overlay/TextureSource.java b/src/client/java/modchest/assets/overlay/TextureSource.java index 7cffb81..fe033ba 100644 --- a/src/client/java/modchest/assets/overlay/TextureSource.java +++ b/src/client/java/modchest/assets/overlay/TextureSource.java @@ -9,8 +9,11 @@ import java.util.function.Supplier; import org.spongepowered.asm.mixin.Final; import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; import com.mojang.serialization.codecs.RecordCodecBuilder; +import modchest.REServerMod; +import modchest.REServerModClient; import modchest.transform.MaterialApplier; import modchest.transform.SpriteApplier; import modchest.transform.TransformResult; @@ -42,8 +45,7 @@ public abstract class TextureSource implements ToOptional { @SuppressWarnings("deprecation") public Entry(Identifier texture, Optional materialSource) { - final Sprite sprite = MinecraftClient.getInstance().getSpriteAtlas(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE) - .apply(texture); + final Sprite sprite = MinecraftClient.getInstance().getSpriteAtlas(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE).apply(texture); this.textureApplier = SpriteApplier.ofNullable(sprite); final Optional materialSourceState = materialSource .map(id -> Registry.BLOCK.get(id).getDefaultState()); @@ -62,7 +64,7 @@ public abstract class TextureSource implements ToOptional { .apply(inst, i -> i)); case SIDED: return RecordCodecBuilder.create( - inst -> inst.group(Sided.SIDED_CODEC.fieldOf("value").forGetter(i -> (Single) i)) + inst -> inst.group(Sided.SIDED_CODEC.fieldOf("value").forGetter(i -> (Sided) i)) .apply(inst, i -> i)); default: throw new IllegalStateException("Invalid TextureSourceKind:" + kind); @@ -110,7 +112,7 @@ public abstract class TextureSource implements ToOptional { Identifier.CODEC.optionalFieldOf("materialFrom").forGetter(e -> e.materialApplier.id())) .apply(inst, Entry::new)); - SIDED_CODEC = CODECS.sidedMapOf(sidedValueCodec).xmap( + SIDED_CODEC = REServerModClient.CODECS.sidedMapOf(sidedValueCodec).xmap( map -> new Sided(new EnumMap<>(map)), sided -> sided.entries); } diff --git a/src/client/java/modchest/block/custom/gridPreviewOutline.java b/src/client/java/modchest/block/custom/gridPreviewOutline.java index 2318b3c..af208fd 100644 --- a/src/client/java/modchest/block/custom/gridPreviewOutline.java +++ b/src/client/java/modchest/block/custom/gridPreviewOutline.java @@ -4,17 +4,20 @@ import static net.minecraft.block.Block.field_31022; import java.nio.ByteBuffer; import java.nio.IntBuffer; +import java.util.List; import java.util.Properties; import org.lwjgl.system.MemoryStack; +import modchest.REServerMod; +import modchest.block.custom.grid.gridBlock; import modchest.event.playerAfterRespawnEvent; -import modchest.grid.gridBlock; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext; import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper; import net.fabricmc.tinyremapper.extension.mixin.hard.util.CamelPrefixString; import net.minecraft.block.Block; import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; import net.minecraft.block.enums.DoubleBlockHalf; import net.minecraft.client.MinecraftClient; import net.minecraft.client.network.ClientPlayerEntity; @@ -84,7 +87,7 @@ public class gridPreviewOutline { final BakedModel model = client.getBlockRenderManager().getModel(blockState); final boolean valid; - if (block == Blocks.GRID_DOOR) { + if (block == REServerMod.BLOCKS.GRID_DOOR) { final BlockPos upPos = pos.up(); final BlockState upState = blockState.with(Properties.DOUBLE_BLOCK_HALF, DoubleBlockHalf.UPPER); final BakedModel upModel = client.getBlockRenderManager().getModel(upState); diff --git a/src/main/java/modchest/mixin/mc/ItemRendererMixin.java b/src/client/java/modchest/mixin/client/ItemRendererMixin.java similarity index 86% rename from src/main/java/modchest/mixin/mc/ItemRendererMixin.java rename to src/client/java/modchest/mixin/client/ItemRendererMixin.java index e7e212d..5d4c993 100644 --- a/src/main/java/modchest/mixin/mc/ItemRendererMixin.java +++ b/src/client/java/modchest/mixin/client/ItemRendererMixin.java @@ -1,4 +1,4 @@ -package modchest.mixin.mc; +package modchest.mixin.client; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -6,7 +6,7 @@ import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -import modchest.util.initializer; +import modchest.REServerMod; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.render.item.ItemModels; @@ -16,7 +16,6 @@ import net.minecraft.client.util.ModelIdentifier; import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.LivingEntity; import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; import net.minecraft.world.World; @Environment(EnvType.CLIENT) @@ -31,8 +30,8 @@ public abstract class ItemRendererMixin { @Redirect(method = "getHeldItemModel", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/ItemModels;getModel(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/client/render/model/BakedModel;")) BakedModel getModelProxy(final ItemModels itemModels, final ItemStack stack) { - if (stack.getItem() == ITEMS.HAMMER) { - return itemModels.getModelManager().getModel(new ModelIdentifier(META.id("hammer_none"), "inventory")); + if (stack.getItem() == REServerMod.ITEMS.HAMMER) { + return itemModels.getModelManager().getModel(new ModelIdentifier(REServerMod.META.id("hammer_none"), "inventory")); } return itemModels.getModel(stack); } @@ -40,10 +39,10 @@ public abstract class ItemRendererMixin { @Redirect(method = "innerRenderInGui", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/ItemRenderer;getHeldItemModel(Lnet/minecraft/item/ItemStack;Lnet/minecraft/world/World;Lnet/minecraft/entity/LivingEntity;)Lnet/minecraft/client/render/model/BakedModel;")) BakedModel getHeldItemModelProxy(final ItemRenderer itemRenderer, final ItemStack stack, final World world, final LivingEntity entity) { - if (stack.getItem() == ITEMS.HAMMER) { + if (stack.getItem() == REServerMod.ITEMS.HAMMER) { final ClientWorld clientWorld = world instanceof ClientWorld ? (ClientWorld) world : null; final BakedModel model = models.getModelManager() - .getModel(new ModelIdentifier(META.id("hammer"), "inventory")); + .getModel(new ModelIdentifier(REServerMod.META.id("hammer"), "inventory")); final BakedModel model2 = model.getOverrides().apply(model, stack, clientWorld, entity, 0); return model2 == null ? models.getModelManager().getMissingModel() : model2; } diff --git a/src/main/java/modchest/mixin/mc/WorldRendererAccess.java b/src/client/java/modchest/mixin/client/WorldRendererAccess.java similarity index 91% rename from src/main/java/modchest/mixin/mc/WorldRendererAccess.java rename to src/client/java/modchest/mixin/client/WorldRendererAccess.java index 9ec426c..2ff1bd0 100644 --- a/src/main/java/modchest/mixin/mc/WorldRendererAccess.java +++ b/src/client/java/modchest/mixin/client/WorldRendererAccess.java @@ -1,4 +1,4 @@ -package modchest.mixin.mc; +package modchest.mixin.client; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; diff --git a/src/client/java/modchest/networking/modNetworkingClient.java b/src/client/java/modchest/networking/modNetworkingClient.java index 7a8acf3..0c5170f 100644 --- a/src/client/java/modchest/networking/modNetworkingClient.java +++ b/src/client/java/modchest/networking/modNetworkingClient.java @@ -1,7 +1,6 @@ package modchest.networking; import modchest.REServerMod; -import modchest.networking.packet.gridRenderRequestS2CPacket; import modchest.networking.packet.respawnRequestS2CPacket; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.minecraft.util.Identifier; @@ -13,7 +12,6 @@ public class modNetworkingClient { //Identifier werden eingeführt public static final Identifier grid_block_networking = new Identifier(REServerMod.MOD_ID, "grid_block_networking"); public static void registerC2SPackets() { //Identifier fuer packets werden registriert (Identifier die der Server aufruft um beim CLient was auszufuehren) - ClientPlayNetworking.registerGlobalReceiver(request_respawn, respawnRequestS2CPacket::receive); //was der Client dann machen soll steht in der receive Methode - ClientPlayNetworking.registerGlobalReceiver(grid_block_networking, gridRenderRequestS2CPacket::receive); + ClientPlayNetworking.registerGlobalReceiver(request_respawn, respawnRequestS2CPacket::receive); //was der Client dann machen soll steht in der receive Methode } } diff --git a/src/client/java/modchest/rendering/gridBlockTexture.java b/src/client/java/modchest/rendering/gridBlockTexture.java index e696e3b..a9f1c6e 100644 --- a/src/client/java/modchest/rendering/gridBlockTexture.java +++ b/src/client/java/modchest/rendering/gridBlockTexture.java @@ -1,40 +1,41 @@ -package modchest.rendering; - -import net.minecraft.client.texture.AbstractTexture; -import net.minecraft.client.texture.TextureManager; -import net.minecraft.resource.ResourceManager; -import net.minecraft.util.Identifier; - -public class gridBlockTexture extends TextureManager{ - - public gridBlockTexture(ResourceManager resourceManager) { - super(resourceManager); - //TODO Auto-generated constructor stub - } - - @Override - public AbstractTexture getTexture(Identifier id) { - return super.getTexture(id); - } - - /*public static BlockColors getBlockColors(Block block, BlockRenderView world, BlockPos pos, BlockColors blockColors) { - BlockState state = block.getDefaultState(); - // Verwende die Farbe für deine Zwecke - BlockColors colors = getBlockColors(block, world, pos, blockColors); - return colors; - }*/ - - /*public static Overlay getOverlayGrid(){ - MinecraftClient minecraftClient = MinecraftClient.getInstance(); - PlayerEntity player = minecraftClient.player; - ItemStack itemStackInHand = player.getMainHandStack(); - Block blockInHand = getBlockFromItem(itemStackInHand.getItem()); - BlockState stateInHand = blockInHand.getDefaultState(); - RenderLayer inHandRenderLayer = ;*/ - - - //stateInHand.getRenderingSeed - -} - - +/* + * package modchest.rendering; + * + * import net.minecraft.client.texture.AbstractTexture; + * import net.minecraft.client.texture.TextureManager; + * import net.minecraft.resource.ResourceManager; + * import net.minecraft.util.Identifier; + * + * public class gridBlockTexture extends TextureManager{ + * + * public gridBlockTexture(ResourceManager resourceManager) { + * super(resourceManager); + * //TODO Auto-generated constructor stub + * } + * + * @Override + * public AbstractTexture getTexture(Identifier id) { + * return super.getTexture(id); + * } + * + * public static BlockColors getBlockColors(Block block, BlockRenderView world, + * BlockPos pos, BlockColors blockColors) { + * BlockState state = block.getDefaultState(); + * // Verwende die Farbe für deine Zwecke + * BlockColors colors = getBlockColors(block, world, pos, blockColors); + * return colors; + * } + * + * public static Overlay getOverlayGrid(){ + * MinecraftClient minecraftClient = MinecraftClient.getInstance(); + * PlayerEntity player = minecraftClient.player; + * ItemStack itemStackInHand = player.getMainHandStack(); + * Block blockInHand = getBlockFromItem(itemStackInHand.getItem()); + * BlockState stateInHand = blockInHand.getDefaultState(); + * RenderLayer inHandRenderLayer = ; + * + * + * //stateInHand.getRenderingSeed + * + * } + */ diff --git a/src/client/java/modchest/transform/BaseApplier.java b/src/client/java/modchest/transform/BaseApplier.java index ed234d9..70d8e06 100644 --- a/src/client/java/modchest/transform/BaseApplier.java +++ b/src/client/java/modchest/transform/BaseApplier.java @@ -25,11 +25,11 @@ import net.minecraft.util.math.random.Random; @Environment(EnvType.CLIENT) public abstract class BaseApplier implements ToOptional { - public abstract TransformResult apply(MutableQuadView mqv, Direction dir, int index, Float4 vs, int color); + public abstract TransformResult apply(MutableQuadView mqv, Direction dir, int index, Float4 us,Float4 vs, int color); public static final BaseApplier NONE = new BaseApplier() { @Override - public TransformResult apply(MutableQuadView mqv, Direction dir, int index, Float4 vs, int color) { + public TransformResult apply(MutableQuadView mqv, Direction dir, int index, Float4 us,Float4 vs, int color) { return TransformResult.NOTHING_TO_DO; } @@ -57,8 +57,9 @@ public abstract class BaseApplier implements ToOptional { final Direction dir = ModelHelper.faceFromIndex(i); final List quads = model.getQuads(state, dir, r); final int size = quads.size(); + sizes.put(dir, size); - final SpriteApplier[] spriteAppliers = this.spriteAppliers.computeIfAbsent(dir, x -> new SpriteAppliers[size]); + final SpriteApplier[] spriteAppliers = this.spriteAppliers.computeIfAbsent(dir, x -> new SpriteApplier[size]); final MaterialApplier[] materialAppliers = this.materialAppliers.computeIfAbsent(dir, x -> new MaterialApplier[size]); final LazyColorApplier[] colorAppliers = this.colorAppliers.computeIfAbsent(dir, x -> new LazyColorApplier[size]); @@ -80,7 +81,7 @@ public abstract class BaseApplier implements ToOptional { } @Override - public TransformResult apply(MutableQuadView mqv, Direction dir, int quadIndex, Float4 vs, int color) { + public TransformResult apply(MutableQuadView mqv, Direction dir, int quadIndex, Float4 us, Float4 vs, int color) { int size = sizes.getInt(dir); if (size == 0) { return TransformResult.failed(String.format("No %s quads in model for %s", dir, state)); diff --git a/src/client/java/modchest/transform/MaterialApplier.java b/src/client/java/modchest/transform/MaterialApplier.java index 3d2f028..b2d176e 100644 --- a/src/client/java/modchest/transform/MaterialApplier.java +++ b/src/client/java/modchest/transform/MaterialApplier.java @@ -6,6 +6,8 @@ import javax.swing.text.html.Option; import org.jetbrains.annotations.NotNull; +import modchest.REServerMod; +import modchest.REServerModClient; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; diff --git a/src/client/java/modchest/transform/MaterialMap.java b/src/client/java/modchest/transform/MaterialMap.java new file mode 100644 index 0000000..58f9e0f --- /dev/null +++ b/src/client/java/modchest/transform/MaterialMap.java @@ -0,0 +1,34 @@ +package modchest.transform; + +public interface MaterialMap { + /** + * Used by renderer to avoid overhead of sprite reverse lookup when not needed. + * @return true if map is sprite-sensitive, false if always returns same material + */ + boolean needsSprite(); + + /** + * Returns null if sprite is unmapped or if this is the default material map. + */ + @Nullable RenderMaterial getMapped(@Nullable Sprite sprite); + + static MaterialMap get(BlockState state) { + return MaterialMapLoader.INSTANCE.get(state); + } + + static MaterialMap get(FluidState fluidState) { + return MaterialMapLoader.INSTANCE.get(fluidState); + } + + static MaterialMap getForParticle(ParticleType particleType) { + return MaterialMapLoader.INSTANCE.get(particleType); + } + + static MaterialMap defaultMaterialMap() { + return MaterialMapLoader.DEFAULT_MAP; + } + + static MaterialMap get(ItemStack itemStack) { + return MaterialMapLoader.INSTANCE.get(itemStack); + } +} \ No newline at end of file diff --git a/src/client/java/modchest/transform/MaterialMapLoader.java b/src/client/java/modchest/transform/MaterialMapLoader.java new file mode 100644 index 0000000..c1d1f13 --- /dev/null +++ b/src/client/java/modchest/transform/MaterialMapLoader.java @@ -0,0 +1,5 @@ +package modchest.transform; + +public class MaterialMapLoader { + +} diff --git a/src/client/java/modchest/transform/SpriteApplier.java b/src/client/java/modchest/transform/SpriteApplier.java index f7192fc..3021264 100644 --- a/src/client/java/modchest/transform/SpriteApplier.java +++ b/src/client/java/modchest/transform/SpriteApplier.java @@ -22,7 +22,6 @@ public abstract class SpriteApplier { } public abstract TransformResult apply(MutableQuadView mqv, Float4 us, Float4 vs); - public abstract Identifier id(); public static final SpriteApplier NONE = new SpriteApplier() { @@ -40,7 +39,7 @@ public abstract class SpriteApplier { public static class Some extends SpriteApplier { private final Sprite toApply; - public Some(final Sprite toApply) { + public Some(Sprite toApply) { this.toApply = toApply; } diff --git a/src/main/java/modchest/REServerMod.java b/src/main/java/modchest/REServerMod.java index d790df0..5d2b3c8 100644 --- a/src/main/java/modchest/REServerMod.java +++ b/src/main/java/modchest/REServerMod.java @@ -13,6 +13,7 @@ import modchest.grid.gridBlockEntityTypes; import modchest.grid.gridBlocks; import modchest.grid.gridItems; import modchest.grid.gridMeta; +import modchest.grid.gridProperties; import modchest.item.custom.SpecialItems; import modchest.util.initializer; @@ -21,7 +22,7 @@ public class REServerMod implements ModInitializer { public static final String MOD_ID = "modchest"; public static final Logger LOGGER = LoggerFactory.getLogger("modchest"); // Erster Error Logger - public static REServerModProperties PROPERTIES; + public static gridProperties PROPERTIES; public static SpecialItems SPECIAL_ITEMS; public static gridMeta META; @@ -38,10 +39,10 @@ public class REServerMod implements ModInitializer { initializer.events(); initializer.networking(); - PROPERTIES = new GridProperties(); + PROPERTIES = new gridProperties(); SPECIAL_ITEMS = new SpecialItems(); - META = new gridMeta() + META = new gridMeta(); BLOCKS = new gridBlocks(); ITEMS = new gridItems(); BLOCK_ENTITY_TYPES = new gridBlockEntityTypes(); diff --git a/src/main/java/modchest/block/custom/grid/gridSlab.java b/src/main/java/modchest/block/custom/grid/gridSlab.java index 93d6e13..5c289a2 100644 --- a/src/main/java/modchest/block/custom/grid/gridSlab.java +++ b/src/main/java/modchest/block/custom/grid/gridSlab.java @@ -4,6 +4,7 @@ import java.util.Properties; import javax.swing.text.html.BlockView; +import modchest.REServerMod; import modchest.block.entity.gridEntity; import modchest.grid.data.Sections; import net.minecraft.block.BlockEntityProvider; @@ -25,7 +26,7 @@ public class gridSlab extends SlabBlock implements gridSlotInfo, BlockEntityProv @Override public Sections sections() { - return META.GRID_SLAB_SECTIONS; + return REServerMod.META.GRID_SLAB_SECTIONS; } @Override @@ -74,8 +75,8 @@ public class gridSlab extends SlabBlock implements gridSlotInfo, BlockEntityProv } @Override - public BlockEntity createBlockEntity(final BlockView world) { - return new gridEntity(BLOCK_ENTITY_TYPES.GRID_SLAB, META.GRID_SLAB_SECTIONS); + public BlockEntity createBlockEntity(BlockView world) { + return new gridEntity(REServerMod.BLOCK_ENTITY_TYPES.GRID_SLAB, REServerMod.META.GRID_SLAB_SECTIONS); } @Override diff --git a/src/main/java/modchest/data/OverlayDataListener.java b/src/main/java/modchest/data/OverlayDataListener.java index 544a02f..4cf7655 100644 --- a/src/main/java/modchest/data/OverlayDataListener.java +++ b/src/main/java/modchest/data/OverlayDataListener.java @@ -15,6 +15,7 @@ import org.spongepowered.include.com.google.gson.JsonParseException; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import modchest.REServerMod; import net.fabricmc.fabric.api.resource.SimpleResourceReloadListener; import net.minecraft.item.ItemStack; import net.minecraft.recipe.Ingredient; @@ -67,7 +68,7 @@ public class OverlayDataListener implements SimpleResourceReloadListener[] baseStatesFromTag(final Sections sections, final ListTag tag) { + private static Optional[] baseStatesFromTag(final Sections sections, final ListTag tag) { final Optional[] baseStates = sections.makeBaseStates(); for (int i = 0, size = tag.size(); i < size; i++) { @@ -123,7 +129,7 @@ public class gridData { } public List, Optional>> toRenderAttachment() { - return Streams.zip(Arrays.stream(baseStates), overlayItems().stream().map(i -> i.flatMap(OVERLAYS::getOverlayId)), Pair::new).collect(Collectors.toList()); + return Streams.zip(Arrays.stream(baseStates), overlayItems().stream().map(i -> i.flatMap(REServerMod.OVERLAYS::getOverlayId)), Pair::new).collect(Collectors.toList()); } } diff --git a/src/main/java/modchest/grid/gridBlockEntityTypes.java b/src/main/java/modchest/grid/gridBlockEntityTypes.java index ed0b2d9..7e70b59 100644 --- a/src/main/java/modchest/grid/gridBlockEntityTypes.java +++ b/src/main/java/modchest/grid/gridBlockEntityTypes.java @@ -1,5 +1,6 @@ package modchest.grid; +import modchest.REServerMod; import modchest.block.entity.gridEntity; import net.minecraft.block.entity.BlockEntityType; import net.minecraft.util.registry.Registry; @@ -11,26 +12,26 @@ public class gridBlockEntityTypes extends Registrar> { public final BlockEntityType GRID = register( BlockEntityType.Builder.create( - () -> new gridEntity(this.GRID, META.GRID_SECTIONS), - BLOCKS.GRID_BLOCK, - BLOCK.GRID_STAIRS, - BLOCK.GRID_FENCE, - BLOCK.GRID_FENCE_GATE, - BLOCKS.GRID_TRAPDOOR, - BLOCKS.GRID_DOOR, - BLOCKS.GRID_PATH, - BLOCKS.GRID_TORCH, - BLOCKS.GRID_WALL_TORCH, - BLOCKS.GRID_PRESSURE_PLATE, - BLOCKS.GRID_WALL, - BLOCKS.GRID_LAYER, - BLOCKS.GRID_CARPET, - BLOCKS.GRID_PANE).build(null), - META.id("frame")); + () -> new gridEntity(this.GRID, REServerMod.META.GRID_SECTIONS), + REServerMod.BLOCKS.GRID_BLOCK, + REServerMod.BLOCKS.GRID_STAIRS, + REServerMod.BLOCKS.GRID_FENCE, + REServerMod.BLOCKS.GRID_FENCE_GATE, + REServerMod.BLOCKS.GRID_TRAPDOOR, + REServerMod.BLOCKS.GRID_DOOR, + REServerMod.BLOCKS.GRID_PATH, + REServerMod.BLOCKS.GRID_TORCH, + REServerMod.BLOCKS.GRID_WALL_TORCH, + REServerMod.BLOCKS.GRID_PRESSURE_PLATE, + REServerMod.BLOCKS.GRID_WALL, + REServerMod.BLOCKS.GRID_LAYER, + REServerMod.BLOCKS.GRID_CARPET, + REServerMod.BLOCKS.GRID_PANE).build(null), + REServerMod.META.id("frame")); public final BlockEntityType GRID_SLAB = register( BlockEntityType.Builder.create( - () -> new gridEntity(this.GRID_SLAB, META.GRID_SLAB_SECTIONS), - BLOCKS.GRID_SLAB).build(null), - META.id("grid_slab")); + () -> new gridEntity(this.GRID_SLAB, REServerMod.META.GRID_SLAB_SECTIONS), + REServerMod.BLOCKS.GRID_SLAB).build(null), + REServerMod.META.id("grid_slab")); } diff --git a/src/main/java/modchest/grid/gridMeta.java b/src/main/java/modchest/grid/gridMeta.java index 4488e2d..7acf163 100644 --- a/src/main/java/modchest/grid/gridMeta.java +++ b/src/main/java/modchest/grid/gridMeta.java @@ -19,14 +19,13 @@ public class gridMeta { public Identifier id(final String path) { return new Identifier(NAMESPACE, path); } - - public final Logger LOGGER = LogManager.getLogger("grid"); + public final Logger LOGGER = LogManager.getLogManager().getLogger("grid"); @SuppressWarnings("deprecation") - public final ScreenHandlerType GRID_SCREEN_HANDLER_TYPE = ScreenHandlerRegistry - .registerExtended(id("grid"), - (syncId, inventory, buf) -> new gridGuiDescription(syncId, inventory, - ScreenHandlerContext.create(inventory.player.world, buf.readBlockPos()))); + public final ScreenHandlerType GRID_SCREEN_HANDLER_TYPE = + ScreenHandlerRegistry.registerExtended( + id("grid"), + (syncId, inventory, buf) -> new gridGuiDescription(syncId, inventory, ScreenHandlerContext.create(inventory.player.world, buf.readBlockPos()))); public final Sections GRID_SECTIONS = new Sections(1); public final Sections GRID_SLAB_SECTIONS = new Sections(2); diff --git a/src/main/java/modchest/mixin/local/SinglePartGridBlock.java b/src/main/java/modchest/mixin/local/SinglePartGridBlock.java index 9bcd119..8ae09ee 100644 --- a/src/main/java/modchest/mixin/local/SinglePartGridBlock.java +++ b/src/main/java/modchest/mixin/local/SinglePartGridBlock.java @@ -2,6 +2,7 @@ package modchest.mixin.local; import org.spongepowered.asm.mixin.Mixin; +import modchest.REServerMod; import modchest.block.custom.grid.gridBlock; import modchest.block.custom.grid.gridCarpet; import modchest.block.custom.grid.gridDoor; @@ -48,7 +49,7 @@ public class SinglePartGridBlock implements gridSlotInfo { @Override public Sections sections() { - return META.GRID_SECTIONS; + return REServerMod.META.GRID_SECTIONS; } @Override diff --git a/src/main/java/modchest/mixin/local/gridBehaviour.java b/src/main/java/modchest/mixin/local/gridBehaviour.java index 8991a93..45f9a6e 100644 --- a/src/main/java/modchest/mixin/local/gridBehaviour.java +++ b/src/main/java/modchest/mixin/local/gridBehaviour.java @@ -18,6 +18,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import com.mojang.datafixers.util.Function3; +import modchest.REServerMod; import modchest.block.custom.grid.grid; import modchest.block.custom.grid.gridBlock; import modchest.block.custom.grid.gridCarpet; @@ -110,14 +111,14 @@ public abstract class gridBehaviour extends Block implements BlockEntityProvider @SuppressWarnings("deprecation") @Override public boolean emitsRedstonePower(final BlockState state) { - return super.emitsRedstonePower(state) || state.get(PROPERTIES.HAS_REDSTONE); + return super.emitsRedstonePower(state) || state.get(REServerMod.PROPERTIES.HAS_REDSTONE); } @SuppressWarnings("deprecation") @Override public int getWeakRedstonePower(BlockState state, net.minecraft.world.BlockView world, BlockPos pos, Direction direction) { - if (state.get(PROPERTIES.HAS_REDSTONE)) { + if (state.get(REServerMod.PROPERTIES.HAS_REDSTONE)) { return 15 - super.getWeakRedstonePower(state, world, pos, direction) } else { return super.getWeakRedstonePower(state, world, pos, direction); @@ -187,7 +188,7 @@ public abstract class gridBehaviour extends Block implements BlockEntityProvider final @Nullable PlayerEntity player = breaker; if (player != null) { - if (player.getStackInHand(player.getActiveHand()).getItem() == ITEMS.GRID_HAMMER) { + if (player.getStackInHand(player.getActiveHand()).getItem() == REServerMod.ITEMS.HAMMER) { onHammerRemoved(world, (gridEntity) blockEntity, oldState, player, false); } else { super.onStateReplaced(oldState, world, pos, newState, moved); @@ -196,7 +197,7 @@ public abstract class gridBehaviour extends Block implements BlockEntityProvider if (blockEntity instanceof Inventory) { ItemScatterer.spawn(world, pos, (Inventory) blockEntity); } - super.onStateReplaced(state, world, pos, newState, moved); + super.onStateReplaced(oldState, world, pos, newState, moved); } } @@ -280,7 +281,7 @@ public abstract class gridBehaviour extends Block implements BlockEntityProvider } if (query.isValidForSpecial()) { - final SpecialItems.SpecialItem specialItem = SPECIAL_ITEM.Map.get(playerStack.getItem()); + final SpecialItems.SpecialItem specialItem = REServerMod.SPECIAL_ITEMS.MAP.get(playerStack.getItem()); final int slot = grid.sections().special().makeAbsolute(specialItem.offset()); if (grid.getStack(slot).isEmpty()) { @@ -307,7 +308,7 @@ public abstract class gridBehaviour extends Block implements BlockEntityProvider if (placer instanceof PlayerEntity) { final PlayerEntity player = (PlayerEntity) placer; - if (player.getOffHandStack().getItem() != ITEMS.GRID_HAMMER || player.getOffHandStack().getTag() == null) { + if (player.getOffHandStack().getItem() != REServerMod.ITEMS.HAMMER || player.getOffHandStack().getTag() == null) { tryCopy = false; } else { final BlockEntity blockEntity = world.getBlockEntity(pos); diff --git a/src/main/java/modchest/mixin/local/gridEntityProvider.java b/src/main/java/modchest/mixin/local/gridEntityProvider.java index b0d6a9f..03e09fb 100644 --- a/src/main/java/modchest/mixin/local/gridEntityProvider.java +++ b/src/main/java/modchest/mixin/local/gridEntityProvider.java @@ -3,6 +3,7 @@ package modchest.mixin.local; import org.jetbrains.annotations.Nullable; import org.spongepowered.asm.mixin.Mixin; +import modchest.REServerMod; import modchest.block.custom.grid.gridBlock; import modchest.block.custom.grid.gridCarpet; import modchest.block.custom.grid.gridDoor; @@ -49,7 +50,7 @@ public class gridEntityProvider implements BlockEntityProvider { @Override public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { - return new gridEntity(BLOCK_ENTITY_TYPES.GRID, META.FRAME_SECTIONS); + return new gridEntity(REServerMod.BLOCK_ENTITY_TYPES.GRID, REServerMod.META.GRID_SECTIONS); } } diff --git a/src/main/java/modchest/mixin/mc/WallBlockMixin.java b/src/main/java/modchest/mixin/mc/WallBlockMixin.java index 7f6beee..9c24eba 100644 --- a/src/main/java/modchest/mixin/mc/WallBlockMixin.java +++ b/src/main/java/modchest/mixin/mc/WallBlockMixin.java @@ -47,8 +47,8 @@ public class WallBlockMixin extends Block { throw new IllegalStateException("Shadow method should not run."); } - @SuppressWarnings("DuplicatedCode") - @Override + + @SuppressWarnings("unused") private Map getShapeMap(float f, float g, float h, float i, float j, float k) { float l = 8.0F - f; float m = 8.0F + f; diff --git a/src/main/java/modchest/networking/packet/gridBlockS2CPacket.java b/src/main/java/modchest/networking/packet/gridBlockS2CPacket.java index 162846a..e386192 100644 --- a/src/main/java/modchest/networking/packet/gridBlockS2CPacket.java +++ b/src/main/java/modchest/networking/packet/gridBlockS2CPacket.java @@ -1,4 +1,4 @@ -package modchest.networking.packet; +/*package modchest.networking.packet; import net.minecraft.network.PacketByteBuf; import net.minecraft.server.network.ServerPlayerEntity; @@ -12,4 +12,4 @@ public class gridBlockS2CPacket { //PacketByteBuf gridBuffer = gridBlock.writeBuffer(hitResult); //ServerPlayNetworking.send(serverPlayerEntity, modNetworkingServer.grid_block_networking, gridBuffer); } -} +}*/ diff --git a/src/main/java/modchest/util/GuiUtil.java b/src/main/java/modchest/util/GuiUtil.java index 328dc55..08f51b1 100644 --- a/src/main/java/modchest/util/GuiUtil.java +++ b/src/main/java/modchest/util/GuiUtil.java @@ -1,4 +1,4 @@ -package modchest.util; +/*package modchest.util; import org.intellij.lang.annotations.JdkConstants.HorizontalAlignment; import org.spongepowered.asm.util.perf.Profiler.Section; @@ -26,4 +26,4 @@ public enum GuiUtil { final Section section) { return constructor.apply(inventory, section.start(), section.size(), 1, false); } -} +}*/ diff --git a/src/main/java/modchest/util/ValidQuery.java b/src/main/java/modchest/util/ValidQuery.java index 5d3938e..9849440 100644 --- a/src/main/java/modchest/util/ValidQuery.java +++ b/src/main/java/modchest/util/ValidQuery.java @@ -3,6 +3,8 @@ package modchest.util; import java.util.Optional; import java.util.function.Function; +import modchest.REServerMod; +import modchest.block.custom.grid.grid; import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.BlockRenderType; import net.minecraft.block.BlockState; @@ -39,11 +41,11 @@ public class ValidQuery { } public boolean isValidForOverlay () { - return OVERLAYS.hasOverlay(stack); + return REServerMod.OVERLAYS.hasOverlay(stack); } public boolean isValidForSpecial() { - return SPECIAL_ITEMS.Map.containsKey(stack.getItem()); + return REServerMod.SPECIAL_ITEMS.MAP.containsKey(stack.getItem()); } } diff --git a/src/main/java/modchest/util/nbt/ArrayTag.java b/src/main/java/modchest/util/nbt/ArrayTag.java new file mode 100644 index 0000000..b46676f --- /dev/null +++ b/src/main/java/modchest/util/nbt/ArrayTag.java @@ -0,0 +1,46 @@ +package modchest.util.nbt; + +import java.lang.reflect.Array; + +/** + * ArrayTag is an abstract representation of any NBT array tag. + * For implementations see {@link ByteArrayTag}, {@link IntArrayTag}, {@link LongArrayTag}. + * @param The array type. + * */ +public abstract class ArrayTag extends Tag { + + public ArrayTag(T value) { + super(value); + if (!value.getClass().isArray()) { + throw new UnsupportedOperationException("type of array tag must be an array"); + } + } + + public int length() { + return Array.getLength(getValue()); + } + + @Override + public T getValue() { + return super.getValue(); + } + + @Override + public void setValue(T value) { + super.setValue(value); + } + + @Override + public String valueToString(int maxDepth) { + return arrayToString("", ""); + } + + protected String arrayToString(String prefix, String suffix) { + StringBuilder sb = new StringBuilder("[").append(prefix).append("".equals(prefix) ? "" : ";"); + for (int i = 0; i < length(); i++) { + sb.append(i == 0 ? "" : ",").append(Array.get(getValue(), i)).append(suffix); + } + sb.append("]"); + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/modchest/util/nbt/ByteArrayTag.java b/src/main/java/modchest/util/nbt/ByteArrayTag.java new file mode 100644 index 0000000..13f1121 --- /dev/null +++ b/src/main/java/modchest/util/nbt/ByteArrayTag.java @@ -0,0 +1,42 @@ +package modchest.util.nbt; + +import java.util.Arrays; + +public class ByteArrayTag extends ArrayTag implements Comparable { + + public static final byte ID = 7; + public static final byte[] ZERO_VALUE = new byte[0]; + + public ByteArrayTag() { + super(ZERO_VALUE); + } + + public ByteArrayTag(byte[] value) { + super(value); + } + + @Override + public byte getID() { + return ID; + } + + @Override + public boolean equals(Object other) { + return super.equals(other) && Arrays.equals(getValue(), ((ByteArrayTag) other).getValue()); + } + + @Override + public int hashCode() { + return Arrays.hashCode(getValue()); + } + + @Override + public int compareTo(ByteArrayTag other) { + return Integer.compare(length(), other.length()); + } + + @Override + public ByteArrayTag clone() { + return new ByteArrayTag(Arrays.copyOf(getValue(), length())); + } +} \ No newline at end of file diff --git a/src/main/java/modchest/util/nbt/ByteTag.java b/src/main/java/modchest/util/nbt/ByteTag.java new file mode 100644 index 0000000..333c16b --- /dev/null +++ b/src/main/java/modchest/util/nbt/ByteTag.java @@ -0,0 +1,47 @@ +package modchest.util.nbt; + +public class ByteTag extends NumberTag implements Comparable { + + public static final byte ID = 1; + public static final byte ZERO_VALUE = 0; + + public ByteTag() { + super(ZERO_VALUE); + } + + public ByteTag(byte value) { + super(value); + } + + public ByteTag(boolean value) { + super((byte) (value ? 1 : 0)); + } + + @Override + public byte getID() { + return ID; + } + + public boolean asBoolean() { + return getValue() > 0; + } + + public void setValue(byte value) { + super.setValue(value); + } + + @Override + public boolean equals(Object other) { + return super.equals(other) && asByte() == ((ByteTag) other).asByte(); + } + + @Override + public int compareTo(ByteTag other) { + return getValue().compareTo(other.getValue()); + } + + @Override + public ByteTag clone() { + return new ByteTag(getValue()); + } +} \ No newline at end of file diff --git a/src/main/java/modchest/util/nbt/CompoundTag.java b/src/main/java/modchest/util/nbt/CompoundTag.java new file mode 100644 index 0000000..c66b8b3 --- /dev/null +++ b/src/main/java/modchest/util/nbt/CompoundTag.java @@ -0,0 +1,299 @@ +package modchest.util.nbt; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.BiConsumer; + +import modchest.util.nbt.io.MaxDepthIO; + +public class CompoundTag extends Tag>> + implements Iterable>>, Comparable, MaxDepthIO { + + public static final byte ID = 10; + + public CompoundTag() { + super(createEmptyValue()); + } + + public CompoundTag(int initialCapacity) { + super(new HashMap<>(initialCapacity)); + } + + @Override + public byte getID() { + return ID; + } + + private static Map> createEmptyValue() { + return new HashMap<>(8); + } + + public int size() { + return getValue().size(); + } + + public Tag remove(String key) { + return getValue().remove(key); + } + + public void clear() { + getValue().clear(); + } + + public boolean containsKey(String key) { + return getValue().containsKey(key); + } + + public boolean containsValue(Tag value) { + return getValue().containsValue(value); + } + + public Collection> values() { + return getValue().values(); + } + + public Set keySet() { + return getValue().keySet(); + } + + public Set>> entrySet() { + return new NonNullEntrySet<>(getValue().entrySet()); + } + + @Override + public Iterator>> iterator() { + return entrySet().iterator(); + } + + public void forEach(BiConsumer> action) { + getValue().forEach(action); + } + + public > C get(String key, Class type) { + Tag t = getValue().get(key); + if (t != null) { + return type.cast(t); + } + return null; + } + + public Tag get(String key) { + return getValue().get(key); + } + + public NumberTag getNumberTag(String key) { + return (NumberTag) getValue().get(key); + } + + public Number getNumber(String key) { + return getNumberTag(key).getValue(); + } + + public ByteTag getByteTag(String key) { + return get(key, ByteTag.class); + } + + public ShortTag getShortTag(String key) { + return get(key, ShortTag.class); + } + + public IntTag getIntTag(String key) { + return get(key, IntTag.class); + } + + public LongTag getLongTag(String key) { + return get(key, LongTag.class); + } + + public FloatTag getFloatTag(String key) { + return get(key, FloatTag.class); + } + + public DoubleTag getDoubleTag(String key) { + return get(key, DoubleTag.class); + } + + public StringTag getStringTag(String key) { + return get(key, StringTag.class); + } + + public ByteArrayTag getByteArrayTag(String key) { + return get(key, ByteArrayTag.class); + } + + public IntArrayTag getIntArrayTag(String key) { + return get(key, IntArrayTag.class); + } + + public LongArrayTag getLongArrayTag(String key) { + return get(key, LongArrayTag.class); + } + + public ListTag getListTag(String key) { + return get(key, ListTag.class); + } + + public CompoundTag getCompoundTag(String key) { + return get(key, CompoundTag.class); + } + + public boolean getBoolean(String key) { + Tag t = get(key); + return t instanceof ByteTag && ((ByteTag) t).asByte() > 0; + } + + public byte getByte(String key) { + ByteTag t = getByteTag(key); + return t == null ? ByteTag.ZERO_VALUE : t.asByte(); + } + + public short getShort(String key) { + ShortTag t = getShortTag(key); + return t == null ? ShortTag.ZERO_VALUE : t.asShort(); + } + + public int getInt(String key) { + IntTag t = getIntTag(key); + return t == null ? IntTag.ZERO_VALUE : t.asInt(); + } + + public long getLong(String key) { + LongTag t = getLongTag(key); + return t == null ? LongTag.ZERO_VALUE : t.asLong(); + } + + public float getFloat(String key) { + FloatTag t = getFloatTag(key); + return t == null ? FloatTag.ZERO_VALUE : t.asFloat(); + } + + public double getDouble(String key) { + DoubleTag t = getDoubleTag(key); + return t == null ? DoubleTag.ZERO_VALUE : t.asDouble(); + } + + public String getString(String key) { + StringTag t = getStringTag(key); + return t == null ? StringTag.ZERO_VALUE : t.getValue(); + } + + public byte[] getByteArray(String key) { + ByteArrayTag t = getByteArrayTag(key); + return t == null ? ByteArrayTag.ZERO_VALUE : t.getValue(); + } + + public int[] getIntArray(String key) { + IntArrayTag t = getIntArrayTag(key); + return t == null ? IntArrayTag.ZERO_VALUE : t.getValue(); + } + + public long[] getLongArray(String key) { + LongArrayTag t = getLongArrayTag(key); + return t == null ? LongArrayTag.ZERO_VALUE : t.getValue(); + } + + public Tag put(String key, Tag tag) { + return getValue().put(Objects.requireNonNull(key), Objects.requireNonNull(tag)); + } + + public Tag putIfNotNull(String key, Tag tag) { + if (tag == null) { + return this; + } + return put(key, tag); + } + + public Tag putBoolean(String key, boolean value) { + return put(key, new ByteTag(value)); + } + + public Tag putByte(String key, byte value) { + return put(key, new ByteTag(value)); + } + + public Tag putShort(String key, short value) { + return put(key, new ShortTag(value)); + } + + public Tag putInt(String key, int value) { + return put(key, new IntTag(value)); + } + + public Tag putLong(String key, long value) { + return put(key, new LongTag(value)); + } + + public Tag putFloat(String key, float value) { + return put(key, new FloatTag(value)); + } + + public Tag putDouble(String key, double value) { + return put(key, new DoubleTag(value)); + } + + public Tag putString(String key, String value) { + return put(key, new StringTag(value)); + } + + public Tag putByteArray(String key, byte[] value) { + return put(key, new ByteArrayTag(value)); + } + + public Tag putIntArray(String key, int[] value) { + return put(key, new IntArrayTag(value)); + } + + public Tag putLongArray(String key, long[] value) { + return put(key, new LongArrayTag(value)); + } + + @Override + public String valueToString(int maxDepth) { + StringBuilder sb = new StringBuilder("{"); + boolean first = true; + for (Map.Entry> e : getValue().entrySet()) { + sb.append(first ? "" : ",") + .append(escapeString(e.getKey(), false)).append(":") + .append(e.getValue().toString(decrementMaxDepth(maxDepth))); + first = false; + } + sb.append("}"); + return sb.toString(); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!super.equals(other) || size() != ((CompoundTag) other).size()) { + return false; + } + for (Map.Entry> e : getValue().entrySet()) { + Tag v; + if ((v = ((CompoundTag) other).get(e.getKey())) == null || !e.getValue().equals(v)) { + return false; + } + } + return true; + } + + @Override + public int compareTo(CompoundTag o) { + return Integer.compare(size(), o.getValue().size()); + } + + @Override + public CompoundTag clone() { + // Choose initial capacity based on default load factor (0.75) so all entries fit in map without resizing + CompoundTag copy = new CompoundTag((int) Math.ceil(getValue().size() / 0.75f)); + for (Map.Entry> e : getValue().entrySet()) { + copy.put(e.getKey(), e.getValue().clone()); + } + return copy; + } +} \ No newline at end of file diff --git a/src/main/java/modchest/util/nbt/DoubleTag.java b/src/main/java/modchest/util/nbt/DoubleTag.java new file mode 100644 index 0000000..0bf3c00 --- /dev/null +++ b/src/main/java/modchest/util/nbt/DoubleTag.java @@ -0,0 +1,39 @@ +package modchest.util.nbt; + +public class DoubleTag extends NumberTag implements Comparable { + + public static final byte ID = 6; + public static final double ZERO_VALUE = 0.0D; + + public DoubleTag() { + super(ZERO_VALUE); + } + + public DoubleTag(double value) { + super(value); + } + + @Override + public byte getID() { + return ID; + } + + public void setValue(double value) { + super.setValue(value); + } + + @Override + public boolean equals(Object other) { + return super.equals(other) && getValue().equals(((DoubleTag) other).getValue()); + } + + @Override + public int compareTo(DoubleTag other) { + return getValue().compareTo(other.getValue()); + } + + @Override + public DoubleTag clone() { + return new DoubleTag(getValue()); + } +} \ No newline at end of file diff --git a/src/main/java/modchest/util/nbt/EndTag.java b/src/main/java/modchest/util/nbt/EndTag.java new file mode 100644 index 0000000..b2d5071 --- /dev/null +++ b/src/main/java/modchest/util/nbt/EndTag.java @@ -0,0 +1,31 @@ +package modchest.util.nbt; + +public final class EndTag extends Tag { + + public static final byte ID = 0; + public static final EndTag INSTANCE = new EndTag(); + + private EndTag() { + super(null); + } + + @Override + public byte getID() { + return ID; + } + + @Override + protected Void checkValue(Void value) { + return value; + } + + @Override + public String valueToString(int maxDepth) { + return "\"end\""; + } + + @Override + public EndTag clone() { + return INSTANCE; + } +} \ No newline at end of file diff --git a/src/main/java/modchest/util/nbt/FloatTag.java b/src/main/java/modchest/util/nbt/FloatTag.java new file mode 100644 index 0000000..c6cf316 --- /dev/null +++ b/src/main/java/modchest/util/nbt/FloatTag.java @@ -0,0 +1,39 @@ +package modchest.util.nbt; + +public class FloatTag extends NumberTag implements Comparable { + + public static final byte ID = 5; + public static final float ZERO_VALUE = 0.0F; + + public FloatTag() { + super(ZERO_VALUE); + } + + public FloatTag(float value) { + super(value); + } + + @Override + public byte getID() { + return ID; + } + + public void setValue(float value) { + super.setValue(value); + } + + @Override + public boolean equals(Object other) { + return super.equals(other) && getValue().equals(((FloatTag) other).getValue()); + } + + @Override + public int compareTo(FloatTag other) { + return getValue().compareTo(other.getValue()); + } + + @Override + public FloatTag clone() { + return new FloatTag(getValue()); + } +} \ No newline at end of file diff --git a/src/main/java/modchest/util/nbt/IntArrayTag.java b/src/main/java/modchest/util/nbt/IntArrayTag.java new file mode 100644 index 0000000..8fc6560 --- /dev/null +++ b/src/main/java/modchest/util/nbt/IntArrayTag.java @@ -0,0 +1,42 @@ +package modchest.util.nbt; + +import java.util.Arrays; + +public class IntArrayTag extends ArrayTag implements Comparable { + + public static final byte ID = 11; + public static final int[] ZERO_VALUE = new int[0]; + + public IntArrayTag() { + super(ZERO_VALUE); + } + + public IntArrayTag(int[] value) { + super(value); + } + + @Override + public byte getID() { + return ID; + } + + @Override + public boolean equals(Object other) { + return super.equals(other) && Arrays.equals(getValue(), ((IntArrayTag) other).getValue()); + } + + @Override + public int hashCode() { + return Arrays.hashCode(getValue()); + } + + @Override + public int compareTo(IntArrayTag other) { + return Integer.compare(length(), other.length()); + } + + @Override + public IntArrayTag clone() { + return new IntArrayTag(Arrays.copyOf(getValue(), length())); + } +} \ No newline at end of file diff --git a/src/main/java/modchest/util/nbt/IntTag.java b/src/main/java/modchest/util/nbt/IntTag.java new file mode 100644 index 0000000..4ce97cd --- /dev/null +++ b/src/main/java/modchest/util/nbt/IntTag.java @@ -0,0 +1,39 @@ +package modchest.util.nbt; + +public class IntTag extends NumberTag implements Comparable { + + public static final byte ID = 3; + public static final int ZERO_VALUE = 0; + + public IntTag() { + super(ZERO_VALUE); + } + + public IntTag(int value) { + super(value); + } + + @Override + public byte getID() { + return ID; + } + + public void setValue(int value) { + super.setValue(value); + } + + @Override + public boolean equals(Object other) { + return super.equals(other) && asInt() == ((IntTag) other).asInt(); + } + + @Override + public int compareTo(IntTag other) { + return getValue().compareTo(other.getValue()); + } + + @Override + public IntTag clone() { + return new IntTag(getValue()); + } +} diff --git a/src/main/java/modchest/util/nbt/ListTag.java b/src/main/java/modchest/util/nbt/ListTag.java new file mode 100644 index 0000000..b109583 --- /dev/null +++ b/src/main/java/modchest/util/nbt/ListTag.java @@ -0,0 +1,350 @@ +package modchest.util.nbt; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; + +import modchest.util.nbt.io.MaxDepthIO; + +/** + * ListTag represents a typed List in the nbt structure. + * An empty {@link ListTag} will be of type {@link EndTag} (unknown type). + * The type of an empty untyped {@link ListTag} can be set by using any of the {@code add()} + * methods or any of the {@code as...List()} methods. + */ +public class ListTag> extends Tag> implements Iterable, Comparable>, MaxDepthIO { + + public static final byte ID = 9; + + private Class typeClass = null; + + private ListTag(int initialCapacity) { + super(createEmptyValue(initialCapacity)); + } + + @Override + public byte getID() { + return ID; + } + + /** + *

Creates a non-type-safe ListTag. Its element type will be set after the first + * element was added.

+ * + *

This is an internal helper method for cases where the element type is not known + * at construction time. Use {@link #ListTag(Class)} when the type is known.

+ * + * @return A new non-type-safe ListTag + */ + public static ListTag createUnchecked(Class typeClass) { + return createUnchecked(typeClass, 3); + } + + /** + *

Creates a non-type-safe ListTag. Its element type will be set after the first + * element was added.

+ * + *

This is an internal helper method for cases where the element type is not known + * at construction time. Use {@link #ListTag(Class)} when the type is known.

+ * + * @return A new non-type-safe ListTag + */ + public static ListTag createUnchecked(Class typeClass, int initialCapacity) { + ListTag list = new ListTag<>(initialCapacity); + list.typeClass = typeClass; + return list; + } + + /** + *

Creates an empty mutable list to be used as empty value of ListTags.

+ * + * @param Type of the list elements + * @param initialCapacity The initial capacity of the returned List + * @return An instance of {@link java.util.List} with an initial capacity of 3 + */ + private static List createEmptyValue(int initialCapacity) { + return new ArrayList<>(initialCapacity); + } + + /** + * @param typeClass The exact class of the elements + * @throws IllegalArgumentException When {@code typeClass} is {@link EndTag}{@code .class} + * @throws NullPointerException When {@code typeClass} is {@code null} + */ + public ListTag(Class typeClass) throws IllegalArgumentException, NullPointerException { + this(typeClass, 3); + } + + /** + * @param typeClass The exact class of the elements + * @param initialCapacity Initial capacity of list + * @throws IllegalArgumentException When {@code typeClass} is {@link EndTag}{@code .class} + * @throws NullPointerException When {@code typeClass} is {@code null} + */ + public ListTag(Class typeClass, int initialCapacity) throws IllegalArgumentException, NullPointerException { + super(createEmptyValue(initialCapacity)); + if (typeClass == EndTag.class) { + throw new IllegalArgumentException("cannot create ListTag with EndTag elements"); + } + this.typeClass = Objects.requireNonNull(typeClass); + } + + public Class getTypeClass() { + return typeClass == null ? EndTag.class : typeClass; + } + + public int size() { + return getValue().size(); + } + + public T remove(int index) { + return getValue().remove(index); + } + + public void clear() { + getValue().clear(); + } + + public boolean contains(T t) { + return getValue().contains(t); + } + + public boolean containsAll(Collection> tags) { + return getValue().containsAll(tags); + } + + public void sort(Comparator comparator) { + getValue().sort(comparator); + } + + @Override + public Iterator iterator() { + return getValue().iterator(); + } + + @Override + public void forEach(Consumer action) { + getValue().forEach(action); + } + + public T set(int index, T t) { + return getValue().set(index, Objects.requireNonNull(t)); + } + + /** + * Adds a Tag to this ListTag after the last index. + * + * @param t The element to be added. + */ + public void add(T t) { + add(size(), t); + } + + public void add(int index, T t) { + Objects.requireNonNull(t); + if (getTypeClass() == EndTag.class) { + typeClass = t.getClass(); + } else if (typeClass != t.getClass()) { + throw new ClassCastException( + String.format("cannot add %s to ListTag<%s>", + t.getClass().getSimpleName(), + typeClass.getSimpleName())); + } + getValue().add(index, t); + } + + public void addAll(Collection t) { + for (T tt : t) { + add(tt); + } + } + + public void addAll(int index, Collection t) { + int i = 0; + for (T tt : t) { + add(index + i, tt); + i++; + } + } + + public void addBoolean(boolean value) { + addUnchecked(new ByteTag(value)); + } + + public void addByte(byte value) { + addUnchecked(new ByteTag(value)); + } + + public void addShort(short value) { + addUnchecked(new ShortTag(value)); + } + + public void addInt(int value) { + addUnchecked(new IntTag(value)); + } + + public void addLong(long value) { + addUnchecked(new LongTag(value)); + } + + public void addFloat(float value) { + addUnchecked(new FloatTag(value)); + } + + public void addDouble(double value) { + addUnchecked(new DoubleTag(value)); + } + + public void addString(String value) { + addUnchecked(new StringTag(value)); + } + + public void addByteArray(byte[] value) { + addUnchecked(new ByteArrayTag(value)); + } + + public void addIntArray(int[] value) { + addUnchecked(new IntArrayTag(value)); + } + + public void addLongArray(long[] value) { + addUnchecked(new LongArrayTag(value)); + } + + public T get(int index) { + return getValue().get(index); + } + + public int indexOf(T t) { + return getValue().indexOf(t); + } + + @SuppressWarnings("unchecked") + public > ListTag asTypedList(Class type) { + checkTypeClass(type); + return (ListTag) this; + } + + public ListTag asByteTagList() { + return asTypedList(ByteTag.class); + } + + public ListTag asShortTagList() { + return asTypedList(ShortTag.class); + } + + public ListTag asIntTagList() { + return asTypedList(IntTag.class); + } + + public ListTag asLongTagList() { + return asTypedList(LongTag.class); + } + + public ListTag asFloatTagList() { + return asTypedList(FloatTag.class); + } + + public ListTag asDoubleTagList() { + return asTypedList(DoubleTag.class); + } + + public ListTag asStringTagList() { + return asTypedList(StringTag.class); + } + + public ListTag asByteArrayTagList() { + return asTypedList(ByteArrayTag.class); + } + + public ListTag asIntArrayTagList() { + return asTypedList(IntArrayTag.class); + } + + public ListTag asLongArrayTagList() { + return asTypedList(LongArrayTag.class); + } + + @SuppressWarnings("unchecked") + public ListTag> asListTagList() { + checkTypeClass(ListTag.class); + typeClass = ListTag.class; + return (ListTag>) this; + } + + public ListTag asCompoundTagList() { + return asTypedList(CompoundTag.class); + } + + @Override + public String valueToString(int maxDepth) { + StringBuilder sb = new StringBuilder("{\"type\":\"").append(getTypeClass().getSimpleName()).append("\",\"list\":["); + for (int i = 0; i < size(); i++) { + sb.append(i > 0 ? "," : "").append(get(i).valueToString(decrementMaxDepth(maxDepth))); + } + sb.append("]}"); + return sb.toString(); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!super.equals(other) || size() != ((ListTag) other).size() || getTypeClass() != ((ListTag) other) + .getTypeClass()) { + return false; + } + for (int i = 0; i < size(); i++) { + if (!get(i).equals(((ListTag) other).get(i))) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + return Objects.hash(getTypeClass().hashCode(), getValue().hashCode()); + } + + @Override + public int compareTo(ListTag o) { + return Integer.compare(size(), o.getValue().size()); + } + + @SuppressWarnings("unchecked") + @Override + public ListTag clone() { + ListTag copy = new ListTag<>(this.size()); + // assure type safety for clone + copy.typeClass = typeClass; + for (T t : getValue()) { + copy.add((T) t.clone()); + } + return copy; + } + + //TODO: make private + @SuppressWarnings("unchecked") + public void addUnchecked(Tag tag) { + if (getTypeClass() != EndTag.class && typeClass != tag.getClass()) { + throw new IllegalArgumentException(String.format( + "cannot add %s to ListTag<%s>", + tag.getClass().getSimpleName(), typeClass.getSimpleName())); + } + add(size(), (T) tag); + } + + private void checkTypeClass(Class clazz) { + if (getTypeClass() != EndTag.class && typeClass != clazz) { + throw new ClassCastException(String.format( + "cannot cast ListTag<%s> to ListTag<%s>", + typeClass.getSimpleName(), clazz.getSimpleName())); + } + } +} \ No newline at end of file diff --git a/src/main/java/modchest/util/nbt/LongArrayTag.java b/src/main/java/modchest/util/nbt/LongArrayTag.java new file mode 100644 index 0000000..40ed9a5 --- /dev/null +++ b/src/main/java/modchest/util/nbt/LongArrayTag.java @@ -0,0 +1,42 @@ +package modchest.util.nbt; + +import java.util.Arrays; + +public class LongArrayTag extends ArrayTag implements Comparable { + + public static final byte ID = 12; + public static final long[] ZERO_VALUE = new long[0]; + + public LongArrayTag() { + super(ZERO_VALUE); + } + + public LongArrayTag(long[] value) { + super(value); + } + + @Override + public byte getID() { + return ID; + } + + @Override + public boolean equals(Object other) { + return super.equals(other) && Arrays.equals(getValue(), ((LongArrayTag) other).getValue()); + } + + @Override + public int hashCode() { + return Arrays.hashCode(getValue()); + } + + @Override + public int compareTo(LongArrayTag other) { + return Integer.compare(length(), other.length()); + } + + @Override + public LongArrayTag clone() { + return new LongArrayTag(Arrays.copyOf(getValue(), length())); + } +} diff --git a/src/main/java/modchest/util/nbt/LongTag.java b/src/main/java/modchest/util/nbt/LongTag.java new file mode 100644 index 0000000..c5ed8b3 --- /dev/null +++ b/src/main/java/modchest/util/nbt/LongTag.java @@ -0,0 +1,39 @@ +package modchest.util.nbt; + +public class LongTag extends NumberTag implements Comparable { + + public static final byte ID = 4; + public static final long ZERO_VALUE = 0L; + + public LongTag() { + super(ZERO_VALUE); + } + + public LongTag(long value) { + super(value); + } + + @Override + public byte getID() { + return ID; + } + + public void setValue(long value) { + super.setValue(value); + } + + @Override + public boolean equals(Object other) { + return super.equals(other) && asLong() == ((LongTag) other).asLong(); + } + + @Override + public int compareTo(LongTag other) { + return getValue().compareTo(other.getValue()); + } + + @Override + public LongTag clone() { + return new LongTag(getValue()); + } +} \ No newline at end of file diff --git a/src/main/java/modchest/util/nbt/NonNullEntrySet.java b/src/main/java/modchest/util/nbt/NonNullEntrySet.java new file mode 100644 index 0000000..167afa8 --- /dev/null +++ b/src/main/java/modchest/util/nbt/NonNullEntrySet.java @@ -0,0 +1,140 @@ +package modchest.util.nbt; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * A decorator for the Set returned by CompoundTag#entrySet() + * that disallows setting null values. + * */ +class NonNullEntrySet implements Set> { + + private Set> set; + + NonNullEntrySet(Set> set) { + this.set = set; + } + + @Override + public int size() { + return set.size(); + } + + @Override + public boolean isEmpty() { + return set.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return set.contains(o); + } + + @Override + public Iterator> iterator() { + return new NonNullEntrySetIterator(set.iterator()); + } + + @Override + public Object[] toArray() { + return set.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return set.toArray(a); + } + + @Override + public boolean add(Map.Entry kvEntry) { + return set.add(kvEntry); + } + + @Override + public boolean remove(Object o) { + return set.remove(o); + } + + @Override + public boolean containsAll(Collection c) { + return set.containsAll(c); + } + + @Override + public boolean addAll(Collection> c) { + return set.addAll(c); + } + + @Override + public boolean retainAll(Collection c) { + return set.retainAll(c); + } + + @Override + public boolean removeAll(Collection c) { + return set.removeAll(c); + } + + @Override + public void clear() { + set.clear(); + } + + class NonNullEntrySetIterator implements Iterator> { + + private Iterator> iterator; + + NonNullEntrySetIterator(Iterator> iterator) { + this.iterator = iterator; + } + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public Map.Entry next() { + return new NonNullEntry(iterator.next()); + } + } + + class NonNullEntry implements Map.Entry { + + private Map.Entry entry; + + NonNullEntry(Map.Entry entry) { + this.entry = entry; + } + + @Override + public K getKey() { + return entry.getKey(); + } + + @Override + public V getValue() { + return entry.getValue(); + } + + @Override + public V setValue(V value) { + if (value == null) { + throw new NullPointerException(getClass().getSimpleName() + " does not allow setting null"); + } + return entry.setValue(value); + } + + @Override + public boolean equals(Object o) { + return entry.equals(o); + } + + @Override + public int hashCode() { + return entry.hashCode(); + } + } +} diff --git a/src/main/java/modchest/util/nbt/NumberTag.java b/src/main/java/modchest/util/nbt/NumberTag.java new file mode 100644 index 0000000..0018e2c --- /dev/null +++ b/src/main/java/modchest/util/nbt/NumberTag.java @@ -0,0 +1,37 @@ +package modchest.util.nbt; + +public abstract class NumberTag> extends Tag { + + public NumberTag(T value) { + super(value); + } + + public byte asByte() { + return getValue().byteValue(); + } + + public short asShort() { + return getValue().shortValue(); + } + + public int asInt() { + return getValue().intValue(); + } + + public long asLong() { + return getValue().longValue(); + } + + public float asFloat() { + return getValue().floatValue(); + } + + public double asDouble() { + return getValue().doubleValue(); + } + + @Override + public String valueToString(int maxDepth) { + return getValue().toString(); + } +} \ No newline at end of file diff --git a/src/main/java/modchest/util/nbt/ShortTag.java b/src/main/java/modchest/util/nbt/ShortTag.java new file mode 100644 index 0000000..37ed564 --- /dev/null +++ b/src/main/java/modchest/util/nbt/ShortTag.java @@ -0,0 +1,39 @@ +package modchest.util.nbt; + +public class ShortTag extends NumberTag implements Comparable { + + public static final byte ID = 2; + public static final short ZERO_VALUE = 0; + + public ShortTag() { + super(ZERO_VALUE); + } + + public ShortTag(short value) { + super(value); + } + + @Override + public byte getID() { + return ID; + } + + public void setValue(short value) { + super.setValue(value); + } + + @Override + public boolean equals(Object other) { + return super.equals(other) && asShort() == ((ShortTag) other).asShort(); + } + + @Override + public int compareTo(ShortTag other) { + return getValue().compareTo(other.getValue()); + } + + @Override + public ShortTag clone() { + return new ShortTag(getValue()); + } +} \ No newline at end of file diff --git a/src/main/java/modchest/util/nbt/StringTag.java b/src/main/java/modchest/util/nbt/StringTag.java new file mode 100644 index 0000000..00c5351 --- /dev/null +++ b/src/main/java/modchest/util/nbt/StringTag.java @@ -0,0 +1,50 @@ +package modchest.util.nbt; + +public class StringTag extends Tag implements Comparable { + + public static final byte ID = 8; + public static final String ZERO_VALUE = ""; + + public StringTag() { + super(ZERO_VALUE); + } + + public StringTag(String value) { + super(value); + } + + @Override + public byte getID() { + return ID; + } + + @Override + public String getValue() { + return super.getValue(); + } + + @Override + public void setValue(String value) { + super.setValue(value); + } + + @Override + public String valueToString(int maxDepth) { + return escapeString(getValue(), false); + } + + @Override + public boolean equals(Object other) { + return super.equals(other) && getValue().equals(((StringTag) other).getValue()); + } + + @Override + public int compareTo(StringTag o) { + return getValue().compareTo(o.getValue()); + } + + @Override + public StringTag clone() { + return new StringTag(getValue()); + } +} diff --git a/src/main/java/modchest/util/nbt/Tag.java b/src/main/java/modchest/util/nbt/Tag.java new file mode 100644 index 0000000..a687e20 --- /dev/null +++ b/src/main/java/modchest/util/nbt/Tag.java @@ -0,0 +1,162 @@ +package modchest.util.nbt; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public abstract class Tag implements Cloneable { + + /** + * The default maximum depth of the NBT structure. + * */ + public static final int DEFAULT_MAX_DEPTH = 512; + + private static final Map ESCAPE_CHARACTERS; + static { + final Map temp = new HashMap<>(); + temp.put("\\", "\\\\\\\\"); + temp.put("\n", "\\\\n"); + temp.put("\t", "\\\\t"); + temp.put("\r", "\\\\r"); + temp.put("\"", "\\\\\""); + ESCAPE_CHARACTERS = Collections.unmodifiableMap(temp); + } + + private static final Pattern ESCAPE_PATTERN = Pattern.compile("[\\\\\n\t\r\"]"); + private static final Pattern NON_QUOTE_PATTERN = Pattern.compile("[a-zA-Z0-9_\\-+]+"); + + private T value; + + /** + * Initializes this Tag with some value. If the value is {@code null}, it will + * throw a {@code NullPointerException} + * @param value The value to be set for this Tag. + * */ + public Tag(T value) { + setValue(value); + } + + /** + * @return This Tag's ID, usually used for serialization and deserialization. + * */ + public abstract byte getID(); + + /** + * @return The value of this Tag. + * */ + protected T getValue() { + return value; + } + + /** + * Sets the value for this Tag directly. + * @param value The value to be set. + * @throws NullPointerException If the value is null + * */ + protected void setValue(T value) { + this.value = checkValue(value); + } + + /** + * Checks if the value {@code value} is {@code null}. + * @param value The value to check + * @throws NullPointerException If {@code value} was {@code null} + * @return The parameter {@code value} + * */ + protected T checkValue(T value) { + return Objects.requireNonNull(value); + } + + /** + * Calls {@link Tag#toString(int)} with an initial depth of {@code 0}. + * @see Tag#toString(int) + * @throws MaxDepthReachedException If the maximum nesting depth is exceeded. + * */ + @Override + public final String toString() { + return toString(DEFAULT_MAX_DEPTH); + } + + /** + * Creates a string representation of this Tag in a valid JSON format. + * @param maxDepth The maximum nesting depth. + * @return The string representation of this Tag. + * @throws MaxDepthReachedException If the maximum nesting depth is exceeded. + * */ + public String toString(int maxDepth) { + return "{\"type\":\""+ getClass().getSimpleName() + "\"," + + "\"value\":" + valueToString(maxDepth) + "}"; + } + + /** + * Calls {@link Tag#valueToString(int)} with {@link Tag#DEFAULT_MAX_DEPTH}. + * @return The string representation of the value of this Tag. + * @throws MaxDepthReachedException If the maximum nesting depth is exceeded. + * */ + public String valueToString() { + return valueToString(DEFAULT_MAX_DEPTH); + } + + /** + * Returns a JSON representation of the value of this Tag. + * @param maxDepth The maximum nesting depth. + * @return The string representation of the value of this Tag. + * @throws MaxDepthReachedException If the maximum nesting depth is exceeded. + * */ + public abstract String valueToString(int maxDepth); + + /** + * Returns whether this Tag and some other Tag are equal. + * They are equal if {@code other} is not {@code null} and they are of the same class. + * Custom Tag implementations should overwrite this but check the result + * of this {@code super}-method while comparing. + * @param other The Tag to compare to. + * @return {@code true} if they are equal based on the conditions mentioned above. + * */ + @Override + public boolean equals(Object other) { + return other != null && getClass() == other.getClass(); + } + + /** + * Calculates the hash code of this Tag. Tags which are equal according to {@link Tag#equals(Object)} + * must return an equal hash code. + * @return The hash code of this Tag. + * */ + @Override + public int hashCode() { + return value.hashCode(); + } + + /** + * Creates a clone of this Tag. + * @return A clone of this Tag. + * */ + @SuppressWarnings("CloneDoesntDeclareCloneNotSupportedException") + public abstract Tag clone(); + + /** + * Escapes a string to fit into a JSON-like string representation for Minecraft + * or to create the JSON string representation of a Tag returned from {@link Tag#toString()} + * @param s The string to be escaped. + * @param lenient {@code true} if it should force double quotes ({@code "}) at the start and + * the end of the string. + * @return The escaped string. + * */ + protected static String escapeString(String s, boolean lenient) { + StringBuffer sb = new StringBuffer(); + Matcher m = ESCAPE_PATTERN.matcher(s); + while (m.find()) { + m.appendReplacement(sb, ESCAPE_CHARACTERS.get(m.group())); + } + m.appendTail(sb); + m = NON_QUOTE_PATTERN.matcher(s); + if (!lenient || !m.matches()) { + sb.insert(0, "\"").append("\""); + } + return sb.toString(); + } +} diff --git a/src/main/java/modchest/util/nbt/io/MaxDepthIO.java b/src/main/java/modchest/util/nbt/io/MaxDepthIO.java new file mode 100644 index 0000000..0a99f5c --- /dev/null +++ b/src/main/java/modchest/util/nbt/io/MaxDepthIO.java @@ -0,0 +1,14 @@ +package modchest.util.nbt.io; + + +public interface MaxDepthIO { + + default int decrementMaxDepth(int maxDepth) { + if (maxDepth < 0) { + throw new IllegalArgumentException("negative maximum depth is not allowed"); + } else if (maxDepth == 0) { + throw new MaxDepthReachedException("reached maximum depth of NBT structure"); + } + return --maxDepth; + } +} \ No newline at end of file diff --git a/src/main/java/modchest/util/nbt/io/MaxDepthReachedException.java b/src/main/java/modchest/util/nbt/io/MaxDepthReachedException.java new file mode 100644 index 0000000..193d356 --- /dev/null +++ b/src/main/java/modchest/util/nbt/io/MaxDepthReachedException.java @@ -0,0 +1,12 @@ +package modchest.util.nbt.io; + +/** + * Exception indicating that the maximum (de-)serialization depth has been reached. + */ +@SuppressWarnings("serial") +public class MaxDepthReachedException extends RuntimeException { + + public MaxDepthReachedException(String msg) { + super(msg); + } +} \ No newline at end of file diff --git a/src/main/resources/assets/modchest/grid/overlays/crimson_nylium/crimson_nylium.json b/src/main/resources/assets/modchest/grid/overlays/crimson_nylium/crimson_nylium.json new file mode 100644 index 0000000..bcb78bf --- /dev/null +++ b/src/main/resources/assets/modchest/grid/overlays/crimson_nylium/crimson_nylium.json @@ -0,0 +1,20 @@ +{ + "parent": "REServerMod:modchest/overlays/zero_sides.json", + "textureSource": { + "type": "sided", + "value": [ + { + "sides": ["UP"], + "value": { + "texture": "minecraft:block/crimson_nylium" + } + }, + { + "sides": ["north", "south", "east", "west"], + "value": { + "texture": "REServerMod:modchest/crimson_nylium_side_overlay" + } + } + ] + } +} diff --git a/src/main/resources/reservermod.mixins.json b/src/main/resources/reservermod.mixins.json index 62856ee..899fcfa 100644 --- a/src/main/resources/reservermod.mixins.json +++ b/src/main/resources/reservermod.mixins.json @@ -4,7 +4,18 @@ "compatibilityLevel": "JAVA_17", "mixins": [ "ServerPlayerEntityMixin", - "bedBlock" + "bedBlock", + "local.gridBehaviour", + "local.gridEntityProvider", + "local.SinglePartGridBlock", + "mc.BlockItemAccess", + "mc.GetItemBeforeEmpty", + "mc.WallBlockMixin" + ], + "client": [ + "mc.WorldRendererAccess", + "mc.BakedQuadAccess", + "mc.ItemRendererMixin" ], "injectors": { "defaultRequire": 1