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

127 lines
4.0 KiB
C#

using UnityEngine;
/// <summary>
/// Handles interaction between players and chunk-based blocks.
/// Converts raycast hits to block indices and manages damage/reveal requests.
/// </summary>
public static class ChunkInteractionHandler
{
/// <summary>
/// Result of a chunk interaction query
/// </summary>
public struct ChunkHitResult
{
public bool hasHit;
public MineableChunk chunk;
public int blockIndex;
public Vector3 hitPoint;
public Vector3 blockWorldPosition;
public BlockData blockData;
public static ChunkHitResult None => new ChunkHitResult { hasHit = false };
}
/// <summary>
/// Try to get chunk and block info from a raycast hit
/// </summary>
public static ChunkHitResult GetChunkHit(RaycastHit hit)
{
// Try to get MineableChunk from hit collider
MineableChunk chunk = hit.collider.GetComponentInParent<MineableChunk>();
if (chunk == null)
{
return ChunkHitResult.None;
}
// Convert hit point to block index
// Push slightly into the surface using the normal to get the correct block
Vector3 insidePoint = hit.point - hit.normal * 0.01f;
int blockIndex = chunk.WorldPointToBlockIndex(insidePoint);
BlockData blockData = chunk.GetBlock(blockIndex);
// Skip if block is empty
if (blockData.IsEmpty)
{
return ChunkHitResult.None;
}
return new ChunkHitResult
{
hasHit = true,
chunk = chunk,
blockIndex = blockIndex,
hitPoint = hit.point,
blockWorldPosition = chunk.GetBlockWorldPosition(blockIndex),
blockData = blockData
};
}
/// <summary>
/// Try to damage a block at a raycast hit point
/// </summary>
public static bool TryDamageAtPoint(RaycastHit hit, float damage)
{
ChunkHitResult result = GetChunkHit(hit);
if (!result.hasHit) return false;
// Request damage on server
result.chunk.DamageBlockServerRpc(result.blockIndex, (byte)Mathf.Min(255, damage));
return true;
}
/// <summary>
/// Try to damage a block directly on a known chunk
/// </summary>
public static bool TryDamageBlock(MineableChunk chunk, int blockIndex, float damage)
{
if (chunk == null) return false;
BlockData block = chunk.GetBlock(blockIndex);
if (block.IsEmpty) return false;
chunk.DamageBlockServerRpc(blockIndex, (byte)Mathf.Min(255, damage));
return true;
}
/// <summary>
/// Try to reveal a block at a raycast hit point
/// </summary>
public static bool TryRevealAtPoint(RaycastHit hit)
{
MineableChunk chunk = hit.collider.GetComponentInParent<MineableChunk>();
if (chunk == null) return false;
int blockIndex = chunk.WorldPointToBlockIndex(hit.point - hit.normal * 0.1f);
BlockData blockData = chunk.GetBlock(blockIndex);
if (blockData.IsEmpty || blockData.IsDiscovered) return false;
chunk.RevealBlockServerRpc(blockIndex);
return true;
}
/// <summary>
/// Perform a sphere cast to find a targetable block in a chunk
/// </summary>
public static ChunkHitResult SphereCastForBlock(Vector3 origin, Vector3 direction, float radius, float maxDistance, LayerMask chunkLayer)
{
if (Physics.SphereCast(origin, radius, direction, out RaycastHit hit, maxDistance, chunkLayer))
{
return GetChunkHit(hit);
}
return ChunkHitResult.None;
}
/// <summary>
/// Perform a raycast to find a targetable block in a chunk
/// </summary>
public static ChunkHitResult RaycastForBlock(Vector3 origin, Vector3 direction, float maxDistance, LayerMask chunkLayer)
{
if (Physics.Raycast(origin, direction, out RaycastHit hit, maxDistance, chunkLayer))
{
return GetChunkHit(hit);
}
return ChunkHitResult.None;
}
}