This commit is contained in:
unknown
2026-04-16 18:19:23 +05:00
parent 6c3f72385e
commit 087db550f1
43 changed files with 1676 additions and 58 deletions

View File

@@ -0,0 +1,139 @@
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Синглтон. Собирает все BlockDefinition, строит Texture2DArray,
/// создаёт один shared Material для всех чанков.
/// Вызвать Initialise() до создания любого чанка.
/// </summary>
public class BlockRegistry : MonoBehaviour
{
public static BlockRegistry Instance { get; private set; }
[Header("All block definitions in the game")]
public List<BlockDefinition> definitions = new();
[Header("Shader")]
public Shader voxelShader; // назначить Blocks/VoxelLit через Inspector
// Доступно после Initialise()
public Material ChunkMaterial { get; private set; }
public Texture2DArray TexArray { get; private set; }
private readonly Dictionary<string, BlockDefinition> _byId = new();
private readonly Dictionary<string, BlockDefinition> _byItemId = new();
void Awake()
{
if (Instance != null) { Destroy(gameObject); return; }
Instance = this;
DontDestroyOnLoad(gameObject);
Initialise();
}
public void Initialise()
{
_byId.Clear();
_byItemId.Clear();
if (definitions == null || definitions.Count == 0)
{
Debug.LogWarning("[BlockRegistry] No BlockDefinitions assigned.");
return;
}
// Собираем уникальные текстуры (top/bottom/side каждого блока)
// Порядок: для блока i → top=i*3, bottom=i*3+1, side=i*3+2
int layerCount = definitions.Count * 3;
int res = 128; // разрешение должно совпадать с текстурами блоков
TexArray = new Texture2DArray(res, res, layerCount,
TextureFormat.RGBA32, true, false);
TexArray.filterMode = FilterMode.Point; // пиксельный стиль
TexArray.wrapMode = TextureWrapMode.Repeat;
for (int i = 0; i < definitions.Count; i++)
{
var def = definitions[i];
def.topIndex = i * 3;
def.bottomIndex = i * 3 + 1;
def.sideIndex = i * 3 + 2;
CopyTexture(def.topTexture, TexArray, def.topIndex, res);
CopyTexture(def.bottomTexture, TexArray, def.bottomIndex, res);
CopyTexture(def.sideTexture, TexArray, def.sideIndex, res);
_byId[def.blockId] = def;
if (def.linkedItem != null)
_byItemId[def.linkedItem.id] = def;
}
TexArray.Apply(true, true); // загрузить на GPU, сделать non-readable
// Создаём один материал для всех чанков
if (voxelShader == null)
voxelShader = Shader.Find("Blocks/VoxelLit");
ChunkMaterial = new Material(voxelShader);
ChunkMaterial.SetTexture("_MainTexArray", TexArray);
Debug.Log($"[BlockRegistry] Initialised {definitions.Count} blocks, {layerCount} texture layers.");
}
// ── Lookups ───────────────────────────────────────────────────────────────
public BlockDefinition GetById(string blockId)
{
_byId.TryGetValue(blockId, out var def);
return def;
}
/// <summary>Находит BlockDefinition по id связанного ItemData (для постановки блока).</summary>
public BlockDefinition GetByItemId(string itemDataId)
{
_byItemId.TryGetValue(itemDataId, out var def);
return def;
}
// ── Утилиты ───────────────────────────────────────────────────────────────
/// <summary>
/// Копирует пиксели из src в Texture2DArray на слой layerIndex.
/// Если src null или не того размера — заполняет пурпурным (ошибка-текстура).
/// </summary>
static void CopyTexture(Texture2D src, Texture2DArray dst, int layerIndex, int res)
{
Color[] pixels;
if (src == null)
{
// Пурпурный = "текстура не назначена"
pixels = new Color[res * res];
for (int p = 0; p < pixels.Length; p++)
pixels[p] = (p / res + p) % 2 == 0 ? Color.magenta : Color.black;
}
else if (src.width != res || src.height != res)
{
Debug.LogWarning($"[BlockRegistry] {src.name} is {src.width}×{src.height}, expected {res}×{res}. Scaling.");
// Простой fallback — масштабировать через RenderTexture
var rt = RenderTexture.GetTemporary(res, res);
Graphics.Blit(src, rt);
var prev = RenderTexture.active;
RenderTexture.active = rt;
var resized = new Texture2D(res, res, TextureFormat.RGBA32, false);
resized.ReadPixels(new Rect(0, 0, res, res), 0, 0);
resized.Apply();
RenderTexture.active = prev;
RenderTexture.ReleaseTemporary(rt);
pixels = resized.GetPixels();
}
else
{
pixels = src.GetPixels();
}
dst.SetPixels(pixels, layerIndex);
}
}