Files
my-project/Assets/Blocks/Scripts/BlockRegistry.cs
unknown 087db550f1 bloak
2026-04-16 18:19:23 +05:00

140 lines
5.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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);
}
}