Esempio n. 1
0
 protected virtual void OnMouseOver()
 {
     if (DungeonManager.instance.mode != DungeonManager.Mode.Move || (Program.selectedProgram && Program.selectedProgram.IsFlying()) || !myTile.isBlocked)
     {
         myTile.OnMouseOver();
     }
     if (Input.GetMouseButtonDown(0))
     {
         if (DungeonManager.instance.mode != DungeonManager.Mode.Deploy)
         {
             Program.selectedProgram = myProgram;
             FindObjectOfType <PathPreview>().ClearPreview();
             selectedObject = this;
         }
     }
     else if (Input.GetMouseButtonDown(1))
     {
         if (Program.isTargetingBreach && Program.selectedProgram && Program.selectedProgram.IsControlledByPlayer())
         {
             Program.selectedProgram.AttemptBreach(this);
         }
         else if ((!Program.isTargetingAttack) && (!Program.isTargetingBreach) && Program.selectedProgram && Program.selectedProgram.IsControlledByPlayer())
         {
             DungeonManager.instance.RightClickTile(myTile);
         }
     }
 }
Esempio n. 2
0
    void Update()
    {
        Vector3 dir  = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")).normalized;
        float   diff = speed - Vector3.Project(rb.velocity, dir).magnitude;

        if (diff < 0)
        {
            diff = 0;
        }
        Vector3 friction = rb.velocity * -0.5f;

        rb.AddForce(dir * diff * 40 + friction);
        if (rb.velocity.magnitude > 0)
        {
            //transform.rotation = Quaternion.LookRotation(Vector3.Scale(rb.velocity.normalized, new Vector3(1, 0, 1)));
        }

        if (Input.GetMouseButtonDown(0))
        {
            RaycastHit hit;
            if (Physics.Raycast(cam.ScreenPointToRay(Input.mousePosition), out hit))
            {
                Debug.Log("Clicked");
                Hackable target = hit.transform.GetComponent <Hackable>();
                if (target != null)
                {
                    ApplyBreakpoint(target);
                }
            }
        }
        if (rb.velocity.y < 0)
        {
            rb.AddForce(Physics.gravity);
        }
    }
Esempio n. 3
0
 private void OnTriggerStay2D(Collider2D collision)
 {
     if (collision.gameObject.CompareTag(TagManager.GetTagNameByEnum(TagEnum.Hackble)))
     {
         currentTarget = collision.gameObject.GetComponent <Hackable>();
     }
 }
Esempio n. 4
0
 private void OnTriggerExit2D(Collider2D collision)
 {
     if (collision.gameObject.CompareTag(TagManager.GetTagNameByEnum(TagEnum.Hackble)))
     {
         currentTarget = null;
     }
 }
Esempio n. 5
0
    //private GameObject instantiatedHackBar;

    private void Update()
    {
        Debug.DrawRay(transform.position, transform.forward * hackRange, Color.red);
        if (Input.GetButtonDown(hackButton))
        {
            DetectCameraBox();
            //if(currentlyHackedObject != null)
            //instantiatedHackBar = Instantiate(hackProgressBar, GameObject.Find("Canvas").transform);
        }

        if (Input.GetButton(hackButton))
        {
            if (currentlyHackedObject != null && !currentlyHackedObject.IsHacked())
            {
                currentlyHackedObject.HackCamera(hackSpeed * Time.deltaTime);
            }
        }

        if (Input.GetButtonUp(hackButton))
        {
            if (currentlyHackedObject != null)
            {
                //if (instantiatedHackBar != null) {
                //    Destroy(instantiatedHackBar);
                //}
                currentlyHackedObject.StopHacking();
                currentlyHackedObject = null;
            }
        }
    }
Esempio n. 6
0
    public GameObject[] severByPointAndNormal(GameObject go, Vector3 pointInWorldSpace, Vector3?normalInWorldSpace)
    {
        Hackable hackable = go.GetComponent <Hackable>();

        if (hackable == null)
        {
            Debug.LogError("GameObject '" + go.name + "' cannot be sliced by point because it has no Hackable component. Please look for the 'slice by point' chapter in the manual.");

            GameObject[] blankResult = { go };
            return(blankResult);
        }
        else
        {
            string boneName           = null;
            float  rootTipProgression = 0f;

            if (determineSlice(hackable, pointInWorldSpace, ref boneName, ref rootTipProgression))
            {
                return(LimbHacker.instance.severByJoint(go, boneName, rootTipProgression, normalInWorldSpace));
            }
            else
            {
                GameObject[] notMuch = { go };
                return(notMuch);
            }
        }
    }
Esempio n. 7
0
    private void DetectCameraBox()
    {
        RaycastHit hit;

        if (Physics.Raycast(transform.position, transform.forward, out hit, hackRange, 1 << cameraBoxLayer))
        {
            currentlyHackedObject = hit.transform.gameObject.GetComponent <Hackable>();
            return;
        }
        currentlyHackedObject = null;
    }
Esempio n. 8
0
    void Update()
    {
        // Check if an object is hackable and if so, set hack.
        if (Input.GetMouseButtonDown(0))
        {
            RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);

            if (hit.collider != null)
            {
                var tmpTerm     = hit.collider.GetComponent <Terminal>();
                var tmpHackable = hit.collider.GetComponent <Hackable>();

                // clicked a Hackable
                if (tmpHackable != null)
                {
                    if (_hackObj != null && _hackObj != tmpHackable)
                    {
                        _hackObj.isHacked = false;
                        if (_term != null)
                        {
                            _term.isHacked = false;
                        }
                    }

                    _hackObj          = tmpHackable;
                    _hackObj.isHacked = !_hackObj.isHacked;
                    Player.ConnectToHackable(_hackObj);
                }

                // clicked a Terminal
                if (tmpTerm != null)
                {
                    _term          = tmpTerm;
                    _term.isHacked = !_term.isHacked;
                    Player.ConnectToTerminal(_term);
                }
            }
        }

        if (_hackObj != null && !_hackObj.isHacked)
        {
            _hackObj = null;
            Player.ClearHackable();
        }

        if (_term != null && !_term.isHacked)
        {
            _term = null;
            Player.ClearTerminal();
        }

        HackWindow.SetActive(_hackObj != null && _term != null);
    }
    public override void OnInspectorGUI()
    {
        Hackable s = (Hackable)target;

        try
        {
            var allBones = LimbHacker.FindBonesInTree(s.gameObject);

            s.alternatePrefab = EditorGUILayout.ObjectField("Alternate prefab", (Object)s.alternatePrefab, typeof(GameObject), false);

            s.infillMaterial = (Material)EditorGUILayout.ObjectField("Infill Material", (Object)s.infillMaterial, typeof(Material), false);

            if (s.infillMaterial != null)
            {
                s.infillMode = (LimbHacker.Infill)EditorGUILayout.EnumPopup("Infill Mode", s.infillMode);
            }

            EditorGUILayout.LabelField("Select which bones are severable:");

            var selectedBones = new List <Transform>();

            var selectAll = GUILayout.Button("Select all");

            foreach (var bone in allBones)
            {
                bool wasSelected = System.Array.IndexOf(s.severables, bone) >= 0;
                bool isSelected  = EditorGUILayout.Toggle(bone.name, wasSelected) || selectAll;

                if (isSelected)
                {
                    selectedBones.Add(bone);
                }
            }

            s.severables = selectedBones.ToArray();

            if (GUI.changed)
            {
                EditorUtility.SetDirty(target);
            }
        }
        catch (LimbHacker.ForestException ex)
        {
            Debug.LogError(ex.Message);
            EditorGUILayout.LabelField("This object must have SkinnedMeshRenderers referring to a single tree.");
        }
    }
Esempio n. 10
0
 public JobSpecification(GameObject subject, Hackable hackable,
                         IEnumerable <MeshSnapshot> meshSnapshots,
                         Dictionary <string, NodeMetadata> nodeMetadata,
                         Material infillMaterial,
                         string jointName, float rootTipProgression, Vector3?tiltPlane, InfillMode infillMode,
                         bool destroyOriginal)
 {
     Subject            = subject;
     Hackable           = hackable;
     MeshSnapshots      = meshSnapshots;
     InfillMaterial     = infillMaterial;
     NodeMetadata       = nodeMetadata;
     JointName          = jointName;
     RootTipProgression = rootTipProgression;
     TiltPlane          = tiltPlane;
     InfillMode         = infillMode;
     DestroyOriginal    = destroyOriginal;
 }
Esempio n. 11
0
 void ApplyBreakpoint(Hackable target)
 {
     if (breakpoints.Contains(target))
     {
         target.Unhack();
         breakpoints.Remove(target);
     }
     else
     {
         if (breakpoints.Count == numBreakpoints)
         {
             breakpoints.First.Value.Unhack();
             breakpoints.RemoveFirst();
         }
         breakpoints.AddLast(target);
         target.Hack();
     }
 }
Esempio n. 12
0
 internal void AttemptBreach(Hackable toHack)
 {
     if (!hasUsedAction && GetBreach() > 0 && !toHack.IsHacked())
     {
         int breachRange = 1;
         if (GetKeywords().Contains("Remote"))
         {
             breachRange = GetRange();
         }
         List <DungeonTile> tempPath = DungeonManager.instance.grid.FindPath(myTile, toHack.myTile, breachRange, true);
         if (tempPath[tempPath.Count - 1] == toHack.myTile)
         {
             Breach newBreach = Instantiate(myBreach, gameObject.transform.position, Quaternion.identity).GetComponent <Breach>();
             newBreach.breach = GetBreach();
             newBreach.SetCourse(tempPath, toHack);
             Program.isTargetingBreach = false;
             movesLeft     = 0;
             hasUsedAction = true;
         }
     }
 }
Esempio n. 13
0
 void ConnectHackable(Hackable objToHack)
 {
     _hackObj           = objToHack;
     objToHack.isHacked = true;
 }
Esempio n. 14
0
 public HackStartInfo(NetworkSimulation netSim, SaveManager saveManager, Hackable hackable)
 {
     _netSim      = netSim;
     _saveManager = saveManager;
     _hackable    = hackable;
 }
Esempio n. 15
0
 override internal void Start()
 {
     base.Start();
     hackable = GetComponent <Hackable>();
     lineOfSightIndicators = new List <GameObject>();
 }
Esempio n. 16
0
 internal void SetTile(DungeonTile dungeonTile)
 {
     myTile          = dungeonTile;
     hackable        = GetComponent <Hackable>();
     hackable.myTile = dungeonTile;
 }
Esempio n. 17
0
 public void ConnectToHackable(Hackable hackObj)
 {
     Beam2.SetActive(true);
     _beam2End = hackObj.gameObject;
     UpdateLines(Beam2, _beam2End);
 }
Esempio n. 18
0
        public void SeverByJoint(GameObject subject, string jointName, float rootTipProgression, Vector3?planeNormal)
        {
            //Sanity check: are we already slicing this?
            foreach (var extantState in jobStates)
            {
                if (ReferenceEquals(extantState.Specification.Subject, subject))
                {
                    //Debug.LogErrorFormat("Turbo Slicer was asked to slice '{0}' but this target is already enqueued.", subject.name);
                    return;
                }
            }

            rootTipProgression = Mathf.Clamp01(rootTipProgression);

            //These here are in local space because they're only used to copy to the resultant meshes; they're not used
            //to transform the vertices. We expect a world-space slice input.

            Hackable hackable = null;

            {
                var hackables = subject.GetComponentsInChildren <Hackable>();

                if (hackables.Length > 0)
                {
                    if (hackables.Length > 1)
                    {
                        Debug.LogWarning("Limb Hacker found multiple slice configurations on object '" + subject.name + "'! Behavior is undefined.");
                    }

                    hackable = hackables[0];
                }
                else
                {
                    Debug.LogWarning("Limb Hacker found no slice configuration on object '" + subject.name + "'.");
                    return;
                }
            }

            //We need information about which BONES are getting severed.
            var metadataByNodeName = new Dictionary <string, NodeMetadata>();
            {
                var childTransformByName = new Dictionary <string, Transform>();
                var parentKeyByKey       = new Dictionary <string, string>();

                foreach (Transform t in GetConcatenatedHierarchy(subject.transform))
                {
                    childTransformByName[t.name] = t;

                    var parent = t.parent;

                    if (t == subject.transform)
                    {
                        parent = null;
                    }

                    parentKeyByKey[t.name] = parent == null ? null : parent.name;
                }

                var severedByChildName = new Dictionary <string, bool>();
                {
                    foreach (string childName in childTransformByName.Keys)
                    {
                        severedByChildName[childName] = childName == jointName;
                    }

                    bool changesMade;
                    do
                    {
                        changesMade = false;

                        foreach (string childKey in childTransformByName.Keys)
                        {
                            bool severed = severedByChildName[childKey];

                            if (severed)
                            {
                                continue;
                            }

                            string parentKey = parentKeyByKey[childKey];

                            bool parentSevered;

                            if (severedByChildName.TryGetValue(parentKey, out parentSevered) == false)
                            {
                                continue;
                            }

                            if (parentSevered)
                            {
                                severedByChildName[childKey] = true;

                                changesMade = true;
                            }
                        }
                    }while (changesMade);
                }

                foreach (var kvp in severedByChildName)
                {
                    var t = childTransformByName[kvp.Key];
                    var isConsideredSevered = kvp.Value;
                    metadataByNodeName[kvp.Key] = new NodeMetadata(t, isConsideredSevered);
                }
            }

            IEnumerable <MeshSnapshot> snapshots;
            var forwardPassAgent = subject.GetComponent <ForwardPassAgent>();

            if (forwardPassAgent == null)
            {
                var snapshotBuilder      = new List <MeshSnapshot>();
                var skinnedMeshRenderers = subject.GetComponentsInChildren <SkinnedMeshRenderer>(true);
                foreach (var smr in skinnedMeshRenderers)
                {
                    var mesh = smr.sharedMesh;

                    var boneMetadata = new BoneMetadata[smr.bones.Length];

                    var bones     = smr.bones;
                    var bindPoses = mesh.bindposes;

                    for (int i = 0; i < boneMetadata.Length; i++)
                    {
                        boneMetadata[i] = new BoneMetadata(i, bones[i].name, bindPoses[i]);
                    }

                    int?infillIndex = null;
                    if (hackable.infillMaterial != null)
                    {
                        var mats = smr.sharedMaterials;
                        for (int i = 0; i < mats.Length; i++)
                        {
                            if (hackable.infillMaterial == mats[i])
                            {
                                infillIndex = i;
                                break;
                            }
                        }
                    }

                    MeshSnapshot snapshot;

                    MeshSnapshot preloadedFragment;
                    if (preloadedMeshes.TryGetValue(mesh.GetInstanceID(), out preloadedFragment))
                    {
                        //The preloaded fragments are missing data which is particular to the SMR. We'll combine it with such data here.

                        snapshot = preloadedFragment.WithKey(smr.name).WithMaterials(smr.sharedMaterials).WithBoneMetadata(boneMetadata).WithInfillIndex(infillIndex);
                    }
                    else
                    {
                        var indices = new int[mesh.subMeshCount][];
                        for (int i = 0; i < mesh.subMeshCount; i++)
                        {
                            indices[i] = mesh.GetIndices(i);
                        }

                        snapshot = new MeshSnapshot(
                            smr.name,
                            mesh.vertices,
                            mesh.normals,
                            mesh.uv,
                            mesh.tangents,
                            mesh.boneWeights,
                            smr.sharedMaterials,
                            boneMetadata,
                            infillIndex,
                            indices);
                    }

                    snapshotBuilder.Add(snapshot);
                }
                snapshots = snapshotBuilder;
            }
            else
            {
                snapshots = forwardPassAgent.Snapshot;
            }

            var jobSpec  = new JobSpecification(subject, hackable, snapshots, metadataByNodeName, hackable.infillMaterial, jointName, rootTipProgression, planeNormal, hackable.infillMode, true);
            var jobState = new JobState(jobSpec);

            try
            {
                switch (workerThreadMode)
                {
                case WorkerThreadMode.Asynchronous:
                    jobStates.Add(jobState);
                        #if NETFX_CORE && !UNITY_EDITOR
                    System.Threading.Tasks.Task.Factory.StartNew(ThreadSafeHack.Slice, jobState);
                        #else
                    System.Threading.ThreadPool.QueueUserWorkItem(ThreadSafeHack.Slice, jobState);
                        #endif
                    break;

                case WorkerThreadMode.Synchronous:
                    ThreadSafeHack.Slice(jobState);
                    if (jobState.HasYield)
                    {
                        ConsumeJobYield(jobState);
                    }
                    else if (jobState.HasException)
                    {
                        throw jobState.Exception;
                    }
                    break;

                default:
                    throw new System.NotImplementedException();
                }
            }
            catch (System.Exception ex)
            {
                Debug.LogException(ex, subject);
            }
        }
Esempio n. 19
0
 internal void SetCourse(List <DungeonTile> path, Hackable target)
 {
     myTile      = path[0];
     this.target = target;
     movePath    = path;
 }
Esempio n. 20
0
        public static bool DetermineSlice(Hackable hackable, Vector3 pointInWorldSpace, ref string boneName, ref float rootTipProgression)
        {
            const int nothing = -1;

            var severables = hackable.severables;

            var indexByObject = new Dictionary <Transform, int>();

            for (var i = 0; i < severables.Length; i++)
            {
                indexByObject[severables[i]] = i;
            }

            var severablesInThreeSpace = new Vector3[severables.Length];

            for (var i = 0; i < severables.Length; i++)
            {
                severablesInThreeSpace[i] = severables[i].position;
            }

            var deltas = new Vector3[severables.Length];

            for (var i = 0; i < severables.Length; i++)
            {
                deltas[i] = severablesInThreeSpace[i] - pointInWorldSpace;
            }

            var mags = new float[severables.Length];

            for (var i = 0; i < severables.Length; i++)
            {
                mags[i] = deltas[i].magnitude;
            }

            var indexOfNearestThing    = nothing;
            var distanceToNearestThing = float.PositiveInfinity;

            for (var i = 0; i < severables.Length; i++)
            {
                if (mags[i] < distanceToNearestThing)
                {
                    indexOfNearestThing    = i;
                    distanceToNearestThing = mags[i];
                }
            }

            if (indexOfNearestThing != nothing)
            {
                var nearestThing = severables[indexOfNearestThing];

                if (indexByObject.ContainsKey(nearestThing.parent))
                {
                    var parentIndex = indexByObject[nearestThing.parent];

                    var hereDelta = severablesInThreeSpace[indexOfNearestThing] - severablesInThreeSpace[parentIndex];

                    var touchDelta = pointInWorldSpace - severablesInThreeSpace[parentIndex];

                    //If the touch is closer to the parent than the severable is, than it's between them.
                    //We'll use that and then use the root tip progression to slice just the right spot.
                    if (touchDelta.magnitude < hereDelta.magnitude)
                    {
                        indexOfNearestThing = parentIndex;
                        nearestThing        = severables[indexOfNearestThing];
                    }
                }

                var childIndices = new List <int>();

                for (var i = 0; i < severables.Length; i++)
                {
                    var candidate = severables[i];

                    if (candidate.parent == nearestThing)
                    {
                        childIndices.Add(i);
                    }
                }

                rootTipProgression = 0f;

                if (childIndices.Count > 0)
                {
                    var aggregatedChildPositions = Vector3.zero;

                    foreach (var i in childIndices)
                    {
                        aggregatedChildPositions += severablesInThreeSpace[i];
                    }

                    var meanChildPosition = aggregatedChildPositions / childIndices.Count;

                    var alfa  = (pointInWorldSpace - nearestThing.position).sqrMagnitude;
                    var bravo = (pointInWorldSpace - meanChildPosition).sqrMagnitude;

                    rootTipProgression = Mathf.Clamp(alfa / bravo, 0.0f, 0.99f);
                }

                boneName = nearestThing.name;

                return(true);
            }
            else
            {
                return(false);
            }
        }
Esempio n. 21
0
    public bool determineSlice(Hackable hackable, Vector3 pointInWorldSpace, ref string boneName, ref float rootTipProgression)
    {
        const int nothing = -1;

        Transform[] severables = hackable.severables;

        Dictionary <Transform, int> indexByObject = new Dictionary <Transform, int>();

        for (int i = 0; i < severables.Length; i++)
        {
            indexByObject[severables[i]] = i;
        }

        Vector3[] severablesInThreeSpace = new Vector3[severables.Length];
        for (int i = 0; i < severables.Length; i++)
        {
            severablesInThreeSpace[i] = severables[i].position;
        }

        Vector3[] deltas = new Vector3 [severables.Length];
        for (int i = 0; i < severables.Length; i++)
        {
            deltas[i] = severablesInThreeSpace[i] - pointInWorldSpace;
        }

        float[] mags = new float[severables.Length];
        for (int i = 0; i < severables.Length; i++)
        {
            mags[i] = deltas[i].magnitude;
        }

        int   indexOfNearestThing    = nothing;
        float distanceToNearestThing = float.PositiveInfinity;

        for (int i = 0; i < severables.Length; i++)
        {
            if (mags[i] < distanceToNearestThing)
            {
                indexOfNearestThing    = i;
                distanceToNearestThing = mags[i];
            }
        }

        if (indexOfNearestThing != nothing)
        {
            Transform nearestThing = severables[indexOfNearestThing];

            if (indexByObject.ContainsKey(nearestThing.parent))
            {
                int parentIndex = indexByObject[nearestThing.parent];

                Vector3 hereDelta = severablesInThreeSpace[indexOfNearestThing] - severablesInThreeSpace[parentIndex];

                Vector3 touchDelta = pointInWorldSpace - severablesInThreeSpace[parentIndex];

                //If the touch is closer to the parent than the severable is, than it's between them.
                //We'll use that and then use the root tip progression to slice just the right spot.
                if (touchDelta.magnitude < hereDelta.magnitude)
                {
                    indexOfNearestThing = parentIndex;
                    nearestThing        = severables[indexOfNearestThing];
                }
            }

            List <int> childIndices = new List <int>();

            for (int i = 0; i < severables.Length; i++)
            {
                Transform candidate = severables[i];

                if (candidate.parent == nearestThing)
                {
                    childIndices.Add(i);
                }
            }

            rootTipProgression = 0f;

            if (childIndices.Count > 0)
            {
                Vector3 aggregatedChildPositions = Vector3.zero;

                foreach (int i in childIndices)
                {
                    aggregatedChildPositions += severablesInThreeSpace[i];
                }

                Vector3 meanChildPosition = aggregatedChildPositions / ((float)childIndices.Count);

                Matrix4x4 flattenTransform;

                Vector3 v1 = Vector3.forward;
                Vector3 v2 = (severablesInThreeSpace[indexOfNearestThing] - meanChildPosition).normalized;
                Vector3 v3 = Vector3.Cross(v1, v2).normalized;
                Vector3 v4 = Vector3.Cross(v3, v1);

                float cos = Vector3.Dot(v2, v1);
                float sin = Vector3.Dot(v2, v4);

                Matrix4x4 m1 = Matrix4x4.identity;
                m1.SetRow(0, (Vector4)v1);
                m1.SetRow(1, (Vector4)v4);
                m1.SetRow(2, (Vector4)v3);

                Matrix4x4 m1i = m1.inverse;

                Matrix4x4 m2 = Matrix4x4.identity;
                m2.SetRow(0, new Vector4(cos, sin, 0, 0));
                m2.SetRow(1, new Vector4(-sin, cos, 0, 0));

                flattenTransform = m1i * m2 * m1;

                Vector3 transformedChildPosition = flattenTransform.MultiplyPoint(meanChildPosition);
                Vector3 transformedRootPosition  = flattenTransform.MultiplyPoint(severablesInThreeSpace[indexOfNearestThing]);
                Vector3 transformedTouchPosition = flattenTransform.MultiplyPoint(pointInWorldSpace);

                rootTipProgression = 1f - Mathf.Clamp((transformedTouchPosition.z - transformedChildPosition.z) / (transformedRootPosition.z - transformedChildPosition.z), 0.05f, 1f);
            }

            boneName = nearestThing.name;

            return(true);
        }
        else
        {
            return(false);
        }
    }
Esempio n. 22
0
    public GameObject[] severByJoint(GameObject go, string jointName, float rootTipProgression, Vector3?planeNormal)
    {
        rootTipProgression = Mathf.Clamp01(rootTipProgression);

        //These here are in local space because they're only used to copy to the resultant meshes; they're not used
        //to transform the vertices. We expect a world-space slice input.

        Hackable hackable = null;

        {
            Hackable[] hackables = go.GetComponentsInChildren <Hackable>();

            if (hackables.Length > 0)
            {
                if (hackables.Length > 1)
                {
                    Debug.LogWarning("Limb Hacker found multiple slice configurations on object '" + go.name + "' in scene '" + Application.loadedLevelName + "'! Behavior is undefined.");
                }

                hackable = hackables[0];
            }
        }

        //We need information about which BONES are getting severed.

        var allBones = LimbHacker.FindBonesInTree(go);

        var childTransformByName = new Dictionary <string, Transform>();
        var parentKeyByKey       = new Dictionary <string, string>();

        foreach (Transform t in GetConcatenatedHierarchy(go.transform))
        {
            childTransformByName[t.name] = t;

            Transform parent = t.parent;

            if (t == go.transform)
            {
                parent = null;
            }

            parentKeyByKey[t.name] = parent == null ? null : parent.name;
        }

        var severedByChildName = new Dictionary <string, bool>();

        {
            foreach (string childName in childTransformByName.Keys)
            {
                severedByChildName[childName] = childName == jointName;
            }

            bool changesMade;
            do
            {
                changesMade = false;

                foreach (string childKey in childTransformByName.Keys)
                {
                    bool severed = severedByChildName[childKey];

                    if (severed)
                    {
                        continue;
                    }

                    string parentKey = parentKeyByKey[childKey];

                    bool parentSevered;

                    if (severedByChildName.TryGetValue(parentKey, out parentSevered) == false)
                    {
                        continue;
                    }

                    if (parentSevered)
                    {
                        severedByChildName[childKey] = true;

                        changesMade = true;
                    }
                }
            }while(changesMade);
        }

        GameObject frontObject, backObject;

        {
            var bonePresenceFront = new Dictionary <string, bool>();
            var bonePresenceBack  = new Dictionary <string, bool>();

            foreach (KeyValuePair <string, bool> kvp in severedByChildName)
            {
                bonePresenceFront[kvp.Key] = kvp.Value;
                bonePresenceBack[kvp.Key]  = !kvp.Value;
            }

            createResultObjects(go, hackable, childTransformByName, bonePresenceFront, bonePresenceBack, out frontObject, out backObject);
        }

        var skinnedMeshRenderers = go.GetComponentsInChildren <SkinnedMeshRenderer>(true);

        foreach (var smr in skinnedMeshRenderers)
        {
            var m = smr.sharedMesh;
            LoadSkinnedMeshRendererIntoCache(smr, true);

            var severedByBoneIndex   = new Dictionary <int, bool>();
            var mandatoryByBoneIndex = new bool[smr.bones.Length];

            string severedJointKey = jointName;

            Dictionary <string, int> boneIndexByName  = new Dictionary <string, int>();
            List <string>            orderedBoneNames = new List <string>();

            foreach (Transform bone in smr.bones)
            {
                boneIndexByName[bone.name] = orderedBoneNames.Count;
                orderedBoneNames.Add(bone.name);
            }

            for (int boneIndex = 0; boneIndex < orderedBoneNames.Count; boneIndex++)
            {
                string boneName = orderedBoneNames[boneIndex];

                severedByBoneIndex[boneIndex] = severedByChildName[boneName];
            }

            Vector4 plane = Vector4.zero;

            bool willSliceThisMesh = boneIndexByName.ContainsKey(severedJointKey);

            if (willSliceThisMesh)
            {
                //We need to create a slice plane in local space. We're going to do that by using the bind poses
                //from the SEVERED limb, its PARENT and its CHILDREN to create a position and normal.

                Matrix4x4[] orderedBindPoses = smr.sharedMesh.bindposes;

                int severedJointIndex = boneIndexByName[severedJointKey];

                Matrix4x4 severedJointMatrix = orderedBindPoses[severedJointIndex].inverse;

                Matrix4x4 severedJointParentMatrix = Matrix4x4.identity;

                if (parentKeyByKey.ContainsKey(severedJointKey))
                {
                    string severedJointParentKey = parentKeyByKey[severedJointKey];

                    if (boneIndexByName.ContainsKey(severedJointParentKey))
                    {
                        int severedJointParentIndex = boneIndexByName[severedJointParentKey];

                        severedJointParentMatrix = orderedBindPoses[severedJointParentIndex].inverse;
                    }
                }

                VectorAccumulator meanChildPosition = new VectorAccumulator();

                for (int i = 0; i < boneIndexByName.Count; i++)
                {
                    mandatoryByBoneIndex[i] = false;
                }

                if (parentKeyByKey.ContainsKey(severedJointKey))
                {
                    string parentKey = parentKeyByKey[severedJointKey];
                    if (boneIndexByName.ContainsKey(parentKey))
                    {
                        mandatoryByBoneIndex[boneIndexByName[parentKey]] = true;
                    }
                }

                if (rootTipProgression > 0f)
                {
                    mandatoryByBoneIndex[boneIndexByName[jointName]] = true;

                    List <string> childKeys = new List <string>();
                    foreach (KeyValuePair <string, string> kvp in parentKeyByKey)
                    {
                        if (kvp.Value == severedJointKey)
                        {
                            childKeys.Add(kvp.Key);
                        }
                    }

                    List <int> childIndices = new List <int>();
                    foreach (string key in childKeys)
                    {
                        int childIndex;

                        if (boneIndexByName.TryGetValue(key, out childIndex))
                        {
                            childIndices.Add(childIndex);
                        }
                    }

                    foreach (int index in childIndices)
                    {
                        Matrix4x4 childMatrix = orderedBindPoses[index].inverse;

                        Vector3 childPosition = childMatrix.MultiplyPoint3x4(Vector3.zero);

                        meanChildPosition.addFigure(childPosition);
                    }
                }

                Vector3 position0 = severedJointParentMatrix.MultiplyPoint3x4(Vector3.zero);
                Vector3 position1 = severedJointMatrix.MultiplyPoint3x4(Vector3.zero);
                Vector3 position2 = meanChildPosition.mean;

                Vector3 deltaParent   = position0 - position1;
                Vector3 deltaChildren = position1 - position2;

                Vector3 position = Vector3.Lerp(position1, position2, rootTipProgression);

                Vector3 normalFromParentToChild = -Vector3.Lerp(deltaParent, deltaChildren, rootTipProgression).normalized;

                if (planeNormal.HasValue)
                {
                    Matrix4x4 fromWorldToLocalSpaceOfBone = smr.bones[severedJointIndex].worldToLocalMatrix;

                    Vector3 v = planeNormal.Value;
                    v = fromWorldToLocalSpaceOfBone.MultiplyVector(v);
                    v = severedJointMatrix.MultiplyVector(v);
                    v.Normalize();

                    if (Vector3.Dot(v, normalFromParentToChild) < 0f)
                    {
                        v = -v;
                    }

                    v = MuffinSliceCommon.clampNormalToBicone(v, normalFromParentToChild, 30f);

                    planeNormal = v;
                }
                else
                {
                    planeNormal = normalFromParentToChild;
                }

                plane = (Vector4)planeNormal.Value;

                plane.w = -(plane.x * position.x + plane.y * position.y + plane.z * position.z);
            }

            //We're going to create two new tentative meshes which contain ALL original vertices in order,
            //plus room for new vertices. Not all of these copied vertices will be addressed, but copying them
            //over eliminates the need to remove doubles and do an On^2 search.

            int submeshCount = c.indices.Length;

            TurboList <int>[] _frontIndices = new TurboList <int> [submeshCount];
            TurboList <int>[] _backIndices  = new TurboList <int> [submeshCount];

            PlaneTriResult[] sidePlanes = new PlaneTriResult[c.vertices.Count];
            {
                BoneWeight[] weights  = c.weights.array;
                Vector3[]    vertices = c.vertices.array;
                int          count    = c.vertices.Count;

                bool[] whollySeveredByVertexIndex = new bool[count];
                bool[] severableByVertexIndex     = new bool[count];
                bool[] mandatoryByVertexIndex     = new bool[count];

                const float minimumWeightForRelevance = 0.1f;

                for (int i = 0; i < severableByVertexIndex.Length; i++)
                {
                    BoneWeight weight = weights[i];

                    bool whollySevered = true;
                    bool severable     = false;
                    bool mandatory     = false;

                    int[]   indices       = { weight.boneIndex0, weight.boneIndex1, weight.boneIndex2, weight.boneIndex3 };
                    float[] scalarWeights = { weight.weight0, weight.weight1, weight.weight2, weight.weight3 };

                    for (int j = 0; j < 4; j++)
                    {
                        if (scalarWeights[j] > minimumWeightForRelevance)
                        {
                            int  index      = indices[j];
                            bool _severable = severedByBoneIndex[index];
                            bool _mandatory = mandatoryByBoneIndex[index];
                            whollySevered &= _severable;
                            severable     |= _severable;
                            mandatory     |= _mandatory;
                        }
                    }

                    whollySeveredByVertexIndex[i] = whollySevered;
                    severableByVertexIndex[i]     = severable;
                    mandatoryByVertexIndex[i]     = mandatory;
                }

                for (int i = 0; i < sidePlanes.Length; i++)
                {
                    if (willSliceThisMesh && mandatoryByVertexIndex[i])
                    {
                        sidePlanes[i] = MuffinSliceCommon.getSidePlane(ref vertices[i], ref plane);
                    }
                    else if (whollySeveredByVertexIndex[i])
                    {
                        sidePlanes[i] = PlaneTriResult.PTR_FRONT;
                    }
                    else if (willSliceThisMesh && severableByVertexIndex[i])
                    {
                        sidePlanes[i] = MuffinSliceCommon.getSidePlane(ref vertices[i], ref plane);
                    }
                    else
                    {
                        sidePlanes[i] = PlaneTriResult.PTR_BACK;
                    }
                }
            }

            TurboList <int> frontInfill = null;
            TurboList <int> backInfill  = null;

            for (int j = 0; j < submeshCount; j++)
            {
                int initialCapacityIndices = Mathf.RoundToInt((float)c.indices[j].Length * factorOfSafetyIndices);

                _frontIndices[j] = new TurboList <int>(initialCapacityIndices);
                _backIndices[j]  = new TurboList <int>(initialCapacityIndices);

                if (hackable.infillMaterial != null && c.mats[j] == hackable.infillMaterial)
                {
                    frontInfill = _frontIndices[j];
                    backInfill  = _backIndices[j];
                }
            }

            if (hackable.infillMaterial != null && frontInfill == null)
            {
                frontInfill = new TurboList <int>(1024);
                backInfill  = new TurboList <int>(1024);
            }

            for (int j = 0; j < submeshCount; j++)
            {
                int initialCapacityIndices = Mathf.RoundToInt((float)c.indices[j].Length * factorOfSafetyIndices);

                int[] _indices = c.indices[j];

                TurboList <int> frontIndices = _frontIndices[j];
                TurboList <int> backIndices  = _backIndices[j];
                TurboList <int> splitPending = new TurboList <int>(initialCapacityIndices);

                int[] indices = new int[3];

                for (int i = 0; i < _indices.Length;)
                {
                    indices[0] = _indices[i++];
                    indices[1] = _indices[i++];
                    indices[2] = _indices[i++];

                    // compute the side of the plane each vertex is on
                    PlaneTriResult r1 = sidePlanes[indices[0]];
                    PlaneTriResult r2 = sidePlanes[indices[1]];
                    PlaneTriResult r3 = sidePlanes[indices[2]];

                    if (r1 == r2 && r1 == r3)                       // if all three vertices are on the same side of the plane.
                    {
                        if (r1 == PlaneTriResult.PTR_FRONT)         // if all three are in front of the plane, then copy to the 'front' output triangle.
                        {
                            frontIndices.AddArray(indices);
                        }
                        else
                        {
                            backIndices.AddArray(indices);
                        }
                    }
                    else if (willSliceThisMesh)
                    {
                        splitPending.AddArray(indices);
                    }
                }

                if (willSliceThisMesh)
                {
                    splitTrianglesLH(plane, c.vertices.array, sidePlanes, splitPending.ToArray(), c, frontIndices, backIndices, hackable.infillMode, frontInfill, backInfill);
                }
            }

            if (hackable.infillMaterial != null)
            {
                bool alreadyPresent = System.Array.IndexOf <Material>(c.mats, hackable.infillMaterial) >= 0;

                if (!alreadyPresent)
                {
                    int oldLength = c.mats.Length, newLength = c.mats.Length + 1;

                    Material[] newMats = new Material[newLength];
                    System.Array.Copy(c.mats, newMats, oldLength);
                    newMats[newLength - 1] = hackable.infillMaterial;
                    c.mats = newMats;

                    TurboList <int>[] indexArray;

                    indexArray = new TurboList <int> [newLength];
                    System.Array.Copy(_backIndices, indexArray, oldLength);
                    indexArray[newLength - 1] = backInfill;
                    _backIndices = indexArray;

                    indexArray = new TurboList <int> [newLength];
                    System.Array.Copy(_frontIndices, indexArray, oldLength);
                    indexArray[newLength - 1] = frontInfill;
                    _frontIndices             = indexArray;

                    submeshCount++;
                }
            }

            Vector3[]    geoSubsetOne, geoSubsetTwo;
            Vector3[]    normalsSubsetOne, normalsSubsetTwo;
            Vector2[]    uvSubsetOne, uvSubsetTwo;
            BoneWeight[] weightSubsetOne, weightSubsetTwo;
            int[][]      indexSubsetOne, indexSubsetTwo;

            indexSubsetOne = new int[submeshCount][];
            indexSubsetTwo = new int[submeshCount][];

            targetSubsetOne.Clear();
            targetSubsetTwo.Clear();

            int transferTableMaximumKey = c.vertices.Count;

            int[] transferTableOne = new int[transferTableMaximumKey];
            int[] transferTableTwo = new int[transferTableMaximumKey];

            for (int i = 0; i < transferTableOne.Length; i++)
            {
                transferTableOne[i] = -1;
            }
            for (int i = 0; i < transferTableTwo.Length; i++)
            {
                transferTableTwo[i] = -1;
            }

            for (int i = 0; i < submeshCount; i++)
            {
                perfectSubsetRD(_frontIndices[i], c.vertices, c.normals, c.UVs, c.weights, out indexSubsetOne[i], targetSubsetOne, ref transferTableOne);
            }

            for (int i = 0; i < submeshCount; i++)
            {
                perfectSubsetRD(_backIndices[i], c.vertices, c.normals, c.UVs, c.weights, out indexSubsetTwo[i], targetSubsetTwo, ref transferTableTwo);
            }

            //Note that we do not explicitly call recalculate bounds because (as per the manual) this is implicit in an
            //assignment to vertices whenever the vertex count changes from zero to non-zero.

            Mesh frontMesh = new Mesh();
            Mesh backMesh  = new Mesh();

            var frontSMR = GetSkinnedMeshRendererWithName(frontObject, smr.name);
            var backSMR  = GetSkinnedMeshRendererWithName(backObject, smr.name);

            if (targetSubsetOne.vertices.Count > 0)
            {
                frontSMR.materials     = c.mats;
                frontSMR.sharedMesh    = frontMesh;
                frontMesh.vertices     = targetSubsetOne.vertices.ToArray();
                frontMesh.normals      = targetSubsetOne.normals.ToArray();
                frontMesh.uv           = targetSubsetOne.UVs.ToArray();
                frontMesh.boneWeights  = targetSubsetOne.weights.ToArray();
                frontMesh.subMeshCount = submeshCount;
                frontMesh.bindposes    = m.bindposes;

                for (int i = 0; i < submeshCount; i++)
                {
                    frontMesh.SetTriangles(indexSubsetOne[i], i);
                }
            }
            else
            {
                GameObject.DestroyImmediate(frontSMR);
            }

            if (targetSubsetTwo.vertices.Count > 0)
            {
                backSMR.materials     = c.mats;
                backSMR.sharedMesh    = backMesh;
                backMesh.vertices     = targetSubsetTwo.vertices.ToArray();
                backMesh.normals      = targetSubsetTwo.normals.ToArray();
                backMesh.uv           = targetSubsetTwo.UVs.ToArray();
                backMesh.boneWeights  = targetSubsetTwo.weights.ToArray();
                backMesh.subMeshCount = submeshCount;
                backMesh.bindposes    = m.bindposes;

                for (int i = 0; i < submeshCount; i++)
                {
                    backMesh.SetTriangles(indexSubsetTwo[i], i);
                }
            }
            else
            {
                GameObject.DestroyImmediate(backSMR);
            }
        }

        var results = new GameObject[] {
            frontObject, backObject
        };

        hackable.handleSlice(results);

        return(results);
    }
Esempio n. 23
0
    private void createResultObjects(GameObject go, Hackable sliceable,
                                     Dictionary <string, Transform> transformByName,
                                     Dictionary <string, bool> frontPresence, Dictionary <string, bool> backPresence,
                                     out GameObject frontObject, out GameObject backObject)
    {
        Transform goTransform = go.transform;

        bool useAlternateForFront, useAlternateForBack;

        if (sliceable.alternatePrefab == null)
        {
            useAlternateForFront = false;
            useAlternateForBack  = false;
        }
        else
        {
            useAlternateForFront = sliceable.cloneAlternate(frontPresence);
            useAlternateForBack  = sliceable.cloneAlternate(backPresence);
        }

        bool backIsNew = useAlternateForBack;

        if (backIsNew)
        {
            Object backSource = useAlternateForBack ? sliceable.alternatePrefab : go;
            backObject = (GameObject)GameObject.Instantiate(backSource);
        }
        else
        {
            backObject = go;
        }


        Object frontSource = useAlternateForFront ? sliceable.alternatePrefab : go;

        frontObject = (GameObject)GameObject.Instantiate(frontSource);

        handleHierarchy(frontObject.transform, frontPresence, transformByName);
        handleHierarchy(backObject.transform, backPresence, transformByName);

        Transform parent = goTransform.parent;

        Vector3 position = goTransform.localPosition;
        Vector3 scale    = goTransform.localScale;

        Quaternion rotation = goTransform.localRotation;

        frontObject.transform.parent        = parent;
        frontObject.transform.localPosition = position;
        frontObject.transform.localScale    = scale;

        frontObject.transform.localRotation = rotation;

        frontObject.layer = go.layer;

        frontObject.name = "LHR Front";
        backObject.name  = "LHR Back";

        if (backIsNew)
        {
            backObject.transform.parent        = parent;
            backObject.transform.localPosition = position;
            backObject.transform.localScale    = scale;

            backObject.transform.localRotation = rotation;

            backObject.layer = go.layer;

            GameObject.Destroy(go);
        }
    }