Files
Dal4segno 59246a67bd 지하 최적화
블록 프리팹 단위 -> 블록 청크 단위 스폰
기타 건설, 조준 관련 사이드이펙트 버그 수정
2026-01-21 21:34:05 +09:00

194 lines
5.0 KiB
C#

using Unity.Netcode;
/// <summary>
/// Compact block state struct for chunk-based storage.
/// 3 bytes per block: type (1), health (1), flags (1)
/// </summary>
public struct BlockData : INetworkSerializable
{
/// <summary>
/// Block type: 0=empty/air, 1=normal stone, 2=resource ore
/// </summary>
public byte blockType;
/// <summary>
/// Block health: 0-255 (0 = destroyed)
/// </summary>
public byte health;
/// <summary>
/// Block flags: bit 0 = isDiscovered (fog of war)
/// </summary>
public byte flags;
// Block type constants
public const byte TYPE_EMPTY = 0;
public const byte TYPE_NORMAL = 1;
public const byte TYPE_RESOURCE = 2;
// Flag bit masks
public const byte FLAG_DISCOVERED = 1 << 0; // Has been seen at least once (networked/permanent)
/// <summary>
/// Whether this block is empty (air or destroyed)
/// </summary>
public bool IsEmpty => blockType == TYPE_EMPTY || health == 0;
/// <summary>
/// Whether this block has been discovered by players
/// </summary>
public bool IsDiscovered
{
get => (flags & FLAG_DISCOVERED) != 0;
set
{
if (value)
flags |= FLAG_DISCOVERED;
else
flags &= unchecked((byte)~FLAG_DISCOVERED);
}
}
/// <summary>
/// Whether this block is a resource block
/// </summary>
public bool IsResource => blockType == TYPE_RESOURCE;
/// <summary>
/// Create an empty block
/// </summary>
public static BlockData Empty => new BlockData
{
blockType = TYPE_EMPTY,
health = 0,
flags = 0
};
/// <summary>
/// Create a normal stone block with full health
/// </summary>
public static BlockData Normal(byte maxHealth = 100) => new BlockData
{
blockType = TYPE_NORMAL,
health = maxHealth,
flags = 0
};
/// <summary>
/// Create a resource ore block with full health
/// </summary>
public static BlockData Resource(byte maxHealth = 150) => new BlockData
{
blockType = TYPE_RESOURCE,
health = maxHealth,
flags = 0
};
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
serializer.SerializeValue(ref blockType);
serializer.SerializeValue(ref health);
serializer.SerializeValue(ref flags);
}
}
/// <summary>
/// Network-serializable container for entire chunk state.
/// Used for initial sync when clients connect.
/// </summary>
public struct ChunkState : INetworkSerializable
{
public BlockData[] blocks;
public const int CHUNK_SIZE = 4;
public const int BLOCKS_PER_CHUNK = CHUNK_SIZE * CHUNK_SIZE * CHUNK_SIZE; // 64
public ChunkState(int size)
{
blocks = new BlockData[size];
}
/// <summary>
/// Ensure blocks array is initialized
/// </summary>
private void EnsureInitialized()
{
if (blocks == null)
{
blocks = new BlockData[BLOCKS_PER_CHUNK];
}
}
/// <summary>
/// Get block at local coordinates within the chunk
/// </summary>
public BlockData GetBlock(int x, int y, int z)
{
if (blocks == null) return BlockData.Empty;
int index = x + y * CHUNK_SIZE + z * CHUNK_SIZE * CHUNK_SIZE;
if (index < 0 || index >= blocks.Length) return BlockData.Empty;
return blocks[index];
}
/// <summary>
/// Set block at local coordinates within the chunk
/// </summary>
public void SetBlock(int x, int y, int z, BlockData block)
{
EnsureInitialized();
int index = x + y * CHUNK_SIZE + z * CHUNK_SIZE * CHUNK_SIZE;
if (index >= 0 && index < blocks.Length)
{
blocks[index] = block;
}
}
/// <summary>
/// Convert local index to local 3D coordinates
/// </summary>
public static (int x, int y, int z) IndexToLocal(int index)
{
int x = index % CHUNK_SIZE;
int y = (index / CHUNK_SIZE) % CHUNK_SIZE;
int z = index / (CHUNK_SIZE * CHUNK_SIZE);
return (x, y, z);
}
/// <summary>
/// Convert local 3D coordinates to index
/// </summary>
public static int LocalToIndex(int x, int y, int z)
{
return x + y * CHUNK_SIZE + z * CHUNK_SIZE * CHUNK_SIZE;
}
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
// Serialize array length first
int length = BLOCKS_PER_CHUNK;
serializer.SerializeValue(ref length);
if (serializer.IsReader)
{
blocks = new BlockData[length];
}
else if (blocks == null)
{
blocks = new BlockData[length];
}
for (int i = 0; i < length; i++)
{
blocks[i].NetworkSerialize(serializer);
}
}
/// <summary>
/// Create a default initialized ChunkState
/// </summary>
public static ChunkState CreateEmpty()
{
return new ChunkState(BLOCKS_PER_CHUNK);
}
}