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,15 @@
using UnityEngine;
/// <summary>
/// fallback to collision validator
/// </summary>
public class DefaultBlockValidator : IBlockValidator
{
public bool IsValid(BlockEditContext ctx)
{
IValidator v = ctx.GhostObject.GetComponent<IValidator>();
return v != null ? v.IsValidPlacement(ctx.GhostObject) : true;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4dd246c8854b6164584d9a3f53ce4e45
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,109 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DefaultRotationHandler : IRotateHandler
{
private List<float> anglesToRotate = new List<float>();
private List<float> addedAngles = new List<float>();
private int currentAngleIndex = 0;
public DefaultRotationHandler()
{
// add regular angles
anglesToRotate.Add(0);
anglesToRotate.Add(45);
anglesToRotate.Add(90);
anglesToRotate.Add(135);
anglesToRotate.Add(180);
anglesToRotate.Add(225);
anglesToRotate.Add(270);
anglesToRotate.Add(315);
}
public void performRotation(BlockEditContext ctx)
{
if (ctx != null && ctx.IsActive)
{
float previousAngle = anglesToRotate[currentAngleIndex];
currentAngleIndex++;
currentAngleIndex %= anglesToRotate.Count;
float currentAngle = anglesToRotate[currentAngleIndex];
float deltaAngle = currentAngle - previousAngle;
Vector3 pivotPoint = ctx.GhostTransform.position;
if (ctx.TargetSocket != null && ctx.MySocket != null)
{
pivotPoint = ctx.MySocket.transform.position;
}
else if (ctx.AttachPoint != null)
{
pivotPoint = ctx.AttachPoint.position;
}
applyRotation(ctx.GhostTransform, pivotPoint, ctx.RotationAxis, deltaAngle);
}
}
public void addAngle(float angle)
{
if (addedAngles.Contains(angle))
{
return;
}
// normalize the angle (0 - 360)
if (angle >= 0)
{
angle = angle % 360;
}
else
{
while (angle < 0)
{
angle += 360;
}
}
int currentSize = anglesToRotate.Count;
// add it to list
for (int i = 0; i < anglesToRotate.Count; i++)
{
if (angle < anglesToRotate[i])
{
anglesToRotate.Insert(i, angle);
return;
}
}
if (currentSize == anglesToRotate.Count) // it's the largest element in the whole rotations
{
anglesToRotate.Add(angle);
}
addedAngles.Add(angle);
}
public void removeAngle(float angle)
{
anglesToRotate.Remove(angle);
addedAngles.Remove(angle);
}
// should be called when changing the object to be snapped to
public void clearAngles()
{
foreach (float angle in addedAngles)
{
anglesToRotate.Remove(angle);
}
addedAngles.Clear();
// reset to the nearest rotation angle
currentAngleIndex++;
currentAngleIndex %= anglesToRotate.Count;
}
private void applyRotation(Transform transform, Vector3 pivot, Vector3 axis, float angle)
{
transform.RotateAround(pivot, axis, angle);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 91311cb2805395b4487594770ab5bca2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,58 @@
using UnityEngine;
/// <summary>
/// regulare snap performed in free move
/// </summary>
public class DefaultSnapBehavior : ISnapBehavior
{
public bool TrySnap(BlockEditContext ctx)
{
if (ctx.TargetSocket == null) return false;
if (ctx.MySocket != null && !ctx.TargetSocket.CanAccept(ctx.MySocket)) return false;
if (ctx.MySocket != null)
{
// 1. Primary Alignment: Align the exact socket normals
Vector3 myNormal = ctx.MySocket.GetNormal().normalized;
Vector3 targetNormal = -ctx.TargetSocket.GetNormal().normalized;
Quaternion primaryRot = Quaternion.FromToRotation(myNormal, targetNormal);
ctx.GhostTransform.rotation = primaryRot * ctx.GhostTransform.rotation;
// 2. Secondary Alignment: Align the 'Up' (or Forward) vectors to prevent random twisting/rolling
Vector3 mySecondary = Mathf.Abs(Vector3.Dot(ctx.MySocket.transform.up, targetNormal)) < 0.9f
? ctx.MySocket.transform.up
: ctx.MySocket.transform.forward;
Vector3 targetSecondary = Mathf.Abs(Vector3.Dot(ctx.TargetSocket.transform.up, -targetNormal)) < 0.9f
? ctx.TargetSocket.transform.up
: ctx.TargetSocket.transform.forward;
// Project secondary vectors onto the flat plane between the sockets
Vector3 projectedMySecondary = Vector3.ProjectOnPlane(mySecondary, targetNormal).normalized;
Vector3 projectedTargetSecondary = Vector3.ProjectOnPlane(targetSecondary, targetNormal).normalized;
if (projectedMySecondary != Vector3.zero && projectedTargetSecondary != Vector3.zero)
{
// Find the twist angle needed to align the secondary axes
float angle = Vector3.SignedAngle(projectedMySecondary, projectedTargetSecondary, targetNormal);
// Snap to the nearest 45 degrees to allow manual 'R' rotations to persist!
float correction = angle - Mathf.Round(angle / 45f) * 45f;
// Rotate the ghost around its own pivot (since we haven't translated yet)
ctx.GhostTransform.rotation = Quaternion.AngleAxis(correction, targetNormal) * ctx.GhostTransform.rotation;
}
// 3. Translate the ghost so the sockets physically touch
ctx.GhostTransform.position +=
ctx.TargetSocket.transform.position - ctx.MySocket.transform.position;
}
else
{
Transform pivot = ctx.AttachPoint != null ? ctx.AttachPoint : ctx.GhostTransform;
Vector3 pivotOffset = pivot.position - ctx.GhostTransform.position;
ctx.GhostTransform.position = ctx.TargetSocket.transform.position - pivotOffset;
}
return true;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f432ee5d448b4ec409cac4c0ad2b7cd4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,16 @@
using UnityEngine;
/// <summary>
/// Simple material color tint
/// </summary>
public class DefaultVisualFeedback : IVisualFeedback
{
public void OnValid(BlockEditContext ctx) => ApplyTint(ctx, ctx.ValidTint);
public void OnInvalid(BlockEditContext ctx) => ApplyTint(ctx, ctx.InvalidTint);
private static void ApplyTint(BlockEditContext ctx, Color tint)
{
foreach (var r in ctx.GhostRenderers)
if (r != null) r.material.color = tint;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cca890b0c1294ca4b8b8eda4c5667a36
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,80 @@
using UnityEngine;
/// <summary>
/// Placement handler for repositioning an already-placed block.
/// </summary>
public class ExistingBlockPlacementHandler : IPlacementHandler
{
private readonly CommandHandler _commandHandler;
public ExistingBlockPlacementHandler(CommandHandler commandHandler)
{
_commandHandler = commandHandler;
Debug.Log("initialize the ExistingBlockPlacement");
}
public void Commit(BlockEditContext ctx)
{
if (ctx.SourceObject == null) return;
_commandHandler.moveBlock(
ctx.SourceObject.GetComponent<Block>().getBlockId(),
ctx.OriginalPosition,
ctx.GhostTransform.position,
ctx.OriginalRotation,
ctx.GhostTransform.rotation);
// ensure the correct positionning after commiting
RestoreObject(ctx, ctx.GhostTransform.position, ctx.GhostTransform.rotation);
}
public void Cancel(BlockEditContext ctx)
{
if (ctx.SourceObject == null) return;
RestoreObject(ctx, ctx.OriginalPosition, ctx.OriginalRotation);
}
private void RestoreObject(BlockEditContext ctx, Vector3 pos, Quaternion rot)
{
ctx.SourceObject.transform.SetPositionAndRotation(pos, rot);
RestoreMaterialAlphaAndColor(ctx.SourceObject);
SetLayerRecursively(ctx.SourceObject, LayerMask.NameToLayer("Interactable"));
ctx.SourceObject.SetActive(true);
}
private void RestoreMaterialAlphaAndColor(GameObject obj)
{
foreach (var r in obj.GetComponentsInChildren<Renderer>())
{
if (r.gameObject.layer == LayerMask.NameToLayer("Gizmos")) continue;
foreach (var mat in r.materials)
{
if (mat.HasProperty("_Color"))
{
mat.color = new Color(1f, 1f, 1f, 1f);
}
}
}
}
private void SetLayerRecursively(GameObject obj, int layer, System.Func<Transform, bool> Method)
{
if (Method(obj.transform))
obj.layer = layer;
foreach (Transform child in obj.transform)
SetLayerRecursively(child.gameObject, layer, Method);
}
private void SetLayerRecursively(GameObject obj, int layer)
{
SetLayerRecursively(obj, layer, x =>
{
return x.gameObject.layer != LayerMask.NameToLayer("Gizmos");
});
}
public void Debugln()
{
Debug.Log("Hi I'm Existing");
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 75458c1d52fce984e892d59070e8c68c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,13 @@
using DependencyInjection.ScriptableObjects;
using UnityEngine;
/// <summary>
/// Concrete ScriptableObject anchor for IPlacementHandler.
/// Injected at runtime so consumers always hold a stable typed reference
/// and can react to handler swaps via the OnValueChanged event.
/// </summary>
[CreateAssetMenu(fileName = "GhostAnchor", menuName = "Dependency Injection/Ghost Anchor")]
public class GhostAnchor : RuntimeAnchor<IPlacementHandler>
{
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 41e9786ef7c2c154bad698653e1506c4
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 DependencyInjection;
using UnityEngine;
/// <summary>
/// encapsulate the behaviors implementation and added to the ghost block on runtime
/// </summary>
public class GhostController : MonoBehaviour
{
[RuntimeInject]
private IPlacementHandler placementHandler;
[Inject]
private IBlockValidator blockValidator;
private ISnapBehavior snapBehavior;
private IVisualFeedback visualFeedback;
private IRotateHandler rotationHandler;
private GlopalLogger logger;
[Inject]
public void init(GlopalLogger logger)
{
this.logger = logger;
}
void Start()
{
if (blockValidator == null)
{
logger.Log("Hamada msh Maugod");
}
else
{
logger.Log("Laa Hamada Maugod");
}
if (placementHandler == null)
{
logger.Log("Hamada Eltany msh Maugod");
}
else
{
placementHandler.Debugln();
}
Invoke(nameof(check), 15);
}
void check()
{
if (placementHandler == null)
{
logger.Log("Hamada Eltany msh Maugod");
}
else
{
placementHandler.Debugln();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d1495a92f469d22429fde76e6ac478fc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,35 @@
using UnityEngine;
/// <summary>
/// Placement handler for brand-new blocks dragged from the menu.
/// </summary>
public class NewBlockPlacementHandler : IPlacementHandler
{
private readonly CommandHandler _commandHandler;
public NewBlockPlacementHandler(CommandHandler commandHandler)
{
_commandHandler = commandHandler;
Debug.Log("initialize the NewBlockPlacement");
}
public void Commit(BlockEditContext ctx)
{
if (ctx.Block == null) return;
_commandHandler.createBlock(
ctx.Block.getBlockData()?.blockName,
ctx.GhostTransform.position,
ctx.GhostTransform.rotation);
}
public void Cancel(BlockEditContext ctx)
{
// nothing for now
}
public void Debugln()
{
Debug.Log("Hi I'm New");
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e76ae260e459c7b4f931cb9c38a0a562
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,29 @@
using DependencyInjection;
using UnityEngine;
public class Provider : MonoBehaviour, IDependencyProvider
{
[Provide]
public IBlockValidator provideValidator()
{
return new DefaultBlockValidator();
}
[Provide]
public IPlacementHandler providePlacementHandler()
{
Debug.Log("First Handler");
return new NewBlockPlacementHandler(null);
}
public void ChangeAnchorInstance()
{
Injector.Instance.Register<IPlacementHandler>(new ExistingBlockPlacementHandler(null));
Debug.Log("Second Handler");
}
private void Start()
{
Invoke(nameof(ChangeAnchorInstance), 5);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 241c3debd0aeb9840afb1b6b80fe066e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: