From 56b9a0d2093d481915c17e34f21566da5a380808 Mon Sep 17 00:00:00 2001 From: OrekiWoof Date: Wed, 18 Mar 2026 23:15:17 +0100 Subject: [PATCH] initial implementation --- .timetracker | 17 +- .../BlockEntityButterflyPinBoard.cs | 202 ++++++++++++++++++ .../Blocks/BlockButterflyPinBoard.cs | 38 ++++ .../ButterflyPins/ButterflyPins.csproj | 16 +- .../Core/ButterflyPinsModSystem.cs | 11 - .../Systems/ButterflyPinsModSystem.cs | 15 ++ .../butterflypins/blocktypes/pinboard2x2.json | 92 ++++++++ .../butterflypins/blocktypes/pinboard3x3.json | 92 ++++++++ .../assets/butterflypins/lang/en.json | 4 + .../recipes/grid/pinboard2x2.json | 10 + .../recipes/grid/pinboard3x3.json | 10 + .../shapes/block/pinboard-2x2.json | 131 ++++++++++++ .../shapes/block/pinboard-3x3.json | 196 +++++++++++++++++ 13 files changed, 814 insertions(+), 20 deletions(-) create mode 100644 ButterflyPins/ButterflyPins/BlockEntities/BlockEntityButterflyPinBoard.cs create mode 100644 ButterflyPins/ButterflyPins/Blocks/BlockButterflyPinBoard.cs delete mode 100644 ButterflyPins/ButterflyPins/Core/ButterflyPinsModSystem.cs create mode 100644 ButterflyPins/ButterflyPins/Systems/ButterflyPinsModSystem.cs create mode 100644 ButterflyPins/ButterflyPins/assets/butterflypins/blocktypes/pinboard2x2.json create mode 100644 ButterflyPins/ButterflyPins/assets/butterflypins/blocktypes/pinboard3x3.json create mode 100644 ButterflyPins/ButterflyPins/assets/butterflypins/lang/en.json create mode 100644 ButterflyPins/ButterflyPins/assets/butterflypins/recipes/grid/pinboard2x2.json create mode 100644 ButterflyPins/ButterflyPins/assets/butterflypins/recipes/grid/pinboard3x3.json create mode 100644 ButterflyPins/ButterflyPins/assets/butterflypins/shapes/block/pinboard-2x2.json create mode 100644 ButterflyPins/ButterflyPins/assets/butterflypins/shapes/block/pinboard-3x3.json diff --git a/.timetracker b/.timetracker index f9eb966..06142b9 100644 --- a/.timetracker +++ b/.timetracker @@ -1,10 +1,25 @@ { - "total": 123, + "total": 11122, "sessions": [ { "begin": "2026-03-17T23:54:43+01:00", "end": "2026-03-17T23:56:46+01:00", "duration": 123 + }, + { + "begin": "2026-03-17T23:56:56+01:00", + "end": "2026-03-18T00:27:03+01:00", + "duration": 1807 + }, + { + "begin": "2026-03-18T19:11:43+01:00", + "end": "2026-03-18T21:24:21+01:00", + "duration": 7958 + }, + { + "begin": "2026-03-18T22:54:14+01:00", + "end": "2026-03-18T23:14:49+01:00", + "duration": 1234 } ] } \ No newline at end of file diff --git a/ButterflyPins/ButterflyPins/BlockEntities/BlockEntityButterflyPinBoard.cs b/ButterflyPins/ButterflyPins/BlockEntities/BlockEntityButterflyPinBoard.cs new file mode 100644 index 0000000..87dd8d3 --- /dev/null +++ b/ButterflyPins/ButterflyPins/BlockEntities/BlockEntityButterflyPinBoard.cs @@ -0,0 +1,202 @@ +using System; +using Vintagestory.API.Client; +using Vintagestory.API.Common; +using Vintagestory.API.Datastructures; +using Vintagestory.API.MathTools; +using Vintagestory.GameContent; + +namespace ButterflyPins.BlockEntities; + +public class BlockEntityButterflyPinBoard : BlockEntityDisplay +{ + private const int MaxBoardSlots = 9; + private const float BoardMargin = 1f / 16f; + private const float BoardSurface = 1f / 16f; + private const string ButterflyPinPrefix = "clothes-butterflypin-"; + + private readonly InventoryGeneric inventory; + + public override InventoryBase Inventory => inventory; + + public override string InventoryClassName => "butterflypinboard"; + + public override int DisplayedItems => ActiveSlotCount; + + private int Rows => Math.Max(1, Block?.Attributes?["rows"].AsInt(2) ?? 2); + + private int Columns => Math.Max(1, Block?.Attributes?["columns"].AsInt(2) ?? 2); + + private float RenderScale => Block?.Attributes?["renderScale"].AsFloat(0.18f) ?? 0.18f; + + private int ActiveSlotCount => Rows * Columns; + + public BlockEntityButterflyPinBoard() + { + inventory = new InventoryGeneric(MaxBoardSlots, null, null); + } + + public override void FromTreeAttributes(ITreeAttribute tree, IWorldAccessor worldForResolving) + { + base.FromTreeAttributes(tree, worldForResolving); + RedrawAfterReceivingTreeAttributes(worldForResolving); + } + + public bool TryInsert(IPlayer byPlayer, int slotIndex, ItemSlot activeSlot) + { + if (!IsValidSlot(slotIndex) || activeSlot.Empty || !CanInsert(slotIndex, activeSlot.Itemstack)) + return false; + + ItemStack sourceStack = activeSlot.Itemstack; + ItemStack placedStack = sourceStack.Clone(); + placedStack.StackSize = 1; + inventory[slotIndex].Itemstack = placedStack; + + activeSlot.TakeOut(1); + activeSlot.MarkDirty(); + inventory[slotIndex].MarkDirty(); + MarkChanged(); + return true; + } + + public bool TryTake(IPlayer byPlayer, int slotIndex) + { + if (!CanTake(slotIndex)) + return false; + + ItemSlot slot = inventory[slotIndex]; + ItemStack stack = slot.Itemstack!; + slot.Itemstack = null; + slot.MarkDirty(); + + if (!byPlayer.InventoryManager.TryGiveItemstack(stack, true)) + Api.World.SpawnItemEntity(stack, Pos.ToVec3d().Add(0.5, 0.5, 0.5)); + + MarkChanged(); + return true; + } + + public bool CanInsert(int slotIndex, ItemStack stack) + { + return IsValidSlot(slotIndex) && inventory[slotIndex].Empty && IsButterflyPin(stack); + } + + public bool CanTake(int slotIndex) + { + return IsValidSlot(slotIndex) && !inventory[slotIndex].Empty; + } + + public void DropContents() + { + for (int slotIndex = 0; slotIndex < ActiveSlotCount; slotIndex++) + { + ItemSlot slot = inventory[slotIndex]; + ItemStack? stack = slot.Itemstack; + if (stack == null) + continue; + + Api.World.SpawnItemEntity(stack, Pos.ToVec3d().Add(0.5, 0.5, 0.5)); + slot.Itemstack = null; + slot.MarkDirty(); + } + } + + public int GetSlotIndex(Vec3d hitPosition) + { + Vec3d local = ToBaseOrientation(hitPosition); + if (local.X < BoardMargin || local.X > 1 - BoardMargin || local.Y < BoardMargin || local.Y > 1 - BoardMargin) + return -1; + + double width = (1 - (BoardMargin * 2)) / Columns; + double height = (1 - (BoardMargin * 2)) / Rows; + + int column = GameMath.Clamp((int)((local.X - BoardMargin) / width), 0, Columns - 1); + int rowFromBottom = GameMath.Clamp((int)((local.Y - BoardMargin) / height), 0, Rows - 1); + int rowFromTop = Rows - 1 - rowFromBottom; + + return (rowFromTop * Columns) + column; + } + + private bool IsValidSlot(int slotIndex) + { + return slotIndex >= 0 && slotIndex < ActiveSlotCount; + } + + private bool IsButterflyPin(ItemStack stack) + { + AssetLocation? code = stack.Collectible?.Code; + return code != null && code.Path.StartsWith(ButterflyPinPrefix, StringComparison.Ordinal); + } + + private void MarkChanged() + { + RedrawAfterReceivingTreeAttributes(Api.World); + base.MarkDirty(true); + Api.World.BlockAccessor.MarkBlockDirty(Pos); + } + + private Vec3d ToBaseOrientation(Vec3d hitPosition) + { + Vec3d centered = new(hitPosition.X - 0.5, hitPosition.Y, hitPosition.Z - 0.5); + float angle = -GetRotationY(); + float sin = GameMath.Sin(angle); + float cos = GameMath.Cos(angle); + + return new Vec3d( + (centered.X * cos) - (centered.Z * sin) + 0.5, + hitPosition.Y, + (centered.X * sin) + (centered.Z * cos) + 0.5 + ); + } + + protected override float[][] genTransformationMatrices() + { + float[][] matrices = new float[DisplayedItems][]; + double cellWidth = (1 - (BoardMargin * 2)) / Columns; + double cellHeight = (1 - (BoardMargin * 2)) / Rows; + float stepX = 0.75f / Columns; + float stepY = 0.75f / Rows; + float yOffset = (Rows == 2 && Columns == 2 ? 1.0f : 0.75f) + 0.07f; + float boardRotationY = GetRotationY(); + float itemRotationY = boardRotationY - GameMath.PIHALF; + + for (int slotIndex = 0; slotIndex < DisplayedItems; slotIndex++) + { + int row = slotIndex / Columns; + int column = slotIndex % Columns; + + float x = (float)(1 - BoardMargin - (0.5 * cellWidth) - (column * stepX)); + float y = (float)(BoardMargin + (0.5 * cellHeight) + ((Rows - 1 - row) * stepY)); + float z = Columns == 2 ? -0/1f : -1/48f; + float xOffset = Columns == 2 ? 0.465f : 0.475f; + Vec3f off = new(x - xOffset, y - yOffset, z + 0.5f); + off = new Matrixf().RotateY(boardRotationY).TransformVector(off.ToVec4f(0)).XYZ; + + matrices[slotIndex] = new Matrixf() + .Translate(off.X, off.Y, off.Z) + .Translate(0.5f, 0f, 0.5f) + .RotateY(itemRotationY) + .Scale(RenderScale, RenderScale, RenderScale) + .Translate(-0.5f, 0f, -0.5f) + .Values; + } + + return matrices; + } + + public float GetRotationY() + { + string side = Block?.Variant?["side"] ?? "south"; + return side switch + { + "north" => GameMath.PI, + "east" => GameMath.PIHALF, + "west" => GameMath.PI + GameMath.PIHALF, + _ => 0f, + }; + } + + public float GetRenderScale() + { + return RenderScale; + } +} \ No newline at end of file diff --git a/ButterflyPins/ButterflyPins/Blocks/BlockButterflyPinBoard.cs b/ButterflyPins/ButterflyPins/Blocks/BlockButterflyPinBoard.cs new file mode 100644 index 0000000..dbc1bee --- /dev/null +++ b/ButterflyPins/ButterflyPins/Blocks/BlockButterflyPinBoard.cs @@ -0,0 +1,38 @@ +using ButterflyPins.BlockEntities; +using Vintagestory.API.Common; +using Vintagestory.API.MathTools; + +namespace ButterflyPins.Blocks; + +public class BlockButterflyPinBoard : Block +{ + public override bool OnBlockInteractStart(IWorldAccessor world, IPlayer byPlayer, BlockSelection blockSel) + { + if (blockSel == null) + return base.OnBlockInteractStart(world, byPlayer, blockSel); + + if (world.BlockAccessor.GetBlockEntity(blockSel.Position) is not BlockEntityButterflyPinBoard board) + return base.OnBlockInteractStart(world, byPlayer, blockSel); + + int slotIndex = board.GetSlotIndex(blockSel.HitPosition); + if (slotIndex < 0) + return base.OnBlockInteractStart(world, byPlayer, blockSel); + + ItemSlot activeSlot = byPlayer.InventoryManager.ActiveHotbarSlot; + if (world.Side == EnumAppSide.Client) + return (!activeSlot.Empty && board.CanInsert(slotIndex, activeSlot.Itemstack)) || board.CanTake(slotIndex); + + if (!activeSlot.Empty && board.TryInsert(byPlayer, slotIndex, activeSlot)) + return true; + + return board.TryTake(byPlayer, slotIndex) || base.OnBlockInteractStart(world, byPlayer, blockSel); + } + + public override void OnBlockBroken(IWorldAccessor world, BlockPos pos, IPlayer byPlayer, float dropQuantityMultiplier = 1) + { + if (world.Side == EnumAppSide.Server && world.BlockAccessor.GetBlockEntity(pos) is BlockEntityButterflyPinBoard board) + board.DropContents(); + + base.OnBlockBroken(world, pos, byPlayer, dropQuantityMultiplier); + } +} \ No newline at end of file diff --git a/ButterflyPins/ButterflyPins/ButterflyPins.csproj b/ButterflyPins/ButterflyPins/ButterflyPins.csproj index d61234a..92c3459 100644 --- a/ButterflyPins/ButterflyPins/ButterflyPins.csproj +++ b/ButterflyPins/ButterflyPins/ButterflyPins.csproj @@ -75,16 +75,16 @@ - - + + PreserveNewest - - + + - - + + PreserveNewest - - + + diff --git a/ButterflyPins/ButterflyPins/Core/ButterflyPinsModSystem.cs b/ButterflyPins/ButterflyPins/Core/ButterflyPinsModSystem.cs deleted file mode 100644 index 74d1751..0000000 --- a/ButterflyPins/ButterflyPins/Core/ButterflyPinsModSystem.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Vintagestory.API.Common; - -namespace ButterflyPins.Core; - -public class ButterflyPinsModSystem : ModSystem -{ - public override void Start(ICoreAPI api) - { - api.Logger.Notification("ButterflyPins loaded"); - } -} diff --git a/ButterflyPins/ButterflyPins/Systems/ButterflyPinsModSystem.cs b/ButterflyPins/ButterflyPins/Systems/ButterflyPinsModSystem.cs new file mode 100644 index 0000000..7a08e40 --- /dev/null +++ b/ButterflyPins/ButterflyPins/Systems/ButterflyPinsModSystem.cs @@ -0,0 +1,15 @@ +using ButterflyPins.BlockEntities; +using ButterflyPins.Blocks; +using Vintagestory.API.Common; + +namespace ButterflyPins.Systems; + +public class ButterflyPinsModSystem : ModSystem +{ + public override void Start(ICoreAPI api) + { + api.RegisterBlockClass("BlockButterflyPinBoard", typeof(BlockButterflyPinBoard)); + api.RegisterBlockEntityClass("ButterflyPinBoard", typeof(BlockEntityButterflyPinBoard)); + api.Logger.Notification("ButterflyPins loaded"); + } +} diff --git a/ButterflyPins/ButterflyPins/assets/butterflypins/blocktypes/pinboard2x2.json b/ButterflyPins/ButterflyPins/assets/butterflypins/blocktypes/pinboard2x2.json new file mode 100644 index 0000000..0323535 --- /dev/null +++ b/ButterflyPins/ButterflyPins/assets/butterflypins/blocktypes/pinboard2x2.json @@ -0,0 +1,92 @@ +{ + "code": "pinboard2x2", + "class": "BlockButterflyPinBoard", + "entityClass": "ButterflyPinBoard", + "behaviors": [ + { "name": "HorizontalAttachable" }, + { "name": "Lockable" } + ], + "variantgroups": [ + { "code": "side", "loadFromProperties": "abstract/horizontalorientation" } + ], + "attributes": { + "rows": 2, + "columns": 2, + "renderScale": 0.85, + "reinforcable": true + }, + "creativeinventory": { + "general": ["pinboard2x2-south"], + "decorative": ["pinboard2x2-south"] + }, + "shapebytype": { + "*-north": { "base": "butterflypins:block/pinboard-2x2", "rotateY": 180 }, + "*-east": { "base": "butterflypins:block/pinboard-2x2", "rotateY": 90 }, + "*-south": { "base": "butterflypins:block/pinboard-2x2", "rotateY": 0 }, + "*-west": { "base": "butterflypins:block/pinboard-2x2", "rotateY": 270 } + }, + "blockmaterial": "Wood", + "drawtype": "json", + "replaceable": 900, + "resistance": 1.5, + "lightAbsorption": 0, + "faceCullMode": "NeverCull", + "sidesolid": { "all": false }, + "sideopaque": { "all": false }, + "emitSideAo": { "all": false }, + "collisionbox": { + "x1": 0.0625, + "y1": 0.0625, + "z1": 0.9375, + "x2": 0.9375, + "y2": 0.9375, + "z2": 1.0, + "rotateYByType": { + "*-north": 180, + "*-east": 90, + "*-south": 0, + "*-west": 270 + } + }, + "selectionbox": { + "x1": 0.0625, + "y1": 0.0625, + "z1": 0.9375, + "x2": 0.9375, + "y2": 0.9375, + "z2": 1.0, + "rotateYByType": { + "*-north": 180, + "*-east": 90, + "*-south": 0, + "*-west": 270 + } + }, + "combustibleProps": { + "burnTemperature": 600, + "burnDuration": 20 + }, + "sounds": { + "place": "block/planks", + "break": "block/planks", + "hit": "block/planks" + }, + "materialDensity": 400, + "guiTransform": { + "rotation": { "x": -19, "y": 136, "z": 0 }, + "origin": { "x": 0.5, "y": 0.5, "z": 0.5 }, + "scale": 1.9 + }, + "groundTransform": { + "translation": { "x": 0, "y": 0, "z": 0 }, + "rotation": { "x": -90, "y": 0, "z": 0 }, + "origin": { "x": 0.5, "y": 0, "z": 0.5 }, + "scale": 2.2 + }, + "tpHandTransform": { + "translation": { "x": -0.45, "y": -0.8, "z": 0.04 }, + "rotation": { "x": 0, "y": 0, "z": -10 }, + "origin": { "x": 0.5, "y": 0.5, "z": 0.5 }, + "scale": 0.95 + } +} \ No newline at end of file diff --git a/ButterflyPins/ButterflyPins/assets/butterflypins/blocktypes/pinboard3x3.json b/ButterflyPins/ButterflyPins/assets/butterflypins/blocktypes/pinboard3x3.json new file mode 100644 index 0000000..fce72ae --- /dev/null +++ b/ButterflyPins/ButterflyPins/assets/butterflypins/blocktypes/pinboard3x3.json @@ -0,0 +1,92 @@ +{ + "code": "pinboard3x3", + "class": "BlockButterflyPinBoard", + "entityClass": "ButterflyPinBoard", + "behaviors": [ + { "name": "HorizontalAttachable" }, + { "name": "Lockable" } + ], + "variantgroups": [ + { "code": "side", "loadFromProperties": "abstract/horizontalorientation" } + ], + "attributes": { + "rows": 3, + "columns": 3, + "renderScale": 0.675, + "reinforcable": true + }, + "creativeinventory": { + "general": ["pinboard3x3-south"], + "decorative": ["pinboard3x3-south"] + }, + "shapebytype": { + "*-north": { "base": "butterflypins:block/pinboard-3x3", "rotateY": 180 }, + "*-east": { "base": "butterflypins:block/pinboard-3x3", "rotateY": 90 }, + "*-south": { "base": "butterflypins:block/pinboard-3x3", "rotateY": 0 }, + "*-west": { "base": "butterflypins:block/pinboard-3x3", "rotateY": 270 } + }, + "blockmaterial": "Wood", + "drawtype": "json", + "replaceable": 900, + "resistance": 1.5, + "lightAbsorption": 0, + "faceCullMode": "NeverCull", + "sidesolid": { "all": false }, + "sideopaque": { "all": false }, + "emitSideAo": { "all": false }, + "collisionbox": { + "x1": 0.0625, + "y1": 0.0625, + "z1": 0.9375, + "x2": 0.9375, + "y2": 0.9375, + "z2": 1.0, + "rotateYByType": { + "*-north": 180, + "*-east": 90, + "*-south": 0, + "*-west": 270 + } + }, + "selectionbox": { + "x1": 0.0625, + "y1": 0.0625, + "z1": 0.9375, + "x2": 0.9375, + "y2": 0.9375, + "z2": 1.0, + "rotateYByType": { + "*-north": 180, + "*-east": 90, + "*-south": 0, + "*-west": 270 + } + }, + "combustibleProps": { + "burnTemperature": 600, + "burnDuration": 25 + }, + "sounds": { + "place": "block/planks", + "break": "block/planks", + "hit": "block/planks" + }, + "materialDensity": 400, + "guiTransform": { + "rotation": { "x": -19, "y": 136, "z": 0 }, + "origin": { "x": 0.5, "y": 0.5, "z": 0.5 }, + "scale": 1.9 + }, + "groundTransform": { + "translation": { "x": 0, "y": 0, "z": 0 }, + "rotation": { "x": -90, "y": 0, "z": 0 }, + "origin": { "x": 0.5, "y": 0, "z": 0.5 }, + "scale": 2.2 + }, + "tpHandTransform": { + "translation": { "x": -0.45, "y": -0.8, "z": 0.04 }, + "rotation": { "x": 0, "y": 0, "z": -10 }, + "origin": { "x": 0.5, "y": 0.5, "z": 0.5 }, + "scale": 0.95 + } +} \ No newline at end of file diff --git a/ButterflyPins/ButterflyPins/assets/butterflypins/lang/en.json b/ButterflyPins/ButterflyPins/assets/butterflypins/lang/en.json new file mode 100644 index 0000000..df6e94b --- /dev/null +++ b/ButterflyPins/ButterflyPins/assets/butterflypins/lang/en.json @@ -0,0 +1,4 @@ +{ + "block-pinboard2x2-*": "Butterfly Pin Board (2x2)", + "block-pinboard3x3-*": "Butterfly Pin Board (3x3)" +} \ No newline at end of file diff --git a/ButterflyPins/ButterflyPins/assets/butterflypins/recipes/grid/pinboard2x2.json b/ButterflyPins/ButterflyPins/assets/butterflypins/recipes/grid/pinboard2x2.json new file mode 100644 index 0000000..c902a33 --- /dev/null +++ b/ButterflyPins/ButterflyPins/assets/butterflypins/recipes/grid/pinboard2x2.json @@ -0,0 +1,10 @@ +{ + "ingredientPattern": "PPP\tS_S\tPPP", + "ingredients": { + "P": { "type": "item", "code": "plank-*" }, + "S": { "type": "item", "code": "stick" } + }, + "width": 3, + "height": 3, + "output": { "type": "block", "code": "pinboard2x2-south" } +} \ No newline at end of file diff --git a/ButterflyPins/ButterflyPins/assets/butterflypins/recipes/grid/pinboard3x3.json b/ButterflyPins/ButterflyPins/assets/butterflypins/recipes/grid/pinboard3x3.json new file mode 100644 index 0000000..aeff790 --- /dev/null +++ b/ButterflyPins/ButterflyPins/assets/butterflypins/recipes/grid/pinboard3x3.json @@ -0,0 +1,10 @@ +{ + "ingredientPattern": "PPP\tPSP\tPPP", + "ingredients": { + "P": { "type": "item", "code": "plank-*" }, + "S": { "type": "item", "code": "stick" } + }, + "width": 3, + "height": 3, + "output": { "type": "block", "code": "pinboard3x3-south" } +} \ No newline at end of file diff --git a/ButterflyPins/ButterflyPins/assets/butterflypins/shapes/block/pinboard-2x2.json b/ButterflyPins/ButterflyPins/assets/butterflypins/shapes/block/pinboard-2x2.json new file mode 100644 index 0000000..7b3d846 --- /dev/null +++ b/ButterflyPins/ButterflyPins/assets/butterflypins/shapes/block/pinboard-2x2.json @@ -0,0 +1,131 @@ +{ + "editor": { + "allAngles": false, + "singleTexture": false + }, + "textureWidth": 16, + "textureHeight": 16, + "textures": { + "wood": "game:block/wood/debarked/aged", + "metal": "game:block/metal/tarnished/rusty-iron" + }, + "elements": [ + { + "name": "board", + "from": [1.0, 1.0, 15.0], + "to": [15.0, 15.0, 16.0], + "faces": { + "north": { "texture": "#wood", "uv": [1.0, 1.0, 15.0, 15.0] }, + "east": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 14.0] }, + "south": { "texture": "#wood", "uv": [1.0, 1.0, 15.0, 15.0] }, + "west": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 14.0] }, + "up": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 1.0] }, + "down": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 1.0] } + } + }, + { + "name": "lipTop", + "from": [1.0, 14.0, 14.5], + "to": [15.0, 15.0, 15.0], + "faces": { + "north": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 1.0] }, + "east": { "texture": "#wood", "uv": [0.0, 0.0, 0.5, 1.0] }, + "south": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 1.0] }, + "west": { "texture": "#wood", "uv": [0.0, 0.0, 0.5, 1.0] }, + "up": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 0.5] }, + "down": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 0.5] } + } + }, + { + "name": "lipBottom", + "from": [1.0, 1.0, 14.5], + "to": [15.0, 2.0, 15.0], + "faces": { + "north": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 1.0] }, + "east": { "texture": "#wood", "uv": [0.0, 0.0, 0.5, 1.0] }, + "south": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 1.0] }, + "west": { "texture": "#wood", "uv": [0.0, 0.0, 0.5, 1.0] }, + "up": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 0.5] }, + "down": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 0.5] } + } + }, + { + "name": "lipLeft", + "from": [1.0, 2.0, 14.5], + "to": [2.0, 14.0, 15.0], + "faces": { + "north": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 12.0] }, + "east": { "texture": "#wood", "uv": [0.0, 0.0, 0.5, 12.0] }, + "south": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 12.0] }, + "west": { "texture": "#wood", "uv": [0.0, 0.0, 0.5, 12.0] }, + "up": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 0.5] }, + "down": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 0.5] } + } + }, + { + "name": "lipRight", + "from": [14.0, 2.0, 14.5], + "to": [15.0, 14.0, 15.0], + "faces": { + "north": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 12.0] }, + "east": { "texture": "#wood", "uv": [0.0, 0.0, 0.5, 12.0] }, + "south": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 12.0] }, + "west": { "texture": "#wood", "uv": [0.0, 0.0, 0.5, 12.0] }, + "up": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 0.5] }, + "down": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 0.5] } + } + }, + { + "name": "pinTopLeft", + "from": [4.75, 10.75, 14.2], + "to": [5.25, 11.25, 14.8], + "faces": { + "north": { "texture": "#metal", "uv": [12.0, 11.5, 12.5, 12.0] }, + "east": { "texture": "#metal", "uv": [10.5, 12.0, 11.0, 12.5] }, + "south": { "texture": "#metal", "uv": [11.0, 12.5, 11.5, 13.0] }, + "west": { "texture": "#metal", "uv": [12.0, 12.0, 12.5, 12.5] }, + "up": { "texture": "#metal", "uv": [10.5, 12.5, 11.0, 13.0] }, + "down": { "texture": "#metal", "uv": [10.5, 11.5, 11.0, 12.0] } + } + }, + { + "name": "pinTopRight", + "from": [10.75, 10.75, 14.2], + "to": [11.25, 11.25, 14.8], + "faces": { + "north": { "texture": "#metal", "uv": [12.0, 11.5, 12.5, 12.0] }, + "east": { "texture": "#metal", "uv": [10.5, 12.0, 11.0, 12.5] }, + "south": { "texture": "#metal", "uv": [11.0, 12.5, 11.5, 13.0] }, + "west": { "texture": "#metal", "uv": [12.0, 12.0, 12.5, 12.5] }, + "up": { "texture": "#metal", "uv": [10.5, 12.5, 11.0, 13.0] }, + "down": { "texture": "#metal", "uv": [10.5, 11.5, 11.0, 12.0] } + } + }, + { + "name": "pinBottomLeft", + "from": [4.75, 4.75, 14.2], + "to": [5.25, 5.25, 14.8], + "faces": { + "north": { "texture": "#metal", "uv": [12.0, 11.5, 12.5, 12.0] }, + "east": { "texture": "#metal", "uv": [10.5, 12.0, 11.0, 12.5] }, + "south": { "texture": "#metal", "uv": [11.0, 12.5, 11.5, 13.0] }, + "west": { "texture": "#metal", "uv": [12.0, 12.0, 12.5, 12.5] }, + "up": { "texture": "#metal", "uv": [10.5, 12.5, 11.0, 13.0] }, + "down": { "texture": "#metal", "uv": [10.5, 11.5, 11.0, 12.0] } + } + }, + { + "name": "pinBottomRight", + "from": [10.75, 4.75, 14.2], + "to": [11.25, 5.25, 14.8], + "faces": { + "north": { "texture": "#metal", "uv": [12.0, 11.5, 12.5, 12.0] }, + "east": { "texture": "#metal", "uv": [10.5, 12.0, 11.0, 12.5] }, + "south": { "texture": "#metal", "uv": [11.0, 12.5, 11.5, 13.0] }, + "west": { "texture": "#metal", "uv": [12.0, 12.0, 12.5, 12.5] }, + "up": { "texture": "#metal", "uv": [10.5, 12.5, 11.0, 13.0] }, + "down": { "texture": "#metal", "uv": [10.5, 11.5, 11.0, 12.0] } + } + } + ] +} \ No newline at end of file diff --git a/ButterflyPins/ButterflyPins/assets/butterflypins/shapes/block/pinboard-3x3.json b/ButterflyPins/ButterflyPins/assets/butterflypins/shapes/block/pinboard-3x3.json new file mode 100644 index 0000000..d05fe02 --- /dev/null +++ b/ButterflyPins/ButterflyPins/assets/butterflypins/shapes/block/pinboard-3x3.json @@ -0,0 +1,196 @@ +{ + "editor": { + "allAngles": false, + "singleTexture": false + }, + "textureWidth": 16, + "textureHeight": 16, + "textures": { + "wood": "game:block/wood/debarked/aged", + "metal": "game:block/metal/tarnished/rusty-iron" + }, + "elements": [ + { + "name": "board", + "from": [1.0, 1.0, 15.0], + "to": [15.0, 15.0, 16.0], + "faces": { + "north": { "texture": "#wood", "uv": [1.0, 1.0, 15.0, 15.0] }, + "east": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 14.0] }, + "south": { "texture": "#wood", "uv": [1.0, 1.0, 15.0, 15.0] }, + "west": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 14.0] }, + "up": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 1.0] }, + "down": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 1.0] } + } + }, + { + "name": "lipTop", + "from": [1.0, 14.0, 14.5], + "to": [15.0, 15.0, 15.0], + "faces": { + "north": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 1.0] }, + "east": { "texture": "#wood", "uv": [0.0, 0.0, 0.5, 1.0] }, + "south": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 1.0] }, + "west": { "texture": "#wood", "uv": [0.0, 0.0, 0.5, 1.0] }, + "up": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 0.5] }, + "down": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 0.5] } + } + }, + { + "name": "lipBottom", + "from": [1.0, 1.0, 14.5], + "to": [15.0, 2.0, 15.0], + "faces": { + "north": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 1.0] }, + "east": { "texture": "#wood", "uv": [0.0, 0.0, 0.5, 1.0] }, + "south": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 1.0] }, + "west": { "texture": "#wood", "uv": [0.0, 0.0, 0.5, 1.0] }, + "up": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 0.5] }, + "down": { "texture": "#wood", "uv": [1.0, 0.0, 15.0, 0.5] } + } + }, + { + "name": "lipLeft", + "from": [1.0, 2.0, 14.5], + "to": [2.0, 14.0, 15.0], + "faces": { + "north": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 12.0] }, + "east": { "texture": "#wood", "uv": [0.0, 0.0, 0.5, 12.0] }, + "south": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 12.0] }, + "west": { "texture": "#wood", "uv": [0.0, 0.0, 0.5, 12.0] }, + "up": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 0.5] }, + "down": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 0.5] } + } + }, + { + "name": "lipRight", + "from": [14.0, 2.0, 14.5], + "to": [15.0, 14.0, 15.0], + "faces": { + "north": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 12.0] }, + "east": { "texture": "#wood", "uv": [0.0, 0.0, 0.5, 12.0] }, + "south": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 12.0] }, + "west": { "texture": "#wood", "uv": [0.0, 0.0, 0.5, 12.0] }, + "up": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 0.5] }, + "down": { "texture": "#wood", "uv": [0.0, 0.0, 1.0, 0.5] } + } + }, + { + "name": "pinA", + "from": [4.0, 12.0, 14.2], + "to": [4.5, 12.5, 14.8], + "faces": { + "north": { "texture": "#metal", "uv": [12.0, 11.5, 12.5, 12.0] }, + "east": { "texture": "#metal", "uv": [10.5, 12.0, 11.0, 12.5] }, + "south": { "texture": "#metal", "uv": [11.0, 12.5, 11.5, 13.0] }, + "west": { "texture": "#metal", "uv": [12.0, 12.0, 12.5, 12.5] }, + "up": { "texture": "#metal", "uv": [10.5, 12.5, 11.0, 13.0] }, + "down": { "texture": "#metal", "uv": [10.5, 11.5, 11.0, 12.0] } + } + }, + { + "name": "pinB", + "from": [8.0, 12.0, 14.2], + "to": [8.5, 12.5, 14.8], + "faces": { + "north": { "texture": "#metal", "uv": [12.0, 11.5, 12.5, 12.0] }, + "east": { "texture": "#metal", "uv": [10.5, 12.0, 11.0, 12.5] }, + "south": { "texture": "#metal", "uv": [11.0, 12.5, 11.5, 13.0] }, + "west": { "texture": "#metal", "uv": [12.0, 12.0, 12.5, 12.5] }, + "up": { "texture": "#metal", "uv": [10.5, 12.5, 11.0, 13.0] }, + "down": { "texture": "#metal", "uv": [10.5, 11.5, 11.0, 12.0] } + } + }, + { + "name": "pinC", + "from": [12.0, 12.0, 14.2], + "to": [12.5, 12.5, 14.8], + "faces": { + "north": { "texture": "#metal", "uv": [12.0, 11.5, 12.5, 12.0] }, + "east": { "texture": "#metal", "uv": [10.5, 12.0, 11.0, 12.5] }, + "south": { "texture": "#metal", "uv": [11.0, 12.5, 11.5, 13.0] }, + "west": { "texture": "#metal", "uv": [12.0, 12.0, 12.5, 12.5] }, + "up": { "texture": "#metal", "uv": [10.5, 12.5, 11.0, 13.0] }, + "down": { "texture": "#metal", "uv": [10.5, 11.5, 11.0, 12.0] } + } + }, + { + "name": "pinD", + "from": [4.0, 8.0, 14.2], + "to": [4.5, 8.5, 14.8], + "faces": { + "north": { "texture": "#metal", "uv": [12.0, 11.5, 12.5, 12.0] }, + "east": { "texture": "#metal", "uv": [10.5, 12.0, 11.0, 12.5] }, + "south": { "texture": "#metal", "uv": [11.0, 12.5, 11.5, 13.0] }, + "west": { "texture": "#metal", "uv": [12.0, 12.0, 12.5, 12.5] }, + "up": { "texture": "#metal", "uv": [10.5, 12.5, 11.0, 13.0] }, + "down": { "texture": "#metal", "uv": [10.5, 11.5, 11.0, 12.0] } + } + }, + { + "name": "pinE", + "from": [8.0, 8.0, 14.2], + "to": [8.5, 8.5, 14.8], + "faces": { + "north": { "texture": "#metal", "uv": [12.0, 11.5, 12.5, 12.0] }, + "east": { "texture": "#metal", "uv": [10.5, 12.0, 11.0, 12.5] }, + "south": { "texture": "#metal", "uv": [11.0, 12.5, 11.5, 13.0] }, + "west": { "texture": "#metal", "uv": [12.0, 12.0, 12.5, 12.5] }, + "up": { "texture": "#metal", "uv": [10.5, 12.5, 11.0, 13.0] }, + "down": { "texture": "#metal", "uv": [10.5, 11.5, 11.0, 12.0] } + } + }, + { + "name": "pinF", + "from": [12.0, 8.0, 14.2], + "to": [12.5, 8.5, 14.8], + "faces": { + "north": { "texture": "#metal", "uv": [12.0, 11.5, 12.5, 12.0] }, + "east": { "texture": "#metal", "uv": [10.5, 12.0, 11.0, 12.5] }, + "south": { "texture": "#metal", "uv": [11.0, 12.5, 11.5, 13.0] }, + "west": { "texture": "#metal", "uv": [12.0, 12.0, 12.5, 12.5] }, + "up": { "texture": "#metal", "uv": [10.5, 12.5, 11.0, 13.0] }, + "down": { "texture": "#metal", "uv": [10.5, 11.5, 11.0, 12.0] } + } + }, + { + "name": "pinG", + "from": [4.0, 4.0, 14.2], + "to": [4.5, 4.5, 14.8], + "faces": { + "north": { "texture": "#metal", "uv": [12.0, 11.5, 12.5, 12.0] }, + "east": { "texture": "#metal", "uv": [10.5, 12.0, 11.0, 12.5] }, + "south": { "texture": "#metal", "uv": [11.0, 12.5, 11.5, 13.0] }, + "west": { "texture": "#metal", "uv": [12.0, 12.0, 12.5, 12.5] }, + "up": { "texture": "#metal", "uv": [10.5, 12.5, 11.0, 13.0] }, + "down": { "texture": "#metal", "uv": [10.5, 11.5, 11.0, 12.0] } + } + }, + { + "name": "pinH", + "from": [8.0, 4.0, 14.2], + "to": [8.5, 4.5, 14.8], + "faces": { + "north": { "texture": "#metal", "uv": [12.0, 11.5, 12.5, 12.0] }, + "east": { "texture": "#metal", "uv": [10.5, 12.0, 11.0, 12.5] }, + "south": { "texture": "#metal", "uv": [11.0, 12.5, 11.5, 13.0] }, + "west": { "texture": "#metal", "uv": [12.0, 12.0, 12.5, 12.5] }, + "up": { "texture": "#metal", "uv": [10.5, 12.5, 11.0, 13.0] }, + "down": { "texture": "#metal", "uv": [10.5, 11.5, 11.0, 12.0] } + } + }, + { + "name": "pinI", + "from": [12.0, 4.0, 14.2], + "to": [12.5, 4.5, 14.8], + "faces": { + "north": { "texture": "#metal", "uv": [12.0, 11.5, 12.5, 12.0] }, + "east": { "texture": "#metal", "uv": [10.5, 12.0, 11.0, 12.5] }, + "south": { "texture": "#metal", "uv": [11.0, 12.5, 11.5, 13.0] }, + "west": { "texture": "#metal", "uv": [12.0, 12.0, 12.5, 12.5] }, + "up": { "texture": "#metal", "uv": [10.5, 12.5, 11.0, 13.0] }, + "down": { "texture": "#metal", "uv": [10.5, 11.5, 11.0, 12.0] } + } + } + ] +} \ No newline at end of file