flatten folder structure, fix collision boxes and gui/fp/tp transforms
This commit is contained in:
212
ButterflyPins/BlockEntities/BlockEntityButterflyPinBoard.cs
Normal file
212
ButterflyPins/BlockEntities/BlockEntityButterflyPinBoard.cs
Normal file
@@ -0,0 +1,212 @@
|
||||
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 float DisplayOriginX => GetDisplayFloat("displayOriginX", 0.31666666f);
|
||||
|
||||
private float DisplayOriginY => GetDisplayFloat("displayOriginY", 0.01333332f);
|
||||
|
||||
private float DisplayOriginZ => GetDisplayFloat("displayOriginZ", 0.47916666f);
|
||||
|
||||
private float DisplayStepX => GetDisplayFloat("displayStepX", -0.25f);
|
||||
|
||||
private float DisplayStepY => GetDisplayFloat("displayStepY", -0.25f);
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
private float GetDisplayFloat(string key, float defaultValue)
|
||||
{
|
||||
return Block?.Attributes?[key].AsFloat(defaultValue) ?? defaultValue;
|
||||
}
|
||||
|
||||
protected override float[][] genTransformationMatrices()
|
||||
{
|
||||
float[][] matrices = new float[DisplayedItems][];
|
||||
float boardRotationY = GetRotationY();
|
||||
float itemRotationY = boardRotationY - GameMath.PIHALF;
|
||||
|
||||
for (int slotIndex = 0; slotIndex < DisplayedItems; slotIndex++)
|
||||
{
|
||||
int row = slotIndex / Columns;
|
||||
int column = slotIndex % Columns;
|
||||
|
||||
Vec3f off = new(
|
||||
DisplayOriginX + (column * DisplayStepX),
|
||||
DisplayOriginY + (row * DisplayStepY),
|
||||
DisplayOriginZ
|
||||
);
|
||||
off = new Matrixf().RotateY(boardRotationY).TransformVector(off.ToVec4f(0)).XYZ;
|
||||
|
||||
matrices[slotIndex] = new Matrixf()
|
||||
.Translate(off.X, off.Y, off.Z)
|
||||
.Translate(0.5f, 0.5f, 0.5f)
|
||||
.RotateY(itemRotationY)
|
||||
.Scale(RenderScale, RenderScale, RenderScale)
|
||||
.Translate(-0.5f, -0.5f, -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user