Initial commit
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c48d0bb4e268084bb4e662e8a7e843c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
public class AxialMoveBehavior : ToggleBehaviour
|
||||
{
|
||||
|
||||
private SelectionManager selectionManager;
|
||||
private GameObject currentGizmosMove;
|
||||
[SerializeField] private GameObject gizmosMovePrefab;
|
||||
private IInteractable CurrentSelection;
|
||||
|
||||
protected void Start()
|
||||
{
|
||||
selectionManager = SelectionManager.getInstance();
|
||||
selectionManager.SelectionEvent.AddListener(interactable => CurrentSelection = interactable);
|
||||
base.Start();
|
||||
}
|
||||
|
||||
public override void Activate()
|
||||
{
|
||||
GizmoInit();
|
||||
}
|
||||
|
||||
public override void Deactivate()
|
||||
{
|
||||
GizmoDeselect();
|
||||
}
|
||||
|
||||
private void GizmoInit()
|
||||
{
|
||||
if (selectionManager.HasOneSelection())
|
||||
{
|
||||
if (currentGizmosMove == null)
|
||||
{
|
||||
currentGizmosMove = Instantiate(gizmosMovePrefab, CurrentSelection.transform);
|
||||
currentGizmosMove.transform.parent = CurrentSelection.transform;
|
||||
currentGizmosMove.transform.localPosition = Vector3.zero;
|
||||
currentGizmosMove.transform.localRotation = Quaternion.identity;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void GizmoDeselect()
|
||||
{
|
||||
if (currentGizmosMove != null)
|
||||
{
|
||||
Destroy(currentGizmosMove);
|
||||
currentGizmosMove = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7369a4817ce3df499fbd2826b839ebd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public interface IBehaviour
|
||||
{
|
||||
void Activate();
|
||||
|
||||
void Deactivate();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d29b16d510e417f48b045fc3d1ab28f6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public abstract class ToggleBehaviour : MonoBehaviour, IBehaviour
|
||||
{
|
||||
[SerializeField] private Toggle toggle;
|
||||
private bool isActivated = false;
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
toggle.onValueChanged.AddListener(value => init());
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
if (isActivated)
|
||||
Deactivate();
|
||||
else
|
||||
Activate();
|
||||
|
||||
isActivated = !isActivated; // flip the flag
|
||||
}
|
||||
|
||||
public abstract void Activate();
|
||||
|
||||
public abstract void Deactivate();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ce060346105eeb44a18e1c3583bffeb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7b4723e08ae5fc4782baf6f1af7fbaa
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d1103c6a25be6447a68e64d4e21211a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,50 @@
|
||||
using UnityEngine;
|
||||
|
||||
public struct GhostMovementContext
|
||||
{
|
||||
// Ghost
|
||||
public readonly Transform GhostTransform;
|
||||
|
||||
// surface
|
||||
public readonly Vector3 SurfacePoint;
|
||||
public readonly Vector3 SurfaceNormal;
|
||||
|
||||
// Socket snap
|
||||
public readonly SocketPoint MySocket;
|
||||
public readonly SocketPoint TargetSocket;
|
||||
|
||||
// Per-prefab config
|
||||
public readonly Transform AttachPoint;
|
||||
public readonly float FollowSpeed;
|
||||
public readonly float HeightOffset;
|
||||
public readonly bool AlignToSurfaceNormal;
|
||||
public readonly bool SnapRotation;
|
||||
|
||||
// Output, GhostManager reads it after the call
|
||||
public Vector3 RotationAxis;
|
||||
|
||||
public GhostMovementContext(
|
||||
Transform ghostTransform,
|
||||
Vector3 surfacePoint,
|
||||
Vector3 surfaceNormal,
|
||||
SocketPoint mySocket,
|
||||
SocketPoint targetSocket,
|
||||
Transform attachPoint,
|
||||
float followSpeed,
|
||||
float heightOffset,
|
||||
bool alignToSurfaceNormal,
|
||||
bool snapRotation)
|
||||
{
|
||||
GhostTransform = ghostTransform;
|
||||
SurfacePoint = surfacePoint;
|
||||
SurfaceNormal = surfaceNormal;
|
||||
MySocket = mySocket;
|
||||
TargetSocket = targetSocket;
|
||||
AttachPoint = attachPoint;
|
||||
FollowSpeed = followSpeed;
|
||||
HeightOffset = heightOffset;
|
||||
AlignToSurfaceNormal = alignToSurfaceNormal;
|
||||
SnapRotation = snapRotation;
|
||||
RotationAxis = Vector3.up;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c3839bd09a5f994a978d6ec4d28907e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,4 @@
|
||||
public interface IBlockValidator
|
||||
{
|
||||
bool IsValid(BlockEditContext ctx);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b7bdf5f93500cc4ea122aed8590f119
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,12 @@
|
||||
/// <summary>
|
||||
/// Drives how the ghost object moves and orients each frame.
|
||||
/// </summary>
|
||||
public interface IGhostMovementStrategy
|
||||
{
|
||||
/// <summary>
|
||||
/// Called every frame when there is an active ghost.
|
||||
/// Responsible for updating GhostTransform.position and .rotation.
|
||||
/// Must also write ctx.RotationAxis before returning.
|
||||
/// </summary>
|
||||
void UpdateMovement(ref GhostMovementContext ctx);
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88109b2aac07c13428dd1bb3bbf4663a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
public interface IPlacementHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// Commit the ghost's current transform as the final placed state.
|
||||
/// </summary>
|
||||
void Commit(BlockEditContext ctx);
|
||||
|
||||
/// <summary>
|
||||
/// Cancel the edit and restore any previous state.
|
||||
/// </summary>
|
||||
void Cancel(BlockEditContext ctx);
|
||||
|
||||
void Debugln();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a79e2636d81808f4ab5c5769d6ea3057
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,22 @@
|
||||
public interface IRotateHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// handle rotation of Ghost Transfrom
|
||||
/// </summary>
|
||||
void performRotation(BlockEditContext ctx);
|
||||
|
||||
/// <summary>
|
||||
/// add an angle to the allowed angles to rotate with
|
||||
/// </summary>
|
||||
void addAngle(float angle);
|
||||
|
||||
/// <summary>
|
||||
/// remove that angle
|
||||
/// </summary>
|
||||
void removeAngle(float angle);
|
||||
|
||||
/// <summary>
|
||||
/// clear all added angles
|
||||
/// </summary>
|
||||
void clearAngles();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 83bb80b9424f55842853a57c456c0401
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
public interface ISnapBehavior
|
||||
{
|
||||
/// <summary>
|
||||
/// Called every frame after socket scanning.
|
||||
/// Returns true if a snap was applied and false if failed.
|
||||
/// </summary>
|
||||
bool TrySnap(BlockEditContext ctx);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74a4d0f44a9d4224f892223405ba68cc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,5 @@
|
||||
public interface IVisualFeedback
|
||||
{
|
||||
void OnValid(BlockEditContext ctx);
|
||||
void OnInvalid(BlockEditContext ctx);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d02dfbcf6de3142458a6092ebae279bb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,7 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Grant InteractionSystem (which contains GhostManagerV2) access to internal
|
||||
// members of Scripts.BlockExtensions (which contains BlockEditContext).
|
||||
// This preserves internal encapsulation against all other assemblies while
|
||||
// keeping the two tightly-coupled modules able to work together.
|
||||
[assembly: InternalsVisibleTo("InteractionSystem")]
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 32603667c964c0741a0654170266de51
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
/// <summary>
|
||||
/// Self-contained state for one block being edited (placed or repositioned).
|
||||
/// </summary>
|
||||
public class BlockEditContext
|
||||
{
|
||||
// Core data
|
||||
public GameObject GhostObject { get; internal set; }
|
||||
public Transform GhostTransform => GhostObject != null ? GhostObject.transform : null;
|
||||
public GameObject SourceObject { get; internal set; } // null for new blocks
|
||||
public BlockData BlockData { get; internal set; }
|
||||
public Renderer[] GhostRenderers { get; internal set; }
|
||||
|
||||
// visual data
|
||||
public bool AlignToSurfaceNormal { get; internal set; } = true;
|
||||
public bool SnapRotation { get; internal set; } = false;
|
||||
public float FollowSpeed { get; internal set; } = 20f;
|
||||
public float HeightOffset { get; internal set; } = 0f;
|
||||
public Color ValidTint { get; internal set; } = new Color(0.5f, 1f, 0.5f, 1f);
|
||||
public Color InvalidTint { get; internal set; } = new Color(1f, 0.5f, 0.5f, 1f);
|
||||
public Transform AttachPoint { get; internal set; }
|
||||
|
||||
// type data
|
||||
public bool IsEditingExisting { get; internal set; }
|
||||
public Vector3 OriginalPosition { get; internal set; }
|
||||
public Quaternion OriginalRotation { get; internal set; }
|
||||
public bool IsValidPlacement { get; internal set; } = true;
|
||||
|
||||
// editable state
|
||||
public Vector3 SurfacePoint { get; internal set; }
|
||||
public Vector3 SurfaceNormal { get; internal set; } = Vector3.up;
|
||||
public Vector3 RotationAxis { get; internal set; } = Vector3.up;
|
||||
|
||||
// sockets
|
||||
public SocketPoint TargetSocket { get; internal set; }
|
||||
public SocketPoint MySocket { get; internal set; }
|
||||
|
||||
// block references
|
||||
public Block Block { get; internal set; }
|
||||
public JointBlock JointBlock { get; internal set; }
|
||||
public SocketContainer Container { get; internal set; }
|
||||
|
||||
|
||||
// Behaviors
|
||||
public IGhostMovementStrategy CurrentStrategy { get; set; }
|
||||
public ISnapBehavior SnapBehavior { get; set; }
|
||||
public IPlacementHandler PlacementHandler { get; set; }
|
||||
public IBlockValidator Validator { get; set; }
|
||||
public IVisualFeedback VisualFeedback { get; set; }
|
||||
public IRotateHandler RotationHandler { get; set; }
|
||||
|
||||
|
||||
public bool IsActive => GhostObject != null && GhostObject.activeSelf;
|
||||
|
||||
public void SetRotationAxis(Vector3 axis) => RotationAxis = axis;
|
||||
|
||||
internal void SetFrameState(Vector3 surfacePoint, Vector3 surfaceNormal, SocketPoint mySocket, SocketPoint targetSocket)
|
||||
{
|
||||
SurfacePoint = surfacePoint;
|
||||
SurfaceNormal = surfaceNormal;
|
||||
MySocket = mySocket;
|
||||
TargetSocket = targetSocket;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3de2505470ee0ae4e8f2c0bfe9636ab8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f7a1ac0be730984ea7518e191b2fa5b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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:
|
||||
+80
@@ -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");
|
||||
}
|
||||
}
|
||||
+11
@@ -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");
|
||||
}
|
||||
}
|
||||
+11
@@ -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:
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "Scripts.BlockExtensions",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:0f8d877125e73cc40a31b031c2e5fe60",
|
||||
"GUID:b59dd872b9d7ceb4094d9c76ee4f729c",
|
||||
"GUID:87ecf4ad9955b8f49b5bd39d4f087204",
|
||||
"GUID:c16923da89c230b46a6c01482752a2ba",
|
||||
"GUID:932aa9200c814388a2af10406d3eb62e",
|
||||
"GUID:fc759e1ad51443e5b90aa7b791e33f55",
|
||||
"GUID:9f27db84ae564425a5b8e82f2f331060"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bbd29cf08aeef3242bbcb0fd3d725c3b
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43df35c72efc6fc4fb793a9a587cdf12
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public abstract class Block : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private BlockData blockData;
|
||||
private string blockId;
|
||||
|
||||
|
||||
public abstract void setupBlock();
|
||||
public abstract void simulate();
|
||||
|
||||
public BlockData getBlockData()
|
||||
{
|
||||
return blockData;
|
||||
}
|
||||
|
||||
public void SetBlockData(BlockData BD) => blockData = BD;
|
||||
|
||||
public void setBlockId(string id)
|
||||
{
|
||||
blockId = id;
|
||||
}
|
||||
public string getBlockId()
|
||||
{
|
||||
return blockId;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 92f0bbe7028183946b24328df29a379b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
using UnityEngine;
|
||||
|
||||
[CreateAssetMenu(fileName = "BlockData", menuName = "Blocks/Block Data", order = 51)]
|
||||
public class BlockData : ScriptableObject
|
||||
{
|
||||
[Header("Block Info")]
|
||||
public string blockName;
|
||||
public GameObject blockPrefab;
|
||||
public CategoryData associatedCategory;
|
||||
|
||||
[Header("Icon")]
|
||||
public Texture2D icon;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b0f036c260429df458bc55fbece6c077
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,70 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
public class BlockFactory : MonoBehaviour
|
||||
{
|
||||
private static BlockFactory Instance;
|
||||
|
||||
private Environment environment;
|
||||
private List<BlockData> blockDataList;
|
||||
private Dictionary<string, BlockData> blocksData = new Dictionary<string, BlockData>();
|
||||
public static BlockFactory getInstance()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
GameObject factoryObject = new GameObject("blockFactory");
|
||||
Instance = factoryObject.AddComponent<BlockFactory>();
|
||||
}
|
||||
return Instance;
|
||||
}
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance == null)
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
environment = Environment.getInstance();
|
||||
blockDataList = Resources.LoadAll<BlockData>("BlocksData").ToList();
|
||||
|
||||
foreach (BlockData blockData in blockDataList)
|
||||
{
|
||||
blocksData.Add(blockData.blockName, blockData);
|
||||
}
|
||||
}
|
||||
|
||||
public GameObject createblock(string prefabId, Vector3 position, Quaternion rotation, string id = null, bool layerDiff = false)
|
||||
{
|
||||
Debug.Log(prefabId);
|
||||
|
||||
if (blocksData.ContainsKey(prefabId))
|
||||
{
|
||||
GameObject blockPrefab = blocksData[prefabId].blockPrefab;
|
||||
GameObject block = Instantiate(blockPrefab, position, rotation);
|
||||
if (layerDiff)
|
||||
{
|
||||
block.gameObject.layer = LayerMask.NameToLayer("Ignore Interaction");
|
||||
Debug.Log($"Set layer of {block} to {LayerMask.LayerToName(block.layer)}");
|
||||
}
|
||||
// the only blocks added to the environment is created with BlockFactory
|
||||
environment.addBlock(block.GetComponent<Block>(), id);
|
||||
return block;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"block with PrefabId {prefabId} not found!");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6119bef9c1e159341b755fad6f48329c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "ItemSystem",
|
||||
"rootNamespace": "",
|
||||
"references": [],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f8d877125e73cc40a31b031c2e5fe60
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[CreateAssetMenu(fileName = "Category", menuName = "YoussefScripts/Create a Category")]
|
||||
public class CategoryData : ScriptableObject
|
||||
{
|
||||
public string ID;
|
||||
public List<BlockData> blocks;
|
||||
public Sprite icon;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ec390037e79ae134b9fe859322a98be8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class CodingBlock : Block
|
||||
{
|
||||
public override void setupBlock()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public override void simulate()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1aca36b1d6467654a9a832b13390ed0e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class ElectricalBlock : Block
|
||||
{
|
||||
public override void setupBlock()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public override void simulate()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 10902277cb1a7434ebcb6c50edc00c52
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,117 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
public class Environment : MonoBehaviour
|
||||
{
|
||||
private static Environment instance;
|
||||
|
||||
private Dictionary<string, Block> blockRegistry = new Dictionary<string, Block>();
|
||||
|
||||
public UnityEvent<Block> onBlockAddedEvent;
|
||||
public UnityEvent<Block, Vector3, Quaternion> onBlockMovedEvt;
|
||||
public UnityEvent<Block> onBlockRemovedEvent;
|
||||
public UnityEvent onChangeEvent;
|
||||
|
||||
public static Environment getInstance()
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = FindObjectOfType<Environment>();
|
||||
if (instance == null)
|
||||
{
|
||||
GameObject environmentObject = new GameObject("Environment");
|
||||
instance = environmentObject.AddComponent<Environment>();
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public Dictionary<String, Block> getBlockRegistry()
|
||||
{
|
||||
return blockRegistry;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
public void addBlock(Block block, string existingUUID = null)
|
||||
{
|
||||
// 1. Assign ID: Use existing (Undo/Redo) or generate a new one (Fresh placement)
|
||||
string uuid = string.IsNullOrEmpty(existingUUID) ? Guid.NewGuid().ToString() : existingUUID;
|
||||
|
||||
block.setBlockId(uuid);
|
||||
|
||||
// 2. Register in the dictionary
|
||||
if (!blockRegistry.ContainsKey(uuid))
|
||||
{
|
||||
blockRegistry.Add(uuid, block);
|
||||
}
|
||||
else
|
||||
{
|
||||
blockRegistry[uuid] = block; // Update reference if already exists
|
||||
}
|
||||
applyChanges();
|
||||
onBlockAddedEvent.Invoke(block);
|
||||
}
|
||||
|
||||
public void moveBlock(Block block, Vector3 oldPos, Quaternion oldRot, Vector3 newPos, Quaternion newRot)
|
||||
{
|
||||
block.transform.SetPositionAndRotation(newPos, newRot);
|
||||
onBlockMovedEvt.Invoke(block, oldPos, oldRot);
|
||||
applyChanges();
|
||||
}
|
||||
|
||||
public void removeBlock(string uuid)
|
||||
{
|
||||
if (blockRegistry.TryGetValue(uuid, out Block block))
|
||||
{
|
||||
onBlockRemovedEvent.Invoke(block);
|
||||
blockRegistry.Remove(uuid);
|
||||
applyChanges();
|
||||
}
|
||||
}
|
||||
|
||||
public void applyChanges()
|
||||
{
|
||||
onChangeEvent.Invoke();
|
||||
}
|
||||
public void completeDestroyBlock(Block block)
|
||||
{
|
||||
if (block != null)
|
||||
Destroy(block.gameObject);
|
||||
}
|
||||
|
||||
public Block getBlock(string uuid)
|
||||
{
|
||||
if (blockRegistry.TryGetValue(uuid, out Block block))
|
||||
{
|
||||
return block;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void clearEnvironment()
|
||||
{
|
||||
foreach (var blockEntry in blockRegistry)
|
||||
{
|
||||
if (blockEntry.Value != null)
|
||||
{
|
||||
Destroy(blockEntry.Value.gameObject);
|
||||
}
|
||||
}
|
||||
blockRegistry.Clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f8e7f129da58b9746a67217bcf1a4aa9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class MechanicalBlock : Block
|
||||
{
|
||||
|
||||
public override void setupBlock()
|
||||
{
|
||||
}
|
||||
|
||||
public override void simulate()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c4a1be166f8c7184ab860f9a010f5764
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class MechanicalJoint : Block
|
||||
{
|
||||
public override void setupBlock()
|
||||
{
|
||||
// unimplemented as it's a Joint
|
||||
}
|
||||
|
||||
public override void simulate()
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a09709a730033f4986af4e51fe685b2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 626a4b0a2a746e148bda3a6624d0c7ff
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,212 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
public class CameraControl : MonoBehaviour
|
||||
{
|
||||
[Header("Dependencies")]
|
||||
private BaseInputProvider inputProvider;
|
||||
|
||||
[Header("Settings")]
|
||||
public Transform pivotPoint;
|
||||
public LayerMask obstacleLayer;
|
||||
|
||||
[Header("Speeds")]
|
||||
public float panSpeed = 0.5f;
|
||||
public float rotateSpeed = 5.0f;
|
||||
public float zoomSpeed = 5.0f;
|
||||
public float minZoom = 2.0f;
|
||||
public float maxZoom = 50.0f;
|
||||
|
||||
[Header("Smoothness")]
|
||||
public bool enableSmoothing = true;
|
||||
public float smoothTime = 0.1f;
|
||||
|
||||
// ---- Internal State ----
|
||||
private Vector3 _targetPosition;
|
||||
private Quaternion _targetRotation;
|
||||
private float _targetZoom;
|
||||
private Vector3 _currentVelocity;
|
||||
|
||||
private bool _isPanning;
|
||||
private bool _isOrbiting;
|
||||
private Vector2 _cursorScreenPos; // kept up to date by OnCursorMoved
|
||||
|
||||
private Camera _cam;
|
||||
|
||||
public bool isInputLocked = false;
|
||||
|
||||
private bool isInitialized = false;
|
||||
|
||||
// -------------------------------------------------------
|
||||
// Lifecycle
|
||||
// -------------------------------------------------------
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_cam = GetComponent<Camera>();
|
||||
if (pivotPoint == null)
|
||||
{
|
||||
var pivotObj = new GameObject("CameraPivot");
|
||||
pivotObj.transform.position = transform.position + transform.forward * 10f;
|
||||
pivotPoint = pivotObj.transform;
|
||||
}
|
||||
|
||||
_targetPosition = pivotPoint.position;
|
||||
_targetRotation = pivotPoint.rotation;
|
||||
_targetZoom = Vector3.Distance(transform.position, pivotPoint.position);
|
||||
|
||||
inputProvider = InputProviderManager.getInstance()?.getCurrentInputProvider();
|
||||
|
||||
inputProvider.OnCursorMoved.AddListener(OnCursorMoved);
|
||||
inputProvider.OnCursorDelta.AddListener(OnCursorDelta);
|
||||
inputProvider.OnPanStart.AddListener(OnPanStart);
|
||||
inputProvider.OnPanEnd.AddListener(OnPanEnd);
|
||||
inputProvider.OnRotateStart.AddListener(OnRotateStart);
|
||||
inputProvider.OnRotateEnd.AddListener(OnRotateEnd);
|
||||
inputProvider.OnZoom.AddListener(OnZoom);
|
||||
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (!isInitialized) return;
|
||||
|
||||
inputProvider.OnCursorMoved.AddListener(OnCursorMoved);
|
||||
inputProvider.OnCursorDelta.AddListener(OnCursorDelta);
|
||||
inputProvider.OnPanStart.AddListener(OnPanStart);
|
||||
inputProvider.OnPanEnd.AddListener(OnPanEnd);
|
||||
inputProvider.OnRotateStart.AddListener(OnRotateStart);
|
||||
inputProvider.OnRotateEnd.AddListener(OnRotateEnd);
|
||||
inputProvider.OnZoom.AddListener(OnZoom);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
inputProvider.OnCursorMoved.RemoveListener(OnCursorMoved);
|
||||
inputProvider.OnCursorDelta.RemoveListener(OnCursorDelta);
|
||||
inputProvider.OnPanStart.RemoveListener(OnPanStart);
|
||||
inputProvider.OnPanEnd.RemoveListener(OnPanEnd);
|
||||
inputProvider.OnRotateStart.RemoveListener(OnRotateStart);
|
||||
inputProvider.OnRotateEnd.RemoveListener(OnRotateEnd);
|
||||
inputProvider.OnZoom.RemoveListener(OnZoom);
|
||||
}
|
||||
|
||||
private void LateUpdate() => ApplyMovement();
|
||||
|
||||
// -------------------------------------------------------
|
||||
// Input event handlers
|
||||
// -------------------------------------------------------
|
||||
|
||||
private void OnCursorMoved(Vector2 screenPos)
|
||||
{
|
||||
_cursorScreenPos = screenPos;
|
||||
}
|
||||
|
||||
private void OnPanStart(Vector2 cursorScreenPos)
|
||||
{
|
||||
if (isInputLocked) return;
|
||||
|
||||
Ray ray = _cam.ScreenPointToRay(cursorScreenPos);
|
||||
_isPanning = !Physics.Raycast(ray, out _, 1000f, obstacleLayer);
|
||||
}
|
||||
|
||||
private void OnPanEnd() => _isPanning = false;
|
||||
|
||||
private void OnRotateStart()
|
||||
{
|
||||
if (!isInputLocked) _isOrbiting = true;
|
||||
}
|
||||
|
||||
private void OnRotateEnd() => _isOrbiting = false;
|
||||
|
||||
private void OnCursorDelta(Vector2 delta)
|
||||
{
|
||||
if (_isPanning)
|
||||
{
|
||||
if (!InputModeManager.Is(InputMode.Camera)) return;
|
||||
Vector3 move = -transform.right * (delta.x * panSpeed * 0.01f)
|
||||
+ -transform.up * (delta.y * panSpeed * 0.01f);
|
||||
_targetPosition += move;
|
||||
}
|
||||
|
||||
if (_isOrbiting)
|
||||
{
|
||||
float mouseX = delta.x * rotateSpeed;
|
||||
float mouseY = -delta.y * rotateSpeed;
|
||||
|
||||
Vector3 euler = _targetRotation.eulerAngles;
|
||||
euler.y += mouseX;
|
||||
euler.x += mouseY;
|
||||
|
||||
if (euler.x > 180f) euler.x -= 360f;
|
||||
euler.x = Mathf.Clamp(euler.x, -85f, 85f);
|
||||
|
||||
_targetRotation = Quaternion.Euler(euler);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnZoom(float scrollValue)
|
||||
{
|
||||
if (!InputModeManager.Is(InputMode.Camera)) return;
|
||||
|
||||
_targetZoom -= scrollValue * zoomSpeed * 0.05f;
|
||||
_targetZoom = Mathf.Clamp(_targetZoom, minZoom, maxZoom);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------
|
||||
// Movement application (unchanged logic)
|
||||
// -------------------------------------------------------
|
||||
|
||||
private void ApplyMovement()
|
||||
{
|
||||
if (enableSmoothing)
|
||||
{
|
||||
pivotPoint.position = Vector3.SmoothDamp(
|
||||
pivotPoint.position, _targetPosition, ref _currentVelocity, smoothTime);
|
||||
|
||||
pivotPoint.rotation = Quaternion.Slerp(
|
||||
pivotPoint.rotation, _targetRotation, Time.deltaTime * (1f / smoothTime));
|
||||
}
|
||||
else
|
||||
{
|
||||
pivotPoint.position = _targetPosition;
|
||||
pivotPoint.rotation = _targetRotation;
|
||||
}
|
||||
|
||||
transform.position = pivotPoint.position - pivotPoint.forward * _targetZoom;
|
||||
transform.LookAt(pivotPoint);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------
|
||||
// Public API
|
||||
// -------------------------------------------------------
|
||||
|
||||
public void SnapToDirection(Vector3 direction)
|
||||
{
|
||||
Vector3 cameraUp = Mathf.Abs(Vector3.Dot(direction, Vector3.up)) > 0.99f
|
||||
? Vector3.forward
|
||||
: Vector3.up;
|
||||
|
||||
_targetRotation = Quaternion.LookRotation(direction, cameraUp);
|
||||
_targetPosition = pivotPoint.position;
|
||||
_currentVelocity = Vector3.zero;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------
|
||||
// Gizmos
|
||||
// -------------------------------------------------------
|
||||
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
if (pivotPoint == null) return;
|
||||
|
||||
Gizmos.color = Color.yellow;
|
||||
Gizmos.DrawWireSphere(pivotPoint.position, 0.5f);
|
||||
Gizmos.DrawLine(transform.position, pivotPoint.position);
|
||||
|
||||
Gizmos.color = Color.cyan;
|
||||
Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
|
||||
Gizmos.DrawFrustum(Vector3.zero, GetComponent<Camera>().fieldOfView, maxZoom, minZoom, 1.0f);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2ff809502f69bf4419a49383fe2deff4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Scripts.Camera",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:d5be31af97e8e5e458cc6c5d560bb7cc"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7239d94c510c9fd4da3ba5963eadd5d6
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,132 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using UnityEngine.UI;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
public class ViewCubeController : MonoBehaviour
|
||||
{
|
||||
[Header("References")]
|
||||
public Camera mainCam; // The Base Camera
|
||||
public Camera viewCubeCam; // The Overlay Camera/Texture Camera
|
||||
private CameraControl CameraController; // Your camera movement script
|
||||
public RawImage viewCubeImage;
|
||||
private EventTrigger eventTrigger;
|
||||
private bool isPointerInViewCube = false;
|
||||
|
||||
[Header("Settings")]
|
||||
private Transform cubeContainer;
|
||||
public LayerMask viewCubeLayer;
|
||||
|
||||
// NEW: We need the RectTransform to calculate positions correctly
|
||||
private RectTransform rawImageRect;
|
||||
// NEW: Store the last ray for debugging in Gizmos
|
||||
private Ray debugRay;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
cubeContainer = transform;
|
||||
if (mainCam) CameraController = mainCam.GetComponent<CameraControl>();
|
||||
|
||||
// Cache the RectTransform so we can access width/height later
|
||||
rawImageRect = viewCubeImage.GetComponent<RectTransform>();
|
||||
|
||||
eventTrigger = viewCubeImage.GetComponent<EventTrigger>();
|
||||
|
||||
EventTrigger.Entry entry = new EventTrigger.Entry();
|
||||
entry.eventID = EventTriggerType.PointerEnter;
|
||||
entry.callback.AddListener((data) => { isPointerInViewCube = true; });
|
||||
eventTrigger.triggers.Add(entry);
|
||||
|
||||
entry = new EventTrigger.Entry();
|
||||
entry.eventID = EventTriggerType.PointerExit;
|
||||
entry.callback.AddListener((data) => { isPointerInViewCube = false; });
|
||||
eventTrigger.triggers.Add(entry);
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
RotateCube();
|
||||
|
||||
if (CameraController != null)
|
||||
{
|
||||
CameraController.isInputLocked = isPointerInViewCube;
|
||||
}
|
||||
|
||||
if (isPointerInViewCube)
|
||||
{
|
||||
CalculateCurrentRay();
|
||||
}
|
||||
|
||||
DetectClick();
|
||||
}
|
||||
|
||||
void RotateCube()
|
||||
{
|
||||
if (mainCam == null || cubeContainer == null) return;
|
||||
cubeContainer.rotation = mainCam.transform.rotation;
|
||||
}
|
||||
|
||||
// NEW FUNCTION: Handles the math to convert Screen Pixels -> UI Pixels -> Camera Ray
|
||||
void CalculateCurrentRay()
|
||||
{
|
||||
Vector2 localPoint;
|
||||
// 1. Convert Screen Mouse Point to a point inside the RawImage rectangle
|
||||
// The 'null' param works for "Screen Space - Overlay" canvas.
|
||||
// If your canvas is "Screen Space - Camera", pass the UI Camera instead of null.
|
||||
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
||||
rawImageRect,
|
||||
Input.mousePosition,
|
||||
null,
|
||||
out localPoint))
|
||||
{
|
||||
// 2. Normalize positions to 0-1 range (Viewport coordinates)
|
||||
// LocalPoint (0,0) is the center of the image. We shift it by +0.5 to make (0,0) the bottom-left.
|
||||
float normalizedX = (localPoint.x / rawImageRect.rect.width) + 0.5f;
|
||||
float normalizedY = (localPoint.y / rawImageRect.rect.height) + 0.5f;
|
||||
|
||||
// 3. Create the ray from the ViewCube Camera using these coordinates
|
||||
debugRay = viewCubeCam.ViewportPointToRay(new Vector3(normalizedX, normalizedY, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void DetectClick()
|
||||
{
|
||||
if (Input.GetMouseButtonDown(0) && isPointerInViewCube)
|
||||
{
|
||||
// We use the ray calculated in CalculateCurrentRay()
|
||||
if (Physics.Raycast(debugRay, out RaycastHit hit, 100f, viewCubeLayer))
|
||||
{
|
||||
Debug.Log("View Cube Hit: " + hit.collider.name);
|
||||
|
||||
Vector3 targetDir = Vector3.zero;
|
||||
|
||||
switch (hit.collider.name)
|
||||
{
|
||||
case "Front": targetDir = Vector3.forward; break;
|
||||
case "Back": targetDir = Vector3.back; break;
|
||||
case "Left": targetDir = Vector3.left; break;
|
||||
case "Right": targetDir = Vector3.right; break;
|
||||
case "Top": targetDir = Vector3.up; break;
|
||||
case "Bottom": targetDir = Vector3.down; break;
|
||||
}
|
||||
|
||||
if (targetDir != Vector3.zero && CameraController != null)
|
||||
{
|
||||
CameraController.SnapToDirection(targetDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DRAW GIZMOS: This will now draw the ray based on where your mouse is hovering
|
||||
private void OnDrawGizmos()
|
||||
{
|
||||
if (viewCubeCam == null) return;
|
||||
|
||||
Gizmos.color = Color.red;
|
||||
// Draw the ray stored in debugRay
|
||||
Gizmos.DrawLine(debugRay.origin, debugRay.origin + debugRay.direction * 100f);
|
||||
// Draw a small sphere at the ray start point to confirm it's coming from the camera
|
||||
Gizmos.DrawSphere(debugRay.origin, 0.2f);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1705a4f5a2431a740a1ff509d1051cc4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a976f37bc8f63e4bb7499c81fc84d15
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,61 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class CommandDTO
|
||||
{
|
||||
[JsonProperty]
|
||||
private string commandName;
|
||||
|
||||
[JsonProperty]
|
||||
private Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
|
||||
public string CommandName => commandName;
|
||||
public Dictionary<string, object> Parameters => parameters;
|
||||
|
||||
public ICommand converToCommand()
|
||||
{
|
||||
// Implementation for converting DTO to Command
|
||||
switch (commandName)
|
||||
{
|
||||
case "CreateCommand":
|
||||
return new CreateBlockCommand(this);
|
||||
case "MoveCommand":
|
||||
return new MoveBlockCommand(this);
|
||||
case "RotateCommand":
|
||||
return new RotateblockCommand(this);
|
||||
case "DeleteCommand":
|
||||
return new DeleteBlockCommand(this);
|
||||
case "DeleteGroup":
|
||||
return new DeleteGroupCommand(this);
|
||||
|
||||
default:
|
||||
Debug.LogWarning($"Unknown command name: {commandName}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandDTOBuilder
|
||||
{
|
||||
private string commandName;
|
||||
private Dictionary<string, object> parameters = new Dictionary<string, object>();
|
||||
public CommandDTOBuilder SetCommandName(string name)
|
||||
{
|
||||
this.commandName = name;
|
||||
return this;
|
||||
}
|
||||
public CommandDTOBuilder AddParameter(string key, object value)
|
||||
{
|
||||
parameters[key] = value;
|
||||
return this;
|
||||
}
|
||||
public CommandDTO Build()
|
||||
{
|
||||
CommandDTO commandDTO = new CommandDTO();
|
||||
commandDTO.commandName = this.commandName;
|
||||
commandDTO.parameters = this.parameters;
|
||||
return commandDTO;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c59b88464539e84c87b396c1cae0b89
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,111 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
public class CommandHandler : MonoBehaviour
|
||||
{
|
||||
private static CommandHandler instance;
|
||||
|
||||
private CommandManager commandManager;
|
||||
private Environment environment;
|
||||
|
||||
|
||||
public static CommandHandler getInstance()
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = FindObjectOfType<CommandHandler>();
|
||||
if (instance == null)
|
||||
{
|
||||
GameObject commandHandlerObject = new GameObject("CommandHandler");
|
||||
instance = commandHandlerObject.AddComponent<CommandHandler>();
|
||||
}
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
commandManager = CommandManager.getInstance();
|
||||
environment = Environment.getInstance();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// Detect Ctrl+Z for undo and Ctrl+Y for redo
|
||||
bool ctrl = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
|
||||
if (ctrl)
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.Z))
|
||||
{
|
||||
Debug.Log("Ctrl+Z detected: Undo action");
|
||||
undoAction();
|
||||
}
|
||||
else if (Input.GetKeyDown(KeyCode.Y))
|
||||
{
|
||||
Debug.Log("Ctrl+Y detected: Redo action");
|
||||
redoAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void createBlock(string prefabId, Vector3 position, Quaternion rotation)
|
||||
{
|
||||
ICommand createCommand = new CreateBlockCommand(prefabId, position, rotation);
|
||||
commandManager.executeCommand(createCommand);
|
||||
}
|
||||
|
||||
public void moveBlock(string blockId, Vector3 prePosition, Vector3 newPosition, Quaternion preRotation, Quaternion newRotation)
|
||||
{
|
||||
ICommand moveCommand = new MoveBlockCommand(blockId, prePosition, newPosition, preRotation, newRotation);
|
||||
commandManager.executeCommand(moveCommand);
|
||||
}
|
||||
|
||||
public void removeBlock(string blockId)
|
||||
{
|
||||
ICommand deleteCommand = new DeleteBlockCommand(blockId);
|
||||
commandManager.executeCommand(deleteCommand);
|
||||
}
|
||||
|
||||
public void removeGroup(List<string> blockIds)
|
||||
{
|
||||
ICommand deleteCommand = new DeleteGroupCommand(blockIds);
|
||||
commandManager.executeCommand(deleteCommand);
|
||||
}
|
||||
|
||||
public void rotateBlock(string blockId, Quaternion newRotation)
|
||||
{
|
||||
ICommand rotateCommand = new RotateblockCommand(blockId, newRotation);
|
||||
commandManager.executeCommand(rotateCommand);
|
||||
}
|
||||
|
||||
public void undoAction()
|
||||
{
|
||||
commandManager.undo();
|
||||
}
|
||||
|
||||
public void redoAction()
|
||||
{
|
||||
commandManager.redo();
|
||||
}
|
||||
|
||||
public void clearHistory()
|
||||
{
|
||||
commandManager.clearHistory();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8802da992aedca34181376075fc0c011
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,73 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class CommandManager
|
||||
{
|
||||
private static CommandManager instance;
|
||||
|
||||
private LinkedList<ICommand> commandStack = new LinkedList<ICommand>();
|
||||
private LinkedList<ICommand> redoStack = new LinkedList<ICommand>();
|
||||
|
||||
private int maxCapacity = 100; // added to prevent memory leak in the long run
|
||||
|
||||
private CommandManager()
|
||||
{
|
||||
}
|
||||
|
||||
public static CommandManager getInstance()
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
instance = new CommandManager();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void setMaxCapacity(int capacity)
|
||||
{
|
||||
maxCapacity = capacity;
|
||||
}
|
||||
|
||||
public void executeCommand(ICommand command)
|
||||
{
|
||||
command.execute();
|
||||
|
||||
commandStack.AddFirst(command);
|
||||
redoStack.Clear();
|
||||
if (commandStack.Count > maxCapacity)
|
||||
{
|
||||
commandStack.RemoveLast();
|
||||
}
|
||||
}
|
||||
|
||||
public void undo()
|
||||
{
|
||||
if (commandStack.Count > 0)
|
||||
{
|
||||
ICommand command = commandStack.First.Value;
|
||||
commandStack.RemoveFirst();
|
||||
command.undo();
|
||||
redoStack.AddFirst(command);
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand redo()
|
||||
{
|
||||
if (redoStack.Count > 0)
|
||||
{
|
||||
ICommand command = redoStack.First.Value;
|
||||
redoStack.RemoveFirst();
|
||||
command.execute();
|
||||
commandStack.AddFirst(command);
|
||||
return command;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void clearHistory()
|
||||
{
|
||||
commandStack.Clear();
|
||||
redoStack.Clear();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55e3134ede92000488aa626c2beb2d62
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "CommandSystem",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:0f8d877125e73cc40a31b031c2e5fe60"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 87ecf4ad9955b8f49b5bd39d4f087204
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 96d25cd0bae776b4082ba6691f9f0d52
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,65 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class CreateBlockCommand : ICommand
|
||||
{
|
||||
private string prefabId;
|
||||
private Vector3 position;
|
||||
private Quaternion rotation;
|
||||
private GameObject objectCreated;
|
||||
private string blockId;
|
||||
private bool layerDiff;
|
||||
private BlockFactory factory;
|
||||
private Environment environment;
|
||||
|
||||
public CreateBlockCommand(string prefabId, Vector3 position, Quaternion rotation, bool LayerDiff = false)
|
||||
{
|
||||
this.prefabId = prefabId;
|
||||
this.position = position;
|
||||
this.rotation = rotation;
|
||||
this.layerDiff = LayerDiff;
|
||||
this.factory = BlockFactory.getInstance();
|
||||
this.environment = Environment.getInstance();
|
||||
}
|
||||
|
||||
public CreateBlockCommand(CommandDTO commandDTO)
|
||||
{
|
||||
this.prefabId = commandDTO.Parameters["prefabId"].ToString();
|
||||
this.position = (Vector3)commandDTO.Parameters["position"];
|
||||
this.rotation = (Quaternion)commandDTO.Parameters["rotation"];
|
||||
this.layerDiff = (bool)commandDTO.Parameters["layerDiff"];
|
||||
this.factory = BlockFactory.getInstance();
|
||||
this.environment = Environment.getInstance();
|
||||
}
|
||||
|
||||
public void execute()
|
||||
{
|
||||
objectCreated = factory.createblock(prefabId, position, rotation, blockId, layerDiff);
|
||||
if (objectCreated != null)
|
||||
{
|
||||
Block blockComponent = objectCreated.GetComponent<Block>();
|
||||
blockId = blockComponent.getBlockId();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("CreateblockCommand: Could not create block with prefab ID " + prefabId);
|
||||
}
|
||||
}
|
||||
|
||||
public void undo()
|
||||
{
|
||||
environment.removeBlock(blockId);
|
||||
}
|
||||
|
||||
public CommandDTO toDTO()
|
||||
{
|
||||
return new CommandDTO.CommandDTOBuilder()
|
||||
.SetCommandName("CreateCommand")
|
||||
.AddParameter("prefabId", prefabId)
|
||||
.AddParameter("position", position)
|
||||
.AddParameter("rotation", rotation)
|
||||
.AddParameter("layerDiff", layerDiff)
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6846488550ca76e49ab5a48c410f5f00
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class DeleteBlockCommand : ICommand
|
||||
{
|
||||
private string blockId;
|
||||
private string prefabDeletedId;
|
||||
private Vector3 blockInitialPosition;
|
||||
private Quaternion blockInitialRotation;
|
||||
private BlockFactory factory;
|
||||
private Environment environment;
|
||||
|
||||
public DeleteBlockCommand(string blockId)
|
||||
{
|
||||
this.blockId = blockId;
|
||||
this.factory = BlockFactory.getInstance();
|
||||
this.environment = Environment.getInstance();
|
||||
}
|
||||
|
||||
public DeleteBlockCommand(CommandDTO commandDTO)
|
||||
{
|
||||
this.blockId = commandDTO.Parameters["blockId"].ToString();
|
||||
this.factory = BlockFactory.getInstance();
|
||||
this.environment = Environment.getInstance();
|
||||
}
|
||||
|
||||
public void execute()
|
||||
{
|
||||
Block block = environment.getBlock(blockId);
|
||||
if (block != null)
|
||||
{
|
||||
blockInitialPosition = block.transform.position;
|
||||
blockInitialRotation = block.transform.rotation;
|
||||
prefabDeletedId = block.getBlockData()?.blockName;
|
||||
environment.removeBlock(blockId);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("DeleteblockCommand: block with ID " + blockId + " not found.");
|
||||
}
|
||||
}
|
||||
|
||||
public void undo()
|
||||
{
|
||||
factory.createblock(prefabDeletedId, blockInitialPosition, blockInitialRotation, blockId);
|
||||
}
|
||||
public CommandDTO toDTO()
|
||||
{
|
||||
return new CommandDTO.CommandDTOBuilder()
|
||||
.SetCommandName("DeleteCommand")
|
||||
.AddParameter("blockId", blockId)
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8631dad80687e2b45a2d8ec6ca40f879
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class DeleteGroupCommand : ICommand
|
||||
{
|
||||
private List<string> blocksId;
|
||||
private List<DeleteBlockCommand> deleteBlockCommands;
|
||||
|
||||
public DeleteGroupCommand(List<string> blocksId)
|
||||
{
|
||||
this.blocksId = blocksId;
|
||||
deleteBlockCommands = new List<DeleteBlockCommand>();
|
||||
}
|
||||
|
||||
public DeleteGroupCommand(CommandDTO commandDTO)
|
||||
{
|
||||
this.blocksId = (List<string>)commandDTO.Parameters["blocksId"];
|
||||
deleteBlockCommands = new List<DeleteBlockCommand>();
|
||||
}
|
||||
|
||||
public void execute()
|
||||
{
|
||||
deleteBlockCommands.Clear();
|
||||
|
||||
foreach (string id in blocksId)
|
||||
{
|
||||
DeleteBlockCommand command = new DeleteBlockCommand(id);
|
||||
command.execute();
|
||||
deleteBlockCommands.Add(command);
|
||||
}
|
||||
}
|
||||
|
||||
public void undo()
|
||||
{
|
||||
foreach (DeleteBlockCommand command in deleteBlockCommands)
|
||||
{
|
||||
command.undo();
|
||||
}
|
||||
}
|
||||
|
||||
public CommandDTO toDTO()
|
||||
{
|
||||
return new CommandDTO.CommandDTOBuilder()
|
||||
.SetCommandName("DeleteGroup")
|
||||
.AddParameter("blocksId", blocksId)
|
||||
.Build();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e09c34ca40233944e8c2702acea7eb90
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,6 @@
|
||||
public interface ICommand
|
||||
{
|
||||
void execute();
|
||||
void undo();
|
||||
CommandDTO toDTO();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da8cfd5f6fb13e2479900c9d4caafa4c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class MoveBlockCommand : ICommand
|
||||
{
|
||||
private string blockId;
|
||||
private Vector3 previousPosition;
|
||||
private Quaternion previousRotation;
|
||||
private Vector3 newPosition;
|
||||
private Quaternion newRotation;
|
||||
private Environment environment;
|
||||
private Transform blockTransform;
|
||||
|
||||
public MoveBlockCommand(string blockId, Vector3 previousPosition, Vector3 newPosition, Quaternion previousRotation, Quaternion newRotation)
|
||||
{
|
||||
this.blockId = blockId;
|
||||
this.newPosition = newPosition;
|
||||
this.previousPosition = previousPosition;
|
||||
this.environment = Environment.getInstance();
|
||||
this.previousRotation = previousRotation;
|
||||
this.newRotation = newRotation;
|
||||
}
|
||||
|
||||
public MoveBlockCommand(CommandDTO commandDTO)
|
||||
{
|
||||
this.blockId = commandDTO.Parameters["blockId"].ToString();
|
||||
this.newPosition = (Vector3)commandDTO.Parameters["newPosition"];
|
||||
this.previousPosition = (Vector3)commandDTO.Parameters["previousPosition"];
|
||||
this.newRotation = (Quaternion)commandDTO.Parameters["newRotation"];
|
||||
this.previousRotation = (Quaternion)commandDTO.Parameters["previousRotation"];
|
||||
this.environment = Environment.getInstance();
|
||||
}
|
||||
|
||||
public void execute()
|
||||
{
|
||||
Block block = environment.getBlock(blockId);
|
||||
if (block != null)
|
||||
environment.moveBlock(block, previousPosition, previousRotation, newPosition, newRotation);
|
||||
else
|
||||
Debug.LogWarning("MoveblockCommand: block with ID " + blockId + " not found.");
|
||||
}
|
||||
|
||||
public void undo()
|
||||
{
|
||||
Block block = environment.getBlock(blockId);
|
||||
if (block != null)
|
||||
environment.moveBlock(block, newPosition, newRotation, previousPosition, previousRotation);
|
||||
else
|
||||
Debug.LogWarning("MoveblockCommand: block with ID " + blockId + " not found.");
|
||||
}
|
||||
|
||||
public CommandDTO toDTO()
|
||||
{
|
||||
return new CommandDTO.CommandDTOBuilder()
|
||||
.SetCommandName("MoveCommand")
|
||||
.AddParameter("blockId", blockId)
|
||||
.AddParameter("newPosition", newPosition)
|
||||
.AddParameter("previousPosition", previousPosition)
|
||||
.AddParameter("newRotation", newRotation)
|
||||
.AddParameter("previousRotation", previousRotation)
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb9209f3464c8224eb210299f2a742ea
|
||||
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 RotateblockCommand : ICommand
|
||||
{
|
||||
private string blockId;
|
||||
private Quaternion newRotation;
|
||||
private Quaternion previousRotation;
|
||||
private Environment environment;
|
||||
private Transform blockTransform;
|
||||
|
||||
public RotateblockCommand(string blockId, Quaternion newRotation)
|
||||
{
|
||||
this.blockId = blockId;
|
||||
this.newRotation = newRotation;
|
||||
this.environment = Environment.getInstance();
|
||||
}
|
||||
|
||||
public RotateblockCommand(CommandDTO commandDTO)
|
||||
{
|
||||
this.blockId = commandDTO.Parameters["blockId"].ToString();
|
||||
this.newRotation = (Quaternion)commandDTO.Parameters["newRotation"];
|
||||
this.environment = Environment.getInstance();
|
||||
}
|
||||
|
||||
public void execute()
|
||||
{
|
||||
blockTransform = environment.getBlock(blockId)?.transform;
|
||||
if (blockTransform != null)
|
||||
{
|
||||
previousRotation = blockTransform.rotation;
|
||||
blockTransform.rotation = newRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("RotateblockCommand: block with ID " + blockId + " not found.");
|
||||
}
|
||||
}
|
||||
|
||||
public void undo()
|
||||
{
|
||||
blockTransform = environment.getBlock(blockId)?.transform;
|
||||
if (blockTransform != null)
|
||||
{
|
||||
blockTransform.rotation = previousRotation;
|
||||
}
|
||||
}
|
||||
public CommandDTO toDTO()
|
||||
{
|
||||
return new CommandDTO.CommandDTOBuilder()
|
||||
.SetCommandName("RotateCommand")
|
||||
.AddParameter("blockId", blockId)
|
||||
.AddParameter("newRotation", newRotation)
|
||||
.Build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8100c36e75da6e42a8d788015b34543
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0403ada0c6e91be46bab191ffa05c627
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace DependencyInjection
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Method | AttributeTargets.Property)]
|
||||
public sealed class InjectAttribute : PropertyAttribute { }
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public sealed class RuntimeInjectAttribute : PropertyAttribute { }
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public sealed class ProvideAttribute : PropertyAttribute { }
|
||||
|
||||
/// <summary>
|
||||
/// Marker interface for MonoBehaviours that provide dependencies to the Injector.
|
||||
/// </summary>
|
||||
public interface IDependencyProvider { }
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user