Initial commit

This commit is contained in:
HussienX72u
2026-07-21 08:56:10 +03:00
commit 4017028111
9410 changed files with 2150500 additions and 0 deletions
@@ -0,0 +1,54 @@
//using Codice.CM.WorkspaceServer;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DeleteInteractor : MonoBehaviour
{
private BaseInputProvider inputProvider;
private CommandHandler commandHandler;
private SelectionManager selectionManager;
private void Start()
{
commandHandler = CommandHandler.getInstance();
selectionManager = SelectionManager.getInstance();
inputProvider = InputProviderManager.getInstance()?.getCurrentInputProvider();
inputProvider.OnDelete.AddListener(() =>
{
DeleteObjects();
});
}
/// <summary>
/// Delete an object and handle all its connections
/// </summary>
public void DeleteObjects()
{
List<IInteractable> selections = selectionManager.GetCurrentSelections();
List<string> deletedBlockIds = new List<string>();
foreach (IInteractable interactable in selections)
{
if (interactable is BaseInteractable baseInteractable)
{
deletedBlockIds.Add(FindBlockIndex(baseInteractable.gameObject));
}
}
selectionManager.ClearSelection();
commandHandler.removeGroup(deletedBlockIds);
}
/// <summary>
/// Find the index of a block in the environment (for CommandHandler)
/// </summary>
private string FindBlockIndex(GameObject obj)
{
Block blockComponent = obj.GetComponent<Block>();
if (blockComponent != null) return blockComponent.getBlockId();
return null;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f5bedc9ea59bf7242bd864dea16867ed
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,109 @@
using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// Responsible only for raycasting and firing selection events.
/// Socket detection has moved to SnappingSystem.
/// Drag/drop logic has moved to GhostManager.
/// </summary>
public class RayInteractor : MonoBehaviour
{
private static RayInteractor instance;
public static RayInteractor getInstance() => instance;
[SerializeField] private LayerMask gizmoLayerMask;
[SerializeField] private LayerMask interactableLayerMask;
[SerializeField] private LayerMask worldLayerMask;
private BaseInputProvider inputProvider;
private Camera mainCamera;
private RaycastHit lastHit;
private GameObject currentGizmo;
public UnityEvent OnWorldClick;
/// <summary>Fired on click when no ghost is active. Passes the hit IInteractable (or null).</summary>
public UnityEvent<IInteractable> OnSelectEvent = new UnityEvent<IInteractable>();
private void Awake()
{
if (instance == null) instance = this;
else Destroy(gameObject);
}
private void Start()
{
mainCamera = Camera.main;
SetupInput();
}
private void SetupInput()
{
inputProvider = InputProviderManager.getInstance()?.getCurrentInputProvider();
// Update ray hit every time the cursor moves
inputProvider.OnCursorMoved.AddListener(screenPos =>
{
Ray ray = mainCamera.ScreenPointToRay(screenPos);
if (Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity, gizmoLayerMask, QueryTriggerInteraction.Ignore))
{
currentGizmo = hit.collider.gameObject;
lastHit = new RaycastHit();
}
else
{
currentGizmo = null;
if (Physics.Raycast(ray, out hit, Mathf.Infinity, interactableLayerMask, QueryTriggerInteraction.Ignore))
{
lastHit = hit;
}
else if (Physics.Raycast(ray, out hit, Mathf.Infinity, worldLayerMask, QueryTriggerInteraction.Ignore))
{
lastHit = hit;
}
}
Debug.DrawRay(ray.origin, ray.direction * 100f, Color.red);
});
// Place/click: delegate to GhostManager if a ghost is active, otherwise fire selection
inputProvider.OnPlace.AddListener(() =>
{
if (GhostManagerV2.getInstance()?.HasActiveGhost() == true)
return;
IInteractable hitInteractable = lastHit.collider?.GetComponentInParent<IInteractable>();
OnSelectEvent.Invoke(hitInteractable);
if (hitInteractable == null && currentGizmo == null)
OnWorldClick.Invoke();
});
}
/// <summary>Returns true and fills hitInfo if the last raycast produced a valid hit.</summary>
public bool GetHitInfo(out RaycastHit hitInfo)
{
hitInfo = lastHit;
return lastHit.collider != null;
}
/// <summary>
/// Returns the currently hovered gizmo GameObject, or null if no gizmo is hovered.
/// </summary>
public GameObject GetCurrentGizmo() => currentGizmo;
/// <summary>Re-casts a fresh ray from the current mouse position and returns the world hit point.</summary>
public Vector3 GetHitPosition()
{
Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, Mathf.Infinity, interactableLayerMask) ||
Physics.Raycast(ray, out hit, Mathf.Infinity, worldLayerMask))
{
return hit.point;
}
return Vector3.zero;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2014fc0b500d2924eae27636ab6dfa44
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,130 @@
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Handles socket proximity detection, highlighting, and closest-socket tracking.
///
/// Key fixes vs previous version:
/// 1. Searches from col.transform.ROOT — so if OverlapSphere hits a child mesh
/// collider, we still find SocketPoints that are siblings of that mesh.
/// 2. Uses QueryTriggerInteraction.Collide — socket colliders are usually triggers;
/// without this flag the overlap silently finds nothing when
/// Physics.queriesHitTriggers is false in Project Settings.
/// 3. Deduplicates across colliders that share a root, so a multi-collider block
/// doesn't add its sockets multiple times.
/// </summary>
public class SnapSystem : MonoBehaviour
{
private static SnapSystem instance;
public static SnapSystem getInstance() => instance;
[SerializeField] private float socketDetectionRadius = 0.5f;
private readonly List<SocketPoint> nearbySockets = new List<SocketPoint>();
private readonly HashSet<Transform> visitedRoots = new HashSet<Transform>();
private SocketPoint closestSocket;
private void Awake()
{
if (instance == null) instance = this;
else Destroy(gameObject);
}
// -------------------------------------------------------------------------
// Public API
// -------------------------------------------------------------------------
/// <summary>
/// Re-scans for sockets around <paramref name="detectionPoint"/>.
/// Call every frame while a ghost is being dragged.
/// </summary>
/// <param name="detectionPoint">
/// World-space ray hit point on the world surface — NOT the ghost's own position.
/// </param>
/// <param name="ghostRoot">
/// The ghost's root transform. Sockets belonging to this hierarchy are ignored.
/// </param>
public void UpdateSockets(Vector3 detectionPoint, Transform ghostRoot)
{
ClearHighlights();
nearbySockets.Clear();
visitedRoots.Clear();
closestSocket = null;
// QueryTriggerInteraction.Collide ensures trigger colliders (typical for sockets) are found
Collider[] colliders = Physics.OverlapSphere(detectionPoint, socketDetectionRadius,
Physics.AllLayers, QueryTriggerInteraction.Collide);
foreach (Collider col in colliders)
{
Transform root = col.transform.root;
// Skip anything that belongs to the held ghost
if (ghostRoot != null && root == ghostRoot) continue;
// Don't process the same block twice (it may have multiple colliders)
if (visitedRoots.Contains(root)) continue;
visitedRoots.Add(root);
// Search from root so we find ALL SocketPoints on the block,
// regardless of which child collider was hit by the overlap.
foreach (SocketPoint socket in root.GetComponentsInChildren<SocketPoint>())
{
if (socket.IsOccupied()) continue;
nearbySockets.Add(socket);
socket.Highlight(HighlightState.Compatible);
Debug.Log($"[SnappingSystem] Found socket: {socket.name} on {root.name}");
}
}
if (nearbySockets.Count > 0)
{
closestSocket = FindClosest(detectionPoint, nearbySockets);
closestSocket?.Highlight(HighlightState.Active);
Debug.Log($"[SnappingSystem] Closest socket: {closestSocket?.name}");
}
}
/// <summary>Resets all highlight states without clearing the list.</summary>
public void ClearHighlights()
{
foreach (SocketPoint socket in nearbySockets)
if (socket != null)
socket.Highlight(HighlightState.Default);
}
/// <summary>Full reset — clears highlights and all cached data.</summary>
public void Clear()
{
ClearHighlights();
nearbySockets.Clear();
visitedRoots.Clear();
closestSocket = null;
}
public List<SocketPoint> GetNearbySockets() => nearbySockets;
public SocketPoint GetClosestSocket() => closestSocket;
// -------------------------------------------------------------------------
// Private helpers
// -------------------------------------------------------------------------
private static SocketPoint FindClosest(Vector3 position, List<SocketPoint> sockets)
{
SocketPoint closest = null;
float minDist = float.MaxValue;
foreach (SocketPoint socket in sockets)
{
float dist = Vector3.Distance(position, socket.GetTransform().position);
if (dist < minDist)
{
minDist = dist;
closest = socket;
}
}
return closest;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 045c88f5578ae514cb9b66dabdd880bb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,57 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TestCommandInteractor : MonoBehaviour
{
[SerializeField] private CommandHandler commandHandler;
void Update()
{
if (Input.GetKeyDown(KeyCode.C))
{
commandHandler.createBlock("Cube", new Vector3(0, 0, 0), Quaternion.identity);
Debug.Log("Create Command Executed");
}
if (Input.GetKeyDown(KeyCode.M))
{
commandHandler.moveBlock("0", Vector3.zero, new Vector3(Random.Range(-5, 5), Random.Range(-5, 5), Random.Range(-5, 5))
, Quaternion.identity, Quaternion.Euler(new Vector3(Random.Range(-5, 5), Random.Range(-5, 5), Random.Range(-5, 5))));
Debug.Log("Move Command Executed");
}
if (Input.GetKeyDown(KeyCode.R))
{
commandHandler.rotateBlock("0", Quaternion.Euler(Random.Range(0, 180), Random.Range(0, 180), Random.Range(0, 180)));
Debug.Log("Rotate Command Executed");
}
if (Input.GetKeyDown(KeyCode.D))
{
commandHandler.removeBlock("0");
Debug.Log("Delete Command Executed");
}
if (Input.GetKey(KeyCode.LeftControl) && Input.GetKeyDown(KeyCode.Z))
{
commandHandler.undoAction();
Debug.Log("Undo Action Executed");
}
if (Input.GetKey(KeyCode.LeftControl) && Input.GetKeyDown(KeyCode.Y))
{
commandHandler.redoAction();
Debug.Log("Redo Action Executed");
}
if (Input.GetKeyDown(KeyCode.X))
{
commandHandler.clearHistory();
Debug.Log("Clear History Executed");
}
// if (Input.GetKeyDown(KeyCode.S))
// {
// commandHandler.saveCommands();
// }
// if (Input.GetKeyDown(KeyCode.L))
// {
// commandHandler.loadCommands();
// }
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 29fd79635eb86014f95cae3fc00ffa19
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: