Пример #1
0
    public void RebuildCritterFromGenomeRecursive(bool physicsOn, bool useSegments, float variableMass, bool editor) {
        //Debug.Log("RebuildCritterFromGenomeRecursive: " + physicsOn.ToString() + ", " + useSegments.ToString() + ", " + variableMass.ToString() + ", " + editor.ToString());
        BoundingBoxMinCorner = Vector3.zero;
        BoundingBoxMaxCorner = Vector3.zero;
        // IMPROVE THIS SO IT WORKS FOR BOTH CritterConstructer AND Trainer
        if (!editor)
            masterCritterGenome.PreBuildCritter(variableMass);
        // Delete existing Segment GameObjects
        if(!useSegments || editor)
            DeleteSegments();
        // Is this the best way to clear the lists? from a memory standpoint...
        segaddonPhysicalAttributesList.Clear();
        
        segaddonJointAngleSensorList.Clear();
        segaddonContactSensorList.Clear();
        segaddonRaycastSensorList.Clear();
        segaddonCompassSensor1DList.Clear();
        segaddonCompassSensor3DList.Clear();
        segaddonPositionSensor1DList.Clear();
        segaddonPositionSensor3DList.Clear();
        segaddonRotationSensor1DList.Clear();
        segaddonRotationSensor3DList.Clear();
        segaddonVelocitySensor1DList.Clear();
        segaddonVelocitySensor3DList.Clear();
        segaddonAltimeterList.Clear();
        segaddonEarBasicList.Clear();
        segaddonGravitySensorList.Clear();
        segaddonOscillatorInputList.Clear();
        segaddonValueInputList.Clear();
        segaddonTimerInputList.Clear();

        segaddonJointMotorList.Clear();
        segaddonThrusterEffector1DList.Clear();
        segaddonThrusterEffector3DList.Clear();
        segaddonTorqueEffector1DList.Clear();
        segaddonTorqueEffector3DList.Clear();
        segaddonMouthBasicList.Clear();
        segaddonNoiseMakerBasicList.Clear();
        segaddonStickyList.Clear();
        segaddonWeaponBasicList.Clear();        

        InitializeSegmentMaterial();

        if (critterSegmentList != null) {
            critterSegmentList.Clear();
        }
        if(inputChannelsList != null) {
            inputChannelsList.Clear();
        }
        else {
            inputChannelsList = new List<BrainInputChannel>();
        }
        if (outputChannelsList != null) {
            outputChannelsList.Clear();
        }
        else {
            outputChannelsList = new List<BrainOutputChannel>();
        }
        // interpret Genome and construct critter in its bind pose
        bool isPendingChildren = true;
        int currentDepth = 0; // start with RootNode
        int maxDepth = 20;  // safeguard to prevent while loop lock
        int nextSegmentID = 0;
        float critterTotalVolume = 0f;
        List<CritterSegment> builtSegmentsList = new List<CritterSegment>();  // keep track of segments that have been built - linear in-order array 0-n segments
        List<BuildSegmentInfo> currentBuildSegmentList = new List<BuildSegmentInfo>();  // keeps track of all current-depth segment build-requests, and holds important metadata
        List<BuildSegmentInfo> nextBuildSegmentList = new List<BuildSegmentInfo>();  // used to keep track of next childSegments that need to be built

        // ***********  Will attempt to traverse the Segments to be created, keeping track of where on each graph (nodes# & segment#) the current build is on.
        BuildSegmentInfo rootSegmentBuildInfo = new BuildSegmentInfo();
        rootSegmentBuildInfo.sourceNode = masterCritterGenome.CritterNodeList[0];
        currentBuildSegmentList.Add(rootSegmentBuildInfo);  // ROOT NODE IS SPECIAL!        

        // Do a Breadth-first traversal??
        while (isPendingChildren) {
            //int numberOfChildNodes = masterCritterGenome.CritterNodeList[currentNode].attachedJointLinkList.Count;
            
            for (int i = 0; i < currentBuildSegmentList.Count; i++) {
                //Debug.Log("currentDepth: " + currentDepth.ToString() + "builtNodesQueue.Count: " + builtSegmentsList.Count.ToString() + ", pendingNodes: " + currentBuildSegmentList.Count.ToString() + ", i: " + i.ToString());
                // Iterate through pending nodes
                // Build current node --> Segment
                GameObject newGO = new GameObject("Node" + nextSegmentID.ToString());
                CritterSegment newSegment = newGO.AddComponent<CritterSegment>();
                builtSegmentsList.Add(newSegment);
                newGO.layer = LayerMask.NameToLayer("editorSegment"); ; // set segmentGO layer to editorSegment, to distinguish it from Gizmos
                
                newGO.transform.SetParent(this.gameObject.transform);
                if (useSegments) {
                    newGO.GetComponent<MeshRenderer>().material = critterSegmentMaterial;
                    newGO.GetComponent<MeshRenderer>().material.SetFloat("_DisplayTarget", 0f);
                    newGO.GetComponent<MeshRenderer>().material.SetFloat("_Selected", 0f);
                    newGO.AddComponent<BoxCollider>().isTrigger = false;                    
                    critterSegmentList.Add(newGO);  // Add to master Linear list of Segments
                }
                else {
                    newGO.SetActive(false);
                }  
  
                newSegment.InitGamePiece();  // create the mesh and some other initialization stuff
                newSegment.sourceNode = currentBuildSegmentList[i].sourceNode;
                newSegment.id = nextSegmentID;
                nextSegmentID++;
                
                if (currentBuildSegmentList[i].sourceNode.ID == 0) {  // is ROOT segment  -- Look into doing Root build BEFORE for loop to avoid the need to do this check
                    newGO.transform.position = masterCritterGenome.centerOfMassOffset;
                    newGO.transform.rotation = Quaternion.identity;
                    newSegment.scalingFactor = newSegment.sourceNode.jointLink.recursionScalingFactor;
                    newGO.transform.localScale = currentBuildSegmentList[i].sourceNode.dimensions * newSegment.scalingFactor;
                    critterTotalVolume += newGO.transform.localScale.x * newGO.transform.localScale.y * newGO.transform.localScale.z;
                    newSegment.surfaceArea = new Vector3(newGO.transform.localScale.y * newGO.transform.localScale.z * 2f, newGO.transform.localScale.x * newGO.transform.localScale.z * 2f, newGO.transform.localScale.x * newGO.transform.localScale.y * 2f);
                    
                }
                else {  // if NOT root segment, can consider parent-related stuff:
                    
                    newSegment.parentSegment = currentBuildSegmentList[i].parentSegment;
                    // Inherit Axis-Inversions from parent segment:
                    newSegment.mirrorX = newSegment.parentSegment.mirrorX;
                    newSegment.mirrorY = newSegment.parentSegment.mirrorY;
                    newSegment.mirrorZ = newSegment.parentSegment.mirrorZ;
                    // inherit scaling factor from parent -- this is later adjusted again if it is part of a recursion chain
                    newSegment.scalingFactor = newSegment.parentSegment.scalingFactor;
                    newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor; // propagate scaling factor
                    // Check for if the segment currently being built is a Mirror COPY:
                    if (currentBuildSegmentList[i].isMirror) {
                        //Debug.Log("This is a MIRROR COPY segment - Wow!");
                        if(currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorX) {
                            // Invert the X-axis  (this will propagate down to all this segment's children
                            newSegment.mirrorX = !newSegment.mirrorX;
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorY) {
                            newSegment.mirrorY = !newSegment.mirrorY;
                        }
                        //else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorZ) {
                        //    newSegment.mirrorZ = !newSegment.mirrorZ;
                        //}
                    }
                }
                if (physicsOn) {
                    newGO.AddComponent<Rigidbody>().isKinematic = false;
                    if(editor && currentBuildSegmentList[i].sourceNode.ID == 0)
                        newGO.GetComponent<Rigidbody>().isKinematic = true;


                    if(editor) {  // TEMPORARY!!!! if editor && physX, build critterMesh so hide segments!
                        //newGO.GetComponent<MeshRenderer>().enabled = false;
                    }
                    //newGO.GetComponent<Rigidbody>().drag = 20f;
                    //newGO.GetComponent<Rigidbody>().angularDrag = 20f;
                    // Bouncy Root:
                    //GameObject anchorGO = new GameObject("Anchor");
                    //anchorGO.transform.SetParent(this.gameObject.transform);
                    //anchorGO.AddComponent<Rigidbody>().isKinematic = true;
                    /*ConfigurableJoint configJoint = newGO.AddComponent<ConfigurableJoint>();
                    configJoint.autoConfigureConnectedAnchor = false;
                    configJoint.connectedBody = anchorGO.GetComponent<Rigidbody>();
                    configJoint.anchor = new Vector3(0f, 0f, 0f);
                    configJoint.connectedAnchor = new Vector3(0f, 0f, 0f);
                    configJoint.xMotion = ConfigurableJointMotion.Locked;
                    configJoint.yMotion = ConfigurableJointMotion.Locked;
                    configJoint.zMotion = ConfigurableJointMotion.Locked;
                    configJoint.angularXMotion = ConfigurableJointMotion.Locked;
                    configJoint.angularYMotion = ConfigurableJointMotion.Locked;
                    configJoint.angularZMotion = ConfigurableJointMotion.Locked;
                    SoftJointLimitSpring limitSpring = configJoint.linearLimitSpring;
                    limitSpring.spring = 80f;
                    limitSpring.damper = 800f;
                    configJoint.linearLimitSpring = limitSpring;
                    SoftJointLimit jointLimit = configJoint.linearLimit;
                    jointLimit.limit = 0.01f;
                    jointLimit.bounciness = 0.01f;
                    configJoint.linearLimit = jointLimit;
                    configJoint.angularXLimitSpring = limitSpring;
                    configJoint.angularYZLimitSpring = limitSpring;
                    */
                }

                // CHECK FOR RECURSION:
                if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { // if the node being considered has recursions:
                    //Debug.Log("currentNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + "newSegmentRecursion#: " + newSegment.recursionNumber.ToString() + ", parentRecursion#: " + currentBuildSegmentList[i].parentSegment.recursionNumber.ToString());
                    if (newSegment.sourceNode == currentBuildSegmentList[i].parentSegment.sourceNode) {  // if this segment's sourceNode is the same is its parent Segment's sourceNode, then it is not the root of the recursion chain!
                        //Debug.Log("newSegment.sourceNode == currentBuildNodeParentSegmentList[i].sourceNode!");

                        // Are we at the end of a recursion chain?
                        if (currentBuildSegmentList[i].parentSegment.recursionNumber >= currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions) {
                            //Debug.Log("recursion number greater than numRecursions! ( " + currentBuildSegmentList[i].parentSegment.recursionNumber.ToString() + " vs " + currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions.ToString());
                            newSegment.recursionNumber = currentBuildSegmentList[i].parentSegment.recursionNumber + 1; //
                            //newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor;
                        }
                        else {  // create new recursion instance!!
                            BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                            newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode;  // request a segment to be built again based on the current sourceNode
                            newSegment.recursionNumber = currentBuildSegmentList[i].parentSegment.recursionNumber + 1;
                            //newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor; // propagate scaling factor
                            newSegmentInfo.parentSegment = newSegment; // parent of itself (the just-built Segment)
                            nextBuildSegmentList.Add(newSegmentInfo);
                            // If the node also has Symmetry:
                            if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                                // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                                BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                                newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode;  // uses same sourceNode, but tags as Mirror:
                                newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                                newSegmentInfoMirror.parentSegment = newSegment;  // 
                                nextBuildSegmentList.Add(newSegmentInfoMirror);
                            }
                        }
                    }
                    else { // this is the root --- its sourceNode has recursion, and this segment is unique from its parentNode:
                        BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                        newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode;
                        newSegment.recursionNumber = 1;
                        newSegmentInfo.parentSegment = newSegment;
                        nextBuildSegmentList.Add(newSegmentInfo);
                        // If the node also has Symmetry:
                        if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                            // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                            BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                            newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode;  // uses same sourceNode, but tags as Mirror:
                            newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                            newSegmentInfoMirror.parentSegment = newSegment;  // 
                            nextBuildSegmentList.Add(newSegmentInfoMirror);
                        }
                    }
                }

                // PositionSEGMENT GameObject!!!
                if (newSegment.id == 0) {  // if ROOT NODE:

                }
                else {
                    SetSegmentTransform(newGO);  // Properly position the SegmentGO where it should be  && scale!
                    critterTotalVolume += newGO.transform.localScale.x * newGO.transform.localScale.y * newGO.transform.localScale.z;
                    if (physicsOn) {
                        //newGO.GetComponent<Rigidbody>().isKinematic = false;
                        newGO.GetComponent<Rigidbody>().ResetInertiaTensor();
                        ConfigurableJoint configJoint = newGO.AddComponent<ConfigurableJoint>();
                        configJoint.autoConfigureConnectedAnchor = false;
                        configJoint.connectedBody = newSegment.parentSegment.gameObject.GetComponent<Rigidbody>();
                        configJoint.anchor = GetJointAnchor(newSegment);
                        configJoint.connectedAnchor = GetJointConnectedAnchor(newSegment); // <-- Might be Unnecessary
                        ConfigureJointSettings(newSegment, ref configJoint);  // UPDATE THIS TO USE segaddonJointMotorSettings!?!?
                    }
                }
                // Check boundingBox:
                //BoundingBox
                CheckBoundingBox(newGO);                

                // SEGMENT ADDONS:
                if (physicsOn) {
                    // Check for Physical Attributes:
                    List<AddonPhysicalAttributes> physicalAttributesList = masterCritterGenome.CheckForAddonPhysicalAttributes(currentBuildSegmentList[i].sourceNode.ID);
                    for(int a = 0; a < physicalAttributesList.Count; a++) {
                        SegaddonPhysicalAttributes newPhysicalAttributes = new SegaddonPhysicalAttributes(physicalAttributesList[a]);
                        newPhysicalAttributes.segmentID = newSegment.id;
                        segaddonPhysicalAttributesList.Add(newPhysicalAttributes);
                        
                        segmentPhysicMaterial.dynamicFriction = newPhysicalAttributes.dynamicFriction[0];
                        segmentPhysicMaterial.staticFriction = newPhysicalAttributes.staticFriction[0];
                        segmentPhysicMaterial.bounciness = newPhysicalAttributes.bounciness[0];
                        RigidbodyConstraints rbConstraints = newGO.GetComponent<Rigidbody>().constraints;
                        if (newPhysicalAttributes.freezePositionX[0]) {
                            rbConstraints = rbConstraints | RigidbodyConstraints.FreezePositionX;
                        }
                        if (newPhysicalAttributes.freezePositionY[0]) {
                            rbConstraints = rbConstraints | RigidbodyConstraints.FreezePositionY;
                        }
                        if (newPhysicalAttributes.freezePositionZ[0]) {
                            rbConstraints = rbConstraints | RigidbodyConstraints.FreezePositionZ;
                        }
                        if (newPhysicalAttributes.freezeRotationX[0]) {
                            rbConstraints = rbConstraints | RigidbodyConstraints.FreezeRotationX;
                        }
                        if (newPhysicalAttributes.freezeRotationY[0]) {
                            rbConstraints = rbConstraints | RigidbodyConstraints.FreezeRotationY;
                        }
                        if (newPhysicalAttributes.freezeRotationZ[0]) {
                            rbConstraints = rbConstraints | RigidbodyConstraints.FreezeRotationZ;
                        }
                        newGO.GetComponent<Rigidbody>().constraints = rbConstraints;
                        newGO.GetComponent<BoxCollider>().material = segmentPhysicMaterial;
                    }

                    #region INPUTS
                    List<AddonJointAngleSensor> jointAngleSensorList = masterCritterGenome.CheckForAddonJointAngleSensor(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < jointAngleSensorList.Count; j++) {
                        SegaddonJointAngleSensor newJointAngleSensor = new SegaddonJointAngleSensor(jointAngleSensorList[j]);
                        newJointAngleSensor.segmentID = newSegment.id;
                        segaddonJointAngleSensorList.Add(newJointAngleSensor);
                                                
                        if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeX) {
                            string inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleX";
                            BrainInputChannel BIC_SegmentAngle = new BrainInputChannel(ref newJointAngleSensor.angleX, true, inputChannelName);
                            inputChannelsList.Add(BIC_SegmentAngle);

                            if (newJointAngleSensor.measureVel) {
                                inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleVelX";
                                BrainInputChannel BIC_SegmentAngleVel = new BrainInputChannel(ref newJointAngleSensor.angleVelX, true, inputChannelName);
                                inputChannelsList.Add(BIC_SegmentAngleVel);
                            }
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeY) {
                            string inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleY";
                            BrainInputChannel BIC_SegmentAngle = new BrainInputChannel(ref newJointAngleSensor.angleY, true, inputChannelName);
                            inputChannelsList.Add(BIC_SegmentAngle);

                            if (newJointAngleSensor.measureVel) {
                                inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleVelY";
                                BrainInputChannel BIC_SegmentAngleVel = new BrainInputChannel(ref newJointAngleSensor.angleVelY, true, inputChannelName);
                                inputChannelsList.Add(BIC_SegmentAngleVel);
                            }
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeZ) {
                            string inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleZ";
                            BrainInputChannel BIC_SegmentAngle = new BrainInputChannel(ref newJointAngleSensor.angleZ, true, inputChannelName);
                            inputChannelsList.Add(BIC_SegmentAngle);

                            if (newJointAngleSensor.measureVel) {
                                inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleVelZ";
                                BrainInputChannel BIC_SegmentAngleVel = new BrainInputChannel(ref newJointAngleSensor.angleVelZ, true, inputChannelName);
                                inputChannelsList.Add(BIC_SegmentAngleVel);
                            }
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.DualXY) {
                            string inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleX";
                            BrainInputChannel BIC_SegmentAngleX = new BrainInputChannel(ref newJointAngleSensor.angleX, true, inputChannelName);
                            inputChannelsList.Add(BIC_SegmentAngleX);

                            inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleY";
                            BrainInputChannel BIC_SegmentAngleY = new BrainInputChannel(ref newJointAngleSensor.angleY, true, inputChannelName);
                            inputChannelsList.Add(BIC_SegmentAngleY);

                            if (newJointAngleSensor.measureVel) {
                                inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleVelX";
                                BrainInputChannel BIC_SegmentAngleVelX = new BrainInputChannel(ref newJointAngleSensor.angleVelX, true, inputChannelName);
                                inputChannelsList.Add(BIC_SegmentAngleVelX);

                                inputChannelName = "Segment " + newJointAngleSensor.segmentID.ToString() + " AngleVelY";
                                BrainInputChannel BIC_SegmentAngleVelY = new BrainInputChannel(ref newJointAngleSensor.angleVelY, true, inputChannelName);
                                inputChannelsList.Add(BIC_SegmentAngleVelY);
                            }
                        }
                    }
                    List<AddonContactSensor> contactSensorList = masterCritterGenome.CheckForAddonContactSensor(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < contactSensorList.Count; j++) {
                        SegaddonContactSensor newContactSensor = new SegaddonContactSensor(contactSensorList[j]);
                        newContactSensor.segmentID = newSegment.id;
                        segaddonContactSensorList.Add(newContactSensor);
                        SegaddonCollisionDetector collisionDetector = newGO.AddComponent<SegaddonCollisionDetector>();
                        collisionDetector.referencedContactSensor = newContactSensor;

                        string inputChannelName = "Segment " + newContactSensor.segmentID.ToString() + " Contact Sensor";
                        BrainInputChannel BIC_SegmentContactInput = new BrainInputChannel(ref newContactSensor.contactStatus, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentContactInput);
                    }
                    List<AddonRaycastSensor> raycastSensorList = masterCritterGenome.CheckForAddonRaycastSensor(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < raycastSensorList.Count; j++) {
                        SegaddonRaycastSensor newRaycastSensor = new SegaddonRaycastSensor(raycastSensorList[j]);
                        newRaycastSensor.segmentID = newSegment.id;
                        segaddonRaycastSensorList.Add(newRaycastSensor);

                        string inputChannelName = "Segment " + newRaycastSensor.segmentID.ToString() + " Raycast Sensor(dist)";
                        BrainInputChannel BIC_SegmentRaycastInput = new BrainInputChannel(ref newRaycastSensor.distance, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentRaycastInput);
                    }
                    List<AddonCompassSensor1D> compassSensor1DList = masterCritterGenome.CheckForAddonCompassSensor1D(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < compassSensor1DList.Count; j++) {
                        SegaddonCompassSensor1D newCompassSensor1D = new SegaddonCompassSensor1D(compassSensor1DList[j]);
                        newCompassSensor1D.segmentID = newSegment.id;
                        segaddonCompassSensor1DList.Add(newCompassSensor1D);

                        string inputChannelName = "Segment " + newCompassSensor1D.segmentID.ToString() + " Compass1D";
                        BrainInputChannel BIC_SegmentCompass1DInput = new BrainInputChannel(ref newCompassSensor1D.dotProduct, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentCompass1DInput);
                    }
                    List<AddonCompassSensor3D> compassSensor3DList = masterCritterGenome.CheckForAddonCompassSensor3D(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < compassSensor3DList.Count; j++) {
                        SegaddonCompassSensor3D newCompassSensor3D = new SegaddonCompassSensor3D(compassSensor3DList[j]);
                        newCompassSensor3D.segmentID = newSegment.id;
                        segaddonCompassSensor3DList.Add(newCompassSensor3D);

                        string inputChannelName = "Segment " + newCompassSensor3D.segmentID.ToString() + " Compass3D Right";
                        BrainInputChannel BIC_SegmentCompass3DInputRight = new BrainInputChannel(ref newCompassSensor3D.dotProductRight, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentCompass3DInputRight);

                        inputChannelName = "Segment " + newCompassSensor3D.segmentID.ToString() + " Compass3D Up";
                        BrainInputChannel BIC_SegmentCompass3DInputUp = new BrainInputChannel(ref newCompassSensor3D.dotProductUp, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentCompass3DInputUp);

                        inputChannelName = "Segment " + newCompassSensor3D.segmentID.ToString() + " Compass3D Forward";
                        BrainInputChannel BIC_SegmentCompass3DInputForward = new BrainInputChannel(ref newCompassSensor3D.dotProductForward, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentCompass3DInputForward);
                    }
                    List<AddonPositionSensor1D> positionSensor1DList = masterCritterGenome.CheckForAddonPositionSensor1D(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < positionSensor1DList.Count; j++) {
                        SegaddonPositionSensor1D newPositionSensor1D = new SegaddonPositionSensor1D(positionSensor1DList[j]);
                        newPositionSensor1D.segmentID = newSegment.id;
                        segaddonPositionSensor1DList.Add(newPositionSensor1D);

                        string inputChannelName = "Segment " + newPositionSensor1D.segmentID.ToString() + " Position1D Forward";
                        BrainInputChannel BIC_SegmentPosition1DInput = new BrainInputChannel(ref newPositionSensor1D.linearDistance, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentPosition1DInput);
                    }
                    List<AddonPositionSensor3D> positionSensor3DList = masterCritterGenome.CheckForAddonPositionSensor3D(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < positionSensor3DList.Count; j++) {
                        SegaddonPositionSensor3D newPositionSensor3D = new SegaddonPositionSensor3D(positionSensor3DList[j]);
                        newPositionSensor3D.segmentID = newSegment.id;
                        segaddonPositionSensor3DList.Add(newPositionSensor3D);

                        string inputChannelName = "Segment " + newPositionSensor3D.segmentID.ToString() + " Position3D Right";
                        BrainInputChannel BIC_SegmentPosition3DInputRight = new BrainInputChannel(ref newPositionSensor3D.distanceRight, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentPosition3DInputRight);

                        inputChannelName = "Segment " + newPositionSensor3D.segmentID.ToString() + " Position3D Up";
                        BrainInputChannel BIC_SegmentPosition3DInputUp = new BrainInputChannel(ref newPositionSensor3D.distanceUp, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentPosition3DInputUp);

                        inputChannelName = "Segment " + newPositionSensor3D.segmentID.ToString() + " Position3D Forward";
                        BrainInputChannel BIC_SegmentPosition3DInputForward = new BrainInputChannel(ref newPositionSensor3D.distanceForward, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentPosition3DInputForward);
                    }
                    List<AddonRotationSensor1D> rotationSensor1DList = masterCritterGenome.CheckForAddonRotationSensor1D(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < rotationSensor1DList.Count; j++) {
                        SegaddonRotationSensor1D newRotationSensor1D = new SegaddonRotationSensor1D(rotationSensor1DList[j]);
                        newRotationSensor1D.segmentID = newSegment.id;
                        segaddonRotationSensor1DList.Add(newRotationSensor1D);

                        string inputChannelName = "Segment " + newRotationSensor1D.segmentID.ToString() + " Rotation1D";
                        BrainInputChannel BIC_SegmentRotation1DInput = new BrainInputChannel(ref newRotationSensor1D.rotationRate, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentRotation1DInput);
                    }
                    List<AddonRotationSensor3D> rotationSensor3DList = masterCritterGenome.CheckForAddonRotationSensor3D(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < rotationSensor3DList.Count; j++) {
                        SegaddonRotationSensor3D newRotationSensor3D = new SegaddonRotationSensor3D(rotationSensor3DList[j]);
                        newRotationSensor3D.segmentID = newSegment.id;
                        segaddonRotationSensor3DList.Add(newRotationSensor3D);

                        string inputChannelName = "Segment " + newRotationSensor3D.segmentID.ToString() + " Rotation3D X";
                        BrainInputChannel BIC_SegmentRotation3DInputX = new BrainInputChannel(ref newRotationSensor3D.rotationRateX, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentRotation3DInputX);

                        inputChannelName = "Segment " + newRotationSensor3D.segmentID.ToString() + " Rotation3D Y";
                        BrainInputChannel BIC_SegmentRotation3DInputY = new BrainInputChannel(ref newRotationSensor3D.rotationRateY, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentRotation3DInputY);

                        inputChannelName = "Segment " + newRotationSensor3D.segmentID.ToString() + " Rotation3D Z";
                        BrainInputChannel BIC_SegmentRotation3DInputZ = new BrainInputChannel(ref newRotationSensor3D.rotationRateZ, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentRotation3DInputZ);
                    }
                    List<AddonVelocitySensor1D> velocitySensor1DList = masterCritterGenome.CheckForAddonVelocitySensor1D(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < velocitySensor1DList.Count; j++) {
                        SegaddonVelocitySensor1D newVelocitySensor1D = new SegaddonVelocitySensor1D(velocitySensor1DList[j]);
                        newVelocitySensor1D.segmentID = newSegment.id;
                        segaddonVelocitySensor1DList.Add(newVelocitySensor1D);

                        string inputChannelName = "Segment " + newVelocitySensor1D.segmentID.ToString() + " Velocity1D";
                        BrainInputChannel BIC_SegmentVelocity1DInput = new BrainInputChannel(ref newVelocitySensor1D.componentVelocity, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentVelocity1DInput);
                    }
                    List<AddonVelocitySensor3D> velocitySensor3DList = masterCritterGenome.CheckForAddonVelocitySensor3D(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < velocitySensor3DList.Count; j++) {
                        SegaddonVelocitySensor3D newVelocitySensor3D = new SegaddonVelocitySensor3D(velocitySensor3DList[j]);
                        newVelocitySensor3D.segmentID = newSegment.id;
                        segaddonVelocitySensor3DList.Add(newVelocitySensor3D);

                        string inputChannelName = "Segment " + newVelocitySensor3D.segmentID.ToString() + " Velocity3D Right";
                        BrainInputChannel BIC_SegmentVelocity3DInputRight = new BrainInputChannel(ref newVelocitySensor3D.velocityRight, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentVelocity3DInputRight);

                        inputChannelName = "Segment " + newVelocitySensor3D.segmentID.ToString() + " Velocity3D Up";
                        BrainInputChannel BIC_SegmentVelocity3DInputUp = new BrainInputChannel(ref newVelocitySensor3D.velocityUp, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentVelocity3DInputUp);

                        inputChannelName = "Segment " + newVelocitySensor3D.segmentID.ToString() + " Velocity3D Forward";
                        BrainInputChannel BIC_SegmentVelocity3DInputForward = new BrainInputChannel(ref newVelocitySensor3D.velocityForward, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentVelocity3DInputForward);
                    }
                    List<AddonAltimeter> altimeterList = masterCritterGenome.CheckForAddonAltimeter(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < altimeterList.Count; j++) {
                        SegaddonAltimeter newAltimeter = new SegaddonAltimeter(altimeterList[j]);
                        newAltimeter.segmentID = newSegment.id;
                        segaddonAltimeterList.Add(newAltimeter);

                        string inputChannelName = "Segment " + newAltimeter.segmentID.ToString() + " Altimeter";
                        BrainInputChannel BIC_SegmentAltimeterInput = new BrainInputChannel(ref newAltimeter.altitude, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentAltimeterInput);
                    }
                    List<AddonEarBasic> earBasicList = masterCritterGenome.CheckForAddonEarBasic(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < earBasicList.Count; j++) {
                        SegaddonEarBasic newEarBasic = new SegaddonEarBasic(earBasicList[j]);
                        newEarBasic.segmentID = newSegment.id;
                        segaddonEarBasicList.Add(newEarBasic);

                        string inputChannelName = "Segment " + newEarBasic.segmentID.ToString() + " Ear Basic";
                        BrainInputChannel BIC_SegmentEarBasicInput = new BrainInputChannel(ref newEarBasic.activation, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentEarBasicInput);
                    }
                    List<AddonGravitySensor> gravitySensorList = masterCritterGenome.CheckForAddonGravitySensor(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < gravitySensorList.Count; j++) {
                        SegaddonGravitySensor newGravitySensor = new SegaddonGravitySensor(gravitySensorList[j]);
                        newGravitySensor.segmentID = newSegment.id;
                        segaddonGravitySensorList.Add(newGravitySensor);

                        string inputChannelName = "Segment " + newGravitySensor.segmentID.ToString() + " Gravity Sensor";
                        BrainInputChannel BIC_SegmentGravityInput = new BrainInputChannel(ref newGravitySensor.gravityDot, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentGravityInput);
                    }
                    List<AddonOscillatorInput> oscillatorInputList = masterCritterGenome.CheckForAddonOscillatorInput(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < oscillatorInputList.Count; j++) {
                        SegaddonOscillatorInput newOscillatorInput = new SegaddonOscillatorInput(oscillatorInputList[j]);
                        newOscillatorInput.segmentID = newSegment.id;
                        segaddonOscillatorInputList.Add(newOscillatorInput);

                        //SegaddonOscillatorInput oscillatorInput = critterBeingTested.segaddonOscillatorInputList[oscillatorInputIndex];
                        string inputChannelName = "Segment " + newOscillatorInput.segmentID.ToString() + " Oscillator Input";
                        BrainInputChannel BIC_SegmentOscillatorInput = new BrainInputChannel(ref newOscillatorInput.value, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentOscillatorInput);
                    }
                    List<AddonValueInput> valueInputList = masterCritterGenome.CheckForAddonValueInput(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < valueInputList.Count; j++) {
                        SegaddonValueInput newValueInput = new SegaddonValueInput(valueInputList[j]);
                        newValueInput.segmentID = newSegment.id;
                        segaddonValueInputList.Add(newValueInput);

                        string inputChannelName = "Segment " + newValueInput.segmentID.ToString() + " Value Input";
                        BrainInputChannel BIC_SegmentValueInput = new BrainInputChannel(ref newValueInput.value, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentValueInput);
                    }
                    List<AddonTimerInput> timerInputList = masterCritterGenome.CheckForAddonTimerInput(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < timerInputList.Count; j++) {
                        SegaddonTimerInput newTimerInput = new SegaddonTimerInput(timerInputList[j]);
                        newTimerInput.segmentID = newSegment.id;
                        segaddonTimerInputList.Add(newTimerInput);

                        string inputChannelName = "Segment " + newTimerInput.segmentID.ToString() + " Timer Input";
                        BrainInputChannel BIC_SegmentTimerInput = new BrainInputChannel(ref newTimerInput.value, true, inputChannelName);
                        inputChannelsList.Add(BIC_SegmentTimerInput);
                    }
                    #endregion

                    #region OUTPUTS:
                    List<AddonJointMotor> jointMotorList = masterCritterGenome.CheckForAddonJointMotor(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < jointMotorList.Count; j++) {
                        SegaddonJointMotor newJointMotor = new SegaddonJointMotor(jointMotorList[j]);
                        newJointMotor.segmentID = newSegment.id;
                        segaddonJointMotorList.Add(newJointMotor);

                        //SegaddonJointMotor motor = critterBeingTested.segaddonJointMotorList[motorIndex];
                        if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeX) {
                            string outputChannelName = "Segment " + newJointMotor.segmentID.ToString() + " Motor Target X";
                            BrainOutputChannel BOC_SegmentAngleVel = new BrainOutputChannel(ref newJointMotor.targetAngularX, true, outputChannelName);
                            outputChannelsList.Add(BOC_SegmentAngleVel);
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeY) {
                            string outputChannelName = "Segment " + newJointMotor.segmentID.ToString() + " Motor Target Y";
                            BrainOutputChannel BOC_SegmentAngleVel = new BrainOutputChannel(ref newJointMotor.targetAngularY, true, outputChannelName);
                            outputChannelsList.Add(BOC_SegmentAngleVel);
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeZ) {
                            string outputChannelName = "Segment " + newJointMotor.segmentID.ToString() + " Motor Target Z";
                            BrainOutputChannel BOC_SegmentAngleVel = new BrainOutputChannel(ref newJointMotor.targetAngularZ, true, outputChannelName);
                            outputChannelsList.Add(BOC_SegmentAngleVel);
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.DualXY) {
                            string outputChannelName = "Segment " + newJointMotor.segmentID.ToString() + " Motor Target X";
                            BrainOutputChannel BOC_SegmentAngleVelX = new BrainOutputChannel(ref newJointMotor.targetAngularX, true, outputChannelName);
                            outputChannelsList.Add(BOC_SegmentAngleVelX);

                            outputChannelName = "Segment " + newJointMotor.segmentID.ToString() + " Motor Target Y";
                            BrainOutputChannel BOC_SegmentAngleVelY = new BrainOutputChannel(ref newJointMotor.targetAngularY, true, outputChannelName);
                            outputChannelsList.Add(BOC_SegmentAngleVelY);
                        }
                    }
                    List<AddonThrusterEffector1D> thrusterEffector1DList = masterCritterGenome.CheckForAddonThrusterEffector1D(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < thrusterEffector1DList.Count; j++) {
                        SegaddonThrusterEffector1D newThrusterEffector1D = new SegaddonThrusterEffector1D(thrusterEffector1DList[j]);
                        newThrusterEffector1D.segmentID = newSegment.id;
                        segaddonThrusterEffector1DList.Add(newThrusterEffector1D);

                        string outputChannelName = "Segment " + newThrusterEffector1D.segmentID.ToString() + " Thruster1D";
                        BrainOutputChannel BOC_SegmentThruster1D = new BrainOutputChannel(ref newThrusterEffector1D.throttle, true, outputChannelName);
                        outputChannelsList.Add(BOC_SegmentThruster1D);
                    }
                    List<AddonThrusterEffector3D> thrusterEffector3DList = masterCritterGenome.CheckForAddonThrusterEffector3D(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < thrusterEffector3DList.Count; j++) {
                        SegaddonThrusterEffector3D newThrusterEffector3D = new SegaddonThrusterEffector3D(thrusterEffector3DList[j]);
                        newThrusterEffector3D.segmentID = newSegment.id;
                        segaddonThrusterEffector3DList.Add(newThrusterEffector3D);

                        string outputChannelName = "Segment " + newThrusterEffector3D.segmentID.ToString() + " Thruster3D X";
                        BrainOutputChannel BOC_SegmentThruster3DX = new BrainOutputChannel(ref newThrusterEffector3D.throttleX, true, outputChannelName);
                        outputChannelsList.Add(BOC_SegmentThruster3DX);

                        outputChannelName = "Segment " + newThrusterEffector3D.segmentID.ToString() + " Thruster3D Y";
                        BrainOutputChannel BOC_SegmentThruster3DY = new BrainOutputChannel(ref newThrusterEffector3D.throttleY, true, outputChannelName);
                        outputChannelsList.Add(BOC_SegmentThruster3DY);

                        outputChannelName = "Segment " + newThrusterEffector3D.segmentID.ToString() + " Thruster3D Z";
                        BrainOutputChannel BOC_SegmentThruster3DZ = new BrainOutputChannel(ref newThrusterEffector3D.throttleZ, true, outputChannelName);
                        outputChannelsList.Add(BOC_SegmentThruster3DZ);
                    }
                    List<AddonTorqueEffector1D> torqueEffector1DList = masterCritterGenome.CheckForAddonTorqueEffector1D(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < torqueEffector1DList.Count; j++) {
                        SegaddonTorqueEffector1D newTorqueEffector1D = new SegaddonTorqueEffector1D(torqueEffector1DList[j]);
                        newTorqueEffector1D.segmentID = newSegment.id;
                        segaddonTorqueEffector1DList.Add(newTorqueEffector1D);

                        string outputChannelName = "Segment " + newTorqueEffector1D.segmentID.ToString() + " Torque1D";
                        BrainOutputChannel BOC_SegmentTorque1D = new BrainOutputChannel(ref newTorqueEffector1D.throttle, true, outputChannelName);
                        outputChannelsList.Add(BOC_SegmentTorque1D);
                    }
                    List<AddonTorqueEffector3D> torqueEffector3DList = masterCritterGenome.CheckForAddonTorqueEffector3D(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < torqueEffector3DList.Count; j++) {
                        SegaddonTorqueEffector3D newTorqueEffector3D = new SegaddonTorqueEffector3D(torqueEffector3DList[j]);
                        newTorqueEffector3D.segmentID = newSegment.id;
                        segaddonTorqueEffector3DList.Add(newTorqueEffector3D);

                        string outputChannelName = "Segment " + newTorqueEffector3D.segmentID.ToString() + " Torque3D X";
                        BrainOutputChannel BOC_SegmentTorque3DX = new BrainOutputChannel(ref newTorqueEffector3D.throttleX, true, outputChannelName);
                        outputChannelsList.Add(BOC_SegmentTorque3DX);

                        outputChannelName = "Segment " + newTorqueEffector3D.segmentID.ToString() + " Torque3D Y";
                        BrainOutputChannel BOC_SegmentTorque3DY = new BrainOutputChannel(ref newTorqueEffector3D.throttleY, true, outputChannelName);
                        outputChannelsList.Add(BOC_SegmentTorque3DY);

                        outputChannelName = "Segment " + newTorqueEffector3D.segmentID.ToString() + " Torque3D Z";
                        BrainOutputChannel BOC_SegmentTorque3DZ = new BrainOutputChannel(ref newTorqueEffector3D.throttleZ, true, outputChannelName);
                        outputChannelsList.Add(BOC_SegmentTorque3DZ);
                    }
                    List<AddonMouthBasic> mouthBasicList = masterCritterGenome.CheckForAddonMouthBasic(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < mouthBasicList.Count; j++) {
                        SegaddonMouthBasic newMouthBasic = new SegaddonMouthBasic(mouthBasicList[j]);
                        newMouthBasic.segmentID = newSegment.id;
                        segaddonMouthBasicList.Add(newMouthBasic);

                        SegaddonTriggerDetector triggerDetector = newGO.AddComponent<SegaddonTriggerDetector>();
                        triggerDetector.referencedMouth = newMouthBasic;
                    }
                    List<AddonNoiseMakerBasic> noiseMakerBasicList = masterCritterGenome.CheckForAddonNoiseMakerBasic(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < noiseMakerBasicList.Count; j++) {
                        SegaddonNoiseMakerBasic newNoiseMakerBasic = new SegaddonNoiseMakerBasic(noiseMakerBasicList[j]);
                        newNoiseMakerBasic.segmentID = newSegment.id;
                        segaddonNoiseMakerBasicList.Add(newNoiseMakerBasic);

                        string outputChannelName = "Segment " + newNoiseMakerBasic.segmentID.ToString() + " NoiseMaker";
                        BrainOutputChannel BOC_SegmentNoiseMaker = new BrainOutputChannel(ref newNoiseMakerBasic.volume, true, outputChannelName);
                        outputChannelsList.Add(BOC_SegmentNoiseMaker);
                    }
                    List<AddonSticky> stickyList = masterCritterGenome.CheckForAddonSticky(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < stickyList.Count; j++) {
                        SegaddonSticky newSticky = new SegaddonSticky(stickyList[j]);
                        newSticky.segmentID = newSegment.id;
                        segaddonStickyList.Add(newSticky);

                        string outputChannelName = "Segment " + newSticky.segmentID.ToString() + " Sticky";
                        BrainOutputChannel BOC_SegmentSticky = new BrainOutputChannel(ref newSticky.stickiness, true, outputChannelName);
                        outputChannelsList.Add(BOC_SegmentSticky);
                    }
                    List<AddonWeaponBasic> weaponBasicList = masterCritterGenome.CheckForAddonWeaponBasic(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < weaponBasicList.Count; j++) {
                        SegaddonWeaponBasic newWeaponBasic = new SegaddonWeaponBasic(weaponBasicList[j]);
                        newWeaponBasic.segmentID = newSegment.id;
                        segaddonWeaponBasicList.Add(newWeaponBasic);

                        string outputChannelName = "Segment " + newWeaponBasic.segmentID.ToString() + " Weapon";
                        BrainOutputChannel BOC_SegmentWeapon = new BrainOutputChannel(ref newWeaponBasic.strength, true, outputChannelName);
                        outputChannelsList.Add(BOC_SegmentWeapon);
                    }                    
                    #endregion
                    
                    
                }
                
                
                // Figure out how many unique Child nodes this built node has:
                //int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedJointLinkList.Count; // old
                int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList.Count;
                //Debug.Log("numberOfChildNodes: " + numberOfChildNodes.ToString() + "currentBuildSegmentList[i].sourceNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + ", i: " + i.ToString());
                for (int c = 0; c < numberOfChildNodes; c++) {

                    // if NO symmetry:
                    // Check if Attaching to a recursion chain && if onlyattachToTail is active:
                    int childID = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList[c];
                    //Debug.Log("%%%%% c=" + c.ToString() + ", childID: " + childID.ToString() + ", critterNodeListCount: " + masterCritterGenome.CritterNodeList.Count.ToString());
                    // if(currentBuildSegmentList[i].sourceNode.attachedJointLinkList[c].childNode.parentJointLink.onlyAttachToTailNode)  // OLD
                    if (masterCritterGenome.CritterNodeList[childID].jointLink.onlyAttachToTailNode) { 
                        if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) {
                            if (newSegment.recursionNumber > newSegment.sourceNode.jointLink.numberOfRecursions) {
                                // Only build segment if it is on the end of a recursion chain:
                                BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                                newSegmentInfo.sourceNode = masterCritterGenome.CritterNodeList[childID];
                                newSegmentInfo.parentSegment = newSegment;
                                nextBuildSegmentList.Add(newSegmentInfo);

                                if (masterCritterGenome.CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                                    // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                                    BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                                    newSegmentInfoMirror.sourceNode = masterCritterGenome.CritterNodeList[childID];
                                    newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                                    newSegmentInfoMirror.parentSegment = newSegment;  // 
                                    nextBuildSegmentList.Add(newSegmentInfoMirror);
                                }
                            }
                        }
                        else {
                            // It only attaches to End nodes, but is parented to a Non-recursive segment, so proceed normally!!!
                            BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                            newSegmentInfo.sourceNode = masterCritterGenome.CritterNodeList[childID];
                            newSegmentInfo.parentSegment = newSegment;
                            nextBuildSegmentList.Add(newSegmentInfo);

                            if (masterCritterGenome.CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                                // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                                BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                                newSegmentInfoMirror.sourceNode = masterCritterGenome.CritterNodeList[childID];
                                newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                                newSegmentInfoMirror.parentSegment = newSegment;  // 
                                nextBuildSegmentList.Add(newSegmentInfoMirror);
                            }
                        }                       
                    }
                    else {  // proceed normally:
                        BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                        newSegmentInfo.sourceNode = masterCritterGenome.CritterNodeList[childID];
                        newSegmentInfo.parentSegment = newSegment;
                        nextBuildSegmentList.Add(newSegmentInfo);

                        if (masterCritterGenome.CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                            // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                            BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                            newSegmentInfoMirror.sourceNode = masterCritterGenome.CritterNodeList[childID];
                            newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                            newSegmentInfoMirror.parentSegment = newSegment;  // 
                            nextBuildSegmentList.Add(newSegmentInfoMirror);
                        }
                    }             
                }                               
            }
            // After all buildNodes have been built, and their subsequent childNodes Enqueued, copy pendingChildQueue into buildNodesQueue
            currentBuildSegmentList.Clear();
            // SWAP LISTS:
            if (nextBuildSegmentList.Count > 0) {
                for (int j = 0; j < nextBuildSegmentList.Count; j++) {
                    currentBuildSegmentList.Add(nextBuildSegmentList[j]);
                }
                nextBuildSegmentList.Clear();  // empty this list for next depth-round
            }
            else {
                isPendingChildren = false;
            }
            if (currentDepth >= maxDepth) { // SAFEGUARD!! prevents infinite loop in case I mess something up
                isPendingChildren = false;
            }
            currentDepth++;
        }

        //Debug.Log("RebuildCritterFromGenomeRecursive " + inputChannelsList.Count.ToString() + ", " + outputChannelsList.Count.ToString());
        //Debug.Log("RebuildCritterFromGenomeRecursive: COM_Offset: (" + masterCritterGenome.centerOfMassOffset.x.ToString() + ", " + masterCritterGenome.centerOfMassOffset.y.ToString() + ", " + masterCritterGenome.centerOfMassOffset.z.ToString() + "), totalVolume: " + critterTotalVolume.ToString());// + " RootPos: " + critterSegmentList[0].transform.position.ToString());
    }
    public void PreBuildCritter(float variableMass) {
        //Debug.Log("RebuildCritterFromGenomeRecursive: " + masterCritterGenome.CritterNodeList.Count.ToString());

        // interpret Genome and construct critter in its bind pose
        bool isPendingChildren = true;
        int currentDepth = 0; // start with RootNode
        int maxDepth = 20;  // safeguard to prevent while loop lock
        int nextSegmentID = 0;
        List<CritterSegment> builtSegmentsList = new List<CritterSegment>();  // keep track of segments that have been built - linear in-order array 0-n segments
        List<BuildSegmentInfo> currentBuildSegmentList = new List<BuildSegmentInfo>();  // keeps track of all current-depth segment build-requests, and holds important metadata
        List<BuildSegmentInfo> nextBuildSegmentList = new List<BuildSegmentInfo>();  // used to keep track of next childSegments that need to be built
        float critterTotalVolume = 0f; // keep track of total volume

        // ***********  Will attempt to traverse the Segments to be created, keeping track of where on each graph (nodes# & segment#) the current build is on.
        BuildSegmentInfo rootSegmentBuildInfo = new BuildSegmentInfo();
        rootSegmentBuildInfo.sourceNode = CritterNodeList[0];
        currentBuildSegmentList.Add(rootSegmentBuildInfo);  // ROOT NODE IS SPECIAL!        

        // Do a Breadth-first traversal??
        #region First WhileLoop
        while (isPendingChildren) {
            //int numberOfChildNodes = masterCritterGenome.CritterNodeList[currentNode].attachedJointLinkList.Count;

            for (int i = 0; i < currentBuildSegmentList.Count; i++) {
                //Debug.Log("currentDepth: " + currentDepth.ToString() + "builtNodesQueue.Count: " + builtSegmentsList.Count.ToString() + ", pendingNodes: " + currentBuildSegmentList.Count.ToString() + ", i: " + i.ToString());
                // Iterate through pending nodes
                // Build current node --> Segment
                GameObject newGO = new GameObject("Node" + nextSegmentID.ToString());
                CritterSegment newSegment = newGO.AddComponent<CritterSegment>();
                builtSegmentsList.Add(newSegment);

                if(TempCritterConstructionGroup.tempCritterConstructionGroup != null) {
                    newGO.transform.SetParent(TempCritterConstructionGroup.tempCritterConstructionGroup.gameObject.transform);
                }
                
                //newGO.AddComponent<BoxCollider>().isTrigger = false;                
                //critterSegmentList.Add(newGO);  // Add to master Linear list of Segments
                //newSegment.InitGamePiece();  // create the mesh and some other initialization stuff
                newSegment.sourceNode = currentBuildSegmentList[i].sourceNode;
                newSegment.id = nextSegmentID;
                nextSegmentID++;

                if (currentBuildSegmentList[i].sourceNode.ID == 0) {  // is ROOT segment  -- Look into doing Root build BEFORE for loop to avoid the need to do this check
                    newGO.transform.position = Vector3.zero;
                    newGO.transform.localPosition = Vector3.zero;
                    newGO.transform.rotation = Quaternion.identity;
                    newSegment.scalingFactor = newSegment.sourceNode.jointLink.recursionScalingFactor;
                    newGO.transform.localScale = currentBuildSegmentList[i].sourceNode.dimensions * newSegment.scalingFactor;
                    //newSegment.surfaceArea = new Vector3(newGO.transform.localScale.y * newGO.transform.localScale.z * 2f, newGO.transform.localScale.x * newGO.transform.localScale.z * 2f, newGO.transform.localScale.x * newGO.transform.localScale.y * 2f);

                }
                else {  // if NOT root segment, can consider parent-related stuff:
                    newSegment.parentSegment = currentBuildSegmentList[i].parentSegment;
                    // Inherit Axis-Inversions from parent segment:
                    newSegment.mirrorX = newSegment.parentSegment.mirrorX;
                    newSegment.mirrorY = newSegment.parentSegment.mirrorY;
                    newSegment.mirrorZ = newSegment.parentSegment.mirrorZ;
                    // inherit scaling factor from parent -- this is later adjusted again if it is part of a recursion chain
                    newSegment.scalingFactor = newSegment.parentSegment.scalingFactor;
                    newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor; // propagate scaling factor
                    // Check for if the segment currently being built is a Mirror COPY:
                    if (currentBuildSegmentList[i].isMirror) {
                        //Debug.Log("This is a MIRROR COPY segment - Wow!");
                        if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorX) {
                            // Invert the X-axis  (this will propagate down to all this segment's children
                            newSegment.mirrorX = !newSegment.mirrorX;
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorY) {
                            newSegment.mirrorY = !newSegment.mirrorY;
                        }
                        //else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorZ) {
                        //    newSegment.mirrorZ = !newSegment.mirrorZ;
                        //}
                    }
                }

                // CHECK FOR RECURSION:
                if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { // if the node being considered has recursions:
                    //Debug.Log("currentNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + "newSegmentRecursion#: " + newSegment.recursionNumber.ToString() + ", parentRecursion#: " + currentBuildSegmentList[i].parentSegment.recursionNumber.ToString());
                    if (newSegment.sourceNode == currentBuildSegmentList[i].parentSegment.sourceNode) {  // if this segment's sourceNode is the same is its parent Segment's sourceNode, then it is not the root of the recursion chain!
                        //Debug.Log("newSegment.sourceNode == currentBuildNodeParentSegmentList[i].sourceNode!");

                        // Are we at the end of a recursion chain?
                        if (currentBuildSegmentList[i].parentSegment.recursionNumber >= currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions) {
                            //Debug.Log("recursion number greater than numRecursions! ( " + currentBuildSegmentList[i].parentSegment.recursionNumber.ToString() + " vs " + currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions.ToString());
                            newSegment.recursionNumber = currentBuildSegmentList[i].parentSegment.recursionNumber + 1; //
                            //newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor;
                        }
                        else {  // create new recursion instance!!
                            BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                            newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode;  // request a segment to be built again based on the current sourceNode
                            newSegment.recursionNumber = currentBuildSegmentList[i].parentSegment.recursionNumber + 1;
                            //newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor; // propagate scaling factor
                            newSegmentInfo.parentSegment = newSegment; // parent of itself (the just-built Segment)
                            nextBuildSegmentList.Add(newSegmentInfo);
                            // If the node also has Symmetry:
                            if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                                // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                                BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                                newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode;  // uses same sourceNode, but tags as Mirror:
                                newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                                newSegmentInfoMirror.parentSegment = newSegment;  // 
                                nextBuildSegmentList.Add(newSegmentInfoMirror);
                            }
                        }
                    }
                    else { // this is the root --- its sourceNode has recursion, and this segment is unique from its parentNode:
                        BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                        newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode;
                        newSegment.recursionNumber = 1;
                        newSegmentInfo.parentSegment = newSegment;
                        nextBuildSegmentList.Add(newSegmentInfo);
                        // If the node also has Symmetry:
                        if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                            // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                            BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                            newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode;  // uses same sourceNode, but tags as Mirror:
                            newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                            newSegmentInfoMirror.parentSegment = newSegment;  // 
                            nextBuildSegmentList.Add(newSegmentInfoMirror);
                        }
                    }
                }
                // Figure out how many unique Child nodes this built node has:
                //int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedJointLinkList.Count; // old
                int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList.Count;
                //Debug.Log("numberOfChildNodes: " + numberOfChildNodes.ToString() + "currentBuildSegmentList[i].sourceNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + ", i: " + i.ToString());
                for (int c = 0; c < numberOfChildNodes; c++) {

                    // if NO symmetry:
                    // Check if Attaching to a recursion chain && if onlyattachToTail is active:
                    int childID = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList[c];
                    //Debug.Log("%%%%% c=" + c.ToString() + ", childID: " + childID.ToString() + ", critterNodeListCount: " + masterCritterGenome.CritterNodeList.Count.ToString());
                    // if(currentBuildSegmentList[i].sourceNode.attachedJointLinkList[c].childNode.parentJointLink.onlyAttachToTailNode)  // OLD
                    if (CritterNodeList[childID].jointLink.onlyAttachToTailNode) {
                        if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) {
                            if (newSegment.recursionNumber > newSegment.sourceNode.jointLink.numberOfRecursions) {
                                // Only build segment if it is on the end of a recursion chain:
                                BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                                newSegmentInfo.sourceNode = CritterNodeList[childID];
                                newSegmentInfo.parentSegment = newSegment;
                                nextBuildSegmentList.Add(newSegmentInfo);

                                if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                                    // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                                    BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                                    newSegmentInfoMirror.sourceNode = CritterNodeList[childID];
                                    newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                                    newSegmentInfoMirror.parentSegment = newSegment;  // 
                                    nextBuildSegmentList.Add(newSegmentInfoMirror);
                                }
                            }
                        }
                        else {
                            // It only attaches to End nodes, but is parented to a Non-recursive segment, so proceed normally!!!
                            BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                            newSegmentInfo.sourceNode = CritterNodeList[childID];
                            newSegmentInfo.parentSegment = newSegment;
                            nextBuildSegmentList.Add(newSegmentInfo);

                            if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                                // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                                BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                                newSegmentInfoMirror.sourceNode = CritterNodeList[childID];
                                newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                                newSegmentInfoMirror.parentSegment = newSegment;  // 
                                nextBuildSegmentList.Add(newSegmentInfoMirror);
                            }
                        }
                    }
                    else {  // proceed normally:
                        BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                        newSegmentInfo.sourceNode = CritterNodeList[childID];
                        newSegmentInfo.parentSegment = newSegment;
                        nextBuildSegmentList.Add(newSegmentInfo);

                        if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                            // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                            BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                            newSegmentInfoMirror.sourceNode = CritterNodeList[childID];
                            newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                            newSegmentInfoMirror.parentSegment = newSegment;  // 
                            nextBuildSegmentList.Add(newSegmentInfoMirror);
                        }
                    }
                }

                // PositionSEGMENT GameObject!!!
                if (newSegment.id == 0) {  // if ROOT NODE:

                }
                else {
                    SetSegmentTransform(newGO);  // Properly position the SegmentGO where it should be  && scale!
                }
                critterTotalVolume += newGO.transform.localScale.x * newGO.transform.localScale.y * newGO.transform.localScale.z;
            }
            // After all buildNodes have been built, and their subsequent childNodes Enqueued, copy pendingChildQueue into buildNodesQueue
            currentBuildSegmentList.Clear();
            // SWAP LISTS:
            if (nextBuildSegmentList.Count > 0) {
                for (int j = 0; j < nextBuildSegmentList.Count; j++) {
                    currentBuildSegmentList.Add(nextBuildSegmentList[j]);
                }
                nextBuildSegmentList.Clear();  // empty this list for next depth-round
            }
            else {
                isPendingChildren = false;
            }
            if (currentDepth >= maxDepth) { // SAFEGUARD!! prevents infinite loop in case I mess something up
                isPendingChildren = false;
            }
            currentDepth++;
        }
        #endregion
        //Debug.Log("RebuildCritterFromGenomeRecursive " + inputChannelsList.Count.ToString() + ", " + outputChannelsList.Count.ToString());

        // Re-Size Critter based on target volume:
        float targetTotalVolume = 4f;
        float linearScaling = Mathf.Pow(targetTotalVolume / critterTotalVolume, 1f / 3f);
        for (int i = 0; i < CritterNodeList.Count; i++) {
            CritterNodeList[i].dimensions.x *= linearScaling;
            CritterNodeList[i].dimensions.y *= linearScaling;
            CritterNodeList[i].dimensions.z *= linearScaling;
        }

        // interpret Genome and construct critter in its bind pose
        isPendingChildren = true;
        currentDepth = 0; // start with RootNode
        maxDepth = 20;  // safeguard to prevent while loop lock
        nextSegmentID = 0;
        builtSegmentsList.Clear();
        currentBuildSegmentList.Clear();
        nextBuildSegmentList.Clear();
        // ***********  Will attempt to traverse the Segments to be created, keeping track of where on each graph (nodes# & segment#) the current build is on.
        rootSegmentBuildInfo = new BuildSegmentInfo();
        rootSegmentBuildInfo.sourceNode = CritterNodeList[0];
        currentBuildSegmentList.Add(rootSegmentBuildInfo);  // ROOT NODE IS SPECIAL!        

        // Do a Breadth-first traversal??
        #region Second WhileLoop
        while (isPendingChildren) {
            //int numberOfChildNodes = masterCritterGenome.CritterNodeList[currentNode].attachedJointLinkList.Count;

            for (int i = 0; i < currentBuildSegmentList.Count; i++) {
                //Debug.Log("currentDepth: " + currentDepth.ToString() + "builtNodesQueue.Count: " + builtSegmentsList.Count.ToString() + ", pendingNodes: " + currentBuildSegmentList.Count.ToString() + ", i: " + i.ToString());
                // Iterate through pending nodes
                // Build current node --> Segment
                GameObject newGO = new GameObject("Node" + nextSegmentID.ToString());
                CritterSegment newSegment = newGO.AddComponent<CritterSegment>();
                builtSegmentsList.Add(newSegment);
                
                newGO.transform.SetParent(TempCritterConstructionGroup.tempCritterConstructionGroup.gameObject.transform);
                //newGO.AddComponent<BoxCollider>().isTrigger = false;                
                //critterSegmentList.Add(newGO);  // Add to master Linear list of Segments
                //newSegment.InitGamePiece();  // create the mesh and some other initialization stuff
                newSegment.sourceNode = currentBuildSegmentList[i].sourceNode;
                newSegment.id = nextSegmentID;
                nextSegmentID++;

                if (currentBuildSegmentList[i].sourceNode.ID == 0) {  // is ROOT segment  -- Look into doing Root build BEFORE for loop to avoid the need to do this check
                    newGO.transform.position = Vector3.zero;
                    newGO.transform.rotation = Quaternion.identity;
                    newSegment.scalingFactor = newSegment.sourceNode.jointLink.recursionScalingFactor;
                    newGO.transform.localScale = currentBuildSegmentList[i].sourceNode.dimensions * newSegment.scalingFactor;
                    //newSegment.surfaceArea = new Vector3(newGO.transform.localScale.y * newGO.transform.localScale.z * 2f, newGO.transform.localScale.x * newGO.transform.localScale.z * 2f, newGO.transform.localScale.x * newGO.transform.localScale.y * 2f);

                }
                else {  // if NOT root segment, can consider parent-related stuff:
                    newSegment.parentSegment = currentBuildSegmentList[i].parentSegment;
                    // Inherit Axis-Inversions from parent segment:
                    newSegment.mirrorX = newSegment.parentSegment.mirrorX;
                    newSegment.mirrorY = newSegment.parentSegment.mirrorY;
                    newSegment.mirrorZ = newSegment.parentSegment.mirrorZ;
                    // inherit scaling factor from parent -- this is later adjusted again if it is part of a recursion chain
                    newSegment.scalingFactor = newSegment.parentSegment.scalingFactor;
                    newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor; // propagate scaling factor
                    // Check for if the segment currently being built is a Mirror COPY:
                    if (currentBuildSegmentList[i].isMirror) {
                        //Debug.Log("This is a MIRROR COPY segment - Wow!");
                        if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorX) {
                            // Invert the X-axis  (this will propagate down to all this segment's children
                            newSegment.mirrorX = !newSegment.mirrorX;
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorY) {
                            newSegment.mirrorY = !newSegment.mirrorY;
                        }
                        //else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorZ) {
                        //    newSegment.mirrorZ = !newSegment.mirrorZ;
                        //}
                    }
                }
                
                // CHECK FOR RECURSION:
                if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { // if the node being considered has recursions:
                    //Debug.Log("currentNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + "newSegmentRecursion#: " + newSegment.recursionNumber.ToString() + ", parentRecursion#: " + currentBuildSegmentList[i].parentSegment.recursionNumber.ToString());
                    if (newSegment.sourceNode == currentBuildSegmentList[i].parentSegment.sourceNode) {  // if this segment's sourceNode is the same is its parent Segment's sourceNode, then it is not the root of the recursion chain!
                        //Debug.Log("newSegment.sourceNode == currentBuildNodeParentSegmentList[i].sourceNode!");

                        // Are we at the end of a recursion chain?
                        if (currentBuildSegmentList[i].parentSegment.recursionNumber >= currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions) {
                            //Debug.Log("recursion number greater than numRecursions! ( " + currentBuildSegmentList[i].parentSegment.recursionNumber.ToString() + " vs " + currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions.ToString());
                            newSegment.recursionNumber = currentBuildSegmentList[i].parentSegment.recursionNumber + 1; //
                            //newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor;
                        }
                        else {  // create new recursion instance!!
                            BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                            newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode;  // request a segment to be built again based on the current sourceNode
                            newSegment.recursionNumber = currentBuildSegmentList[i].parentSegment.recursionNumber + 1;
                            //newSegment.scalingFactor *= currentBuildSegmentList[i].sourceNode.jointLink.recursionScalingFactor; // propagate scaling factor
                            newSegmentInfo.parentSegment = newSegment; // parent of itself (the just-built Segment)
                            nextBuildSegmentList.Add(newSegmentInfo);
                            // If the node also has Symmetry:
                            if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                                // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                                BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                                newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode;  // uses same sourceNode, but tags as Mirror:
                                newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                                newSegmentInfoMirror.parentSegment = newSegment;  // 
                                nextBuildSegmentList.Add(newSegmentInfoMirror);
                            }
                        }
                    }
                    else { // this is the root --- its sourceNode has recursion, and this segment is unique from its parentNode:
                        BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                        newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode;
                        newSegment.recursionNumber = 1;
                        newSegmentInfo.parentSegment = newSegment;
                        nextBuildSegmentList.Add(newSegmentInfo);
                        // If the node also has Symmetry:
                        if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                            // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                            BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                            newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode;  // uses same sourceNode, but tags as Mirror:
                            newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                            newSegmentInfoMirror.parentSegment = newSegment;  // 
                            nextBuildSegmentList.Add(newSegmentInfoMirror);
                        }
                    }
                }
                // Figure out how many unique Child nodes this built node has:
                //int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedJointLinkList.Count; // old
                int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList.Count;
                //Debug.Log("numberOfChildNodes: " + numberOfChildNodes.ToString() + "currentBuildSegmentList[i].sourceNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + ", i: " + i.ToString());
                for (int c = 0; c < numberOfChildNodes; c++) {

                    // if NO symmetry:
                    // Check if Attaching to a recursion chain && if onlyattachToTail is active:
                    int childID = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList[c];
                    //Debug.Log("%%%%% c=" + c.ToString() + ", childID: " + childID.ToString() + ", critterNodeListCount: " + masterCritterGenome.CritterNodeList.Count.ToString());
                    // if(currentBuildSegmentList[i].sourceNode.attachedJointLinkList[c].childNode.parentJointLink.onlyAttachToTailNode)  // OLD
                    if (CritterNodeList[childID].jointLink.onlyAttachToTailNode) {
                        if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) {
                            if (newSegment.recursionNumber > newSegment.sourceNode.jointLink.numberOfRecursions) {
                                // Only build segment if it is on the end of a recursion chain:
                                BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                                newSegmentInfo.sourceNode = CritterNodeList[childID];
                                newSegmentInfo.parentSegment = newSegment;
                                nextBuildSegmentList.Add(newSegmentInfo);

                                if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                                    // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                                    BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                                    newSegmentInfoMirror.sourceNode = CritterNodeList[childID];
                                    newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                                    newSegmentInfoMirror.parentSegment = newSegment;  // 
                                    nextBuildSegmentList.Add(newSegmentInfoMirror);
                                }
                            }
                        }
                        else {
                            // It only attaches to End nodes, but is parented to a Non-recursive segment, so proceed normally!!!
                            BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                            newSegmentInfo.sourceNode = CritterNodeList[childID];
                            newSegmentInfo.parentSegment = newSegment;
                            nextBuildSegmentList.Add(newSegmentInfo);

                            if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                                // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                                BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                                newSegmentInfoMirror.sourceNode = CritterNodeList[childID];
                                newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                                newSegmentInfoMirror.parentSegment = newSegment;  // 
                                nextBuildSegmentList.Add(newSegmentInfoMirror);
                            }
                        }
                    }
                    else {  // proceed normally:
                        BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                        newSegmentInfo.sourceNode = CritterNodeList[childID];
                        newSegmentInfo.parentSegment = newSegment;
                        nextBuildSegmentList.Add(newSegmentInfo);

                        if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                            // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                            BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                            newSegmentInfoMirror.sourceNode = CritterNodeList[childID];
                            newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                            newSegmentInfoMirror.parentSegment = newSegment;  // 
                            nextBuildSegmentList.Add(newSegmentInfoMirror);
                        }
                    }
                }

                // PositionSEGMENT GameObject!!!
                if (newSegment.id == 0) {  // if ROOT NODE:

                }
                else {
                    SetSegmentTransform(newGO);  // Properly position the SegmentGO where it should be  && scale!                    
                }
            }
            // After all buildNodes have been built, and their subsequent childNodes Enqueued, copy pendingChildQueue into buildNodesQueue
            currentBuildSegmentList.Clear();
            // SWAP LISTS:
            if (nextBuildSegmentList.Count > 0) {
                for (int j = 0; j < nextBuildSegmentList.Count; j++) {
                    currentBuildSegmentList.Add(nextBuildSegmentList[j]);
                }
                nextBuildSegmentList.Clear();  // empty this list for next depth-round
            }
            else {
                isPendingChildren = false;
            }
            if (currentDepth >= maxDepth) { // SAFEGUARD!! prevents infinite loop in case I mess something up
                isPendingChildren = false;
            }
            currentDepth++;
        }
        #endregion
        //Debug.Log("RebuildCritterFromGenomeRecursive " + inputChannelsList.Count.ToString() + ", " + outputChannelsList.Count.ToString());

        centerOfMassOffset.x = 0f;
        centerOfMassOffset.y = 0f;
        centerOfMassOffset.z = 0f;
        Vector3 avgPos = new Vector3(0f, 0f, 0f);
        List<float> segmentMassesList = new List<float>();
        float critterTotalMass = 0f;        
        
        // Fill data arrays with Critter stats for CritterSEGMENTS:
        for (int i = 0; i < builtSegmentsList.Count; i++) {  // iterate through every segment            
            float segmentVolume = builtSegmentsList[i].transform.localScale.x * builtSegmentsList[i].transform.localScale.y * builtSegmentsList[i].transform.localScale.z;            
            float segmentMass = Mathf.Lerp(1f, segmentVolume, variableMass);
            segmentMassesList.Add(segmentMass);
            critterTotalMass += segmentMass;
        }
        float avgMass = critterTotalMass / builtSegmentsList.Count;  //
        string segmentPositions = "CritterPreBuild SegmentPositions: \n";
        critterTotalMass /= avgMass;  // Adjust to center around 1f;
        for (int j = 0; j < builtSegmentsList.Count; j++) {
            // Finalize Segment Mass Value:
            segmentMassesList[j] /= avgMass;  // Center the segment Masses around 1f, to avoid precision errors
            //critterBeingTested.critterSegmentList[j].GetComponent<Rigidbody>().mass = wormSegmentArray_Mass[j];
            float shareOfTotalMass = segmentMassesList[j] / critterTotalMass;
            avgPos.x += builtSegmentsList[j].transform.position.x * shareOfTotalMass;  // multiply position by proportional share of total mass
            avgPos.y += builtSegmentsList[j].transform.position.y * shareOfTotalMass;
            avgPos.z += builtSegmentsList[j].transform.position.z * shareOfTotalMass;
            segmentPositions += "(" + builtSegmentsList[j].transform.position.x.ToString() + ", " + builtSegmentsList[j].transform.position.y.ToString() + ", " + builtSegmentsList[j].transform.position.z.ToString() + ")\n";
        }        
        centerOfMassOffset.x = -avgPos.x;
        centerOfMassOffset.y = -avgPos.y;
        centerOfMassOffset.z = -avgPos.z;
        //Debug.Log(segmentPositions + "\nC.O.M: (" + avgPos.x.ToString() + ", " + avgPos.y.ToString() + ", " + avgPos.z.ToString() + ")");        
        // Delete created Segment GameObjects:
        // Do I need to delete Components first?
        TempCritterConstructionGroup.tempCritterConstructionGroup.DeleteSegments();
    }
    public List<GeneNodeNEAT> GetBlankBrainNodesFromBody() {
        List<GeneNodeNEAT> newNodeList = new List<GeneNodeNEAT>();

        // Split into Input/Output list and put together afterward?
        List<GeneNodeNEAT> inputNodeList = new List<GeneNodeNEAT>();
        List<GeneNodeNEAT> outputNodeList = new List<GeneNodeNEAT>();

        int numSegments = 0;
        int numInputs = 0;
        int numOutputs = 0;

        bool isPendingChildren = true;
        int currentDepth = 0; // start with RootNode
        int maxDepth = 20;  // safeguard to prevent while loop lock
        int nextSegmentID = 0;

        int currentBrainNodeID = 0;

        List<BuildSegmentInfo> currentBuildSegmentList = new List<BuildSegmentInfo>();  // keeps track of all current-depth segment build-requests, and holds important metadata
        List<BuildSegmentInfo> nextBuildSegmentList = new List<BuildSegmentInfo>();  // used to keep track of next childSegments that need to be built

        // ***********  Will attempt to traverse the Segments to be created, keeping track of where on each graph (nodes# & segment#) the current build is on.
        BuildSegmentInfo rootSegmentBuildInfo = new BuildSegmentInfo();
        rootSegmentBuildInfo.sourceNode = CritterNodeList[0];
        currentBuildSegmentList.Add(rootSegmentBuildInfo);  // ROOT NODE IS SPECIAL!

        // Do a Breadth-first traversal??
        while (isPendingChildren) {
            for (int i = 0; i < currentBuildSegmentList.Count; i++) {
                numSegments++;
                nextSegmentID++;
                
                // PhysicalAttributes no inputs/outputs
                #region INPUTS
                // Joint Angle Sensors:
                if (currentBuildSegmentList[i].sourceNode.ID != 0) {  // is NOT ROOT segment  -- Look into doing Root build BEFORE for loop to avoid the need to do this check                                                                      
                    List<AddonJointAngleSensor> jointAngleSensorList = CheckForAddonJointAngleSensor(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < jointAngleSensorList.Count; j++) {
                        // HINGE X X X X X
                        if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeX) {
                            if (jointAngleSensorList[j].measureVel[0]) {  // ALSO MEASURES ANGULAR VELOCITY:
                                numInputs++;
                                GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                                inputNodeList.Add(newNodeNEAT1);
                                currentBrainNodeID++;

                                numInputs++;
                                GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1);
                                inputNodeList.Add(newNodeNEAT2);
                                currentBrainNodeID++;
                            }
                            else {  // Only Angle, no velocity:
                                numInputs++;
                                GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                                inputNodeList.Add(newNodeNEAT);
                                currentBrainNodeID++;
                            }
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeY) {
                            if (jointAngleSensorList[j].measureVel[0]) {
                                numInputs++;
                                GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                                inputNodeList.Add(newNodeNEAT1);
                                currentBrainNodeID++;

                                numInputs++;
                                GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1);
                                inputNodeList.Add(newNodeNEAT2);
                                currentBrainNodeID++;
                            }
                            else {
                                numInputs++;
                                GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                                inputNodeList.Add(newNodeNEAT);
                                currentBrainNodeID++;
                            }
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeZ) {
                            if (jointAngleSensorList[j].measureVel[0]) {
                                numInputs++;
                                GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                                inputNodeList.Add(newNodeNEAT1);
                                currentBrainNodeID++;

                                numInputs++;
                                GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1);
                                inputNodeList.Add(newNodeNEAT2);
                                currentBrainNodeID++;
                            }
                            else {
                                numInputs++;
                                GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                                inputNodeList.Add(newNodeNEAT);
                                currentBrainNodeID++;
                            }
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.DualXY) {
                            if (jointAngleSensorList[j].measureVel[0]) {
                                numInputs++;
                                GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                                inputNodeList.Add(newNodeNEAT1);
                                currentBrainNodeID++;

                                numInputs++;
                                GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1);
                                inputNodeList.Add(newNodeNEAT2);
                                currentBrainNodeID++;

                                numInputs++;
                                GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2);
                                inputNodeList.Add(newNodeNEAT3);
                                currentBrainNodeID++;

                                numInputs++;
                                GeneNodeNEAT newNodeNEAT4 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 3);
                                inputNodeList.Add(newNodeNEAT4);
                                currentBrainNodeID++;
                            }
                            else {
                                numInputs++;
                                GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                                inputNodeList.Add(newNodeNEAT1);
                                currentBrainNodeID++;

                                numInputs++;
                                GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, jointAngleSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1);
                                inputNodeList.Add(newNodeNEAT2);
                                currentBrainNodeID++;
                            }
                        }
                    }
                }
                List<AddonContactSensor> contactSensorList = CheckForAddonContactSensor(currentBuildSegmentList[i].sourceNode.ID);
                for(int j = 0; j < contactSensorList.Count; j++) {
                    numInputs++;
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, contactSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    inputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;
                }                
                List<AddonRaycastSensor> raycastSensorList = CheckForAddonRaycastSensor(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < raycastSensorList.Count; j++) {
                    numInputs++;
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, raycastSensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    inputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;
                }
                List<AddonCompassSensor1D> compassSensor1DList = CheckForAddonCompassSensor1D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < compassSensor1DList.Count; j++) {
                    numInputs++;
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, compassSensor1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    inputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;
                }
                List<AddonCompassSensor3D> compassSensor3DList = CheckForAddonCompassSensor3D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < compassSensor3DList.Count; j++) {
                    numInputs++;
                    GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, compassSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    inputNodeList.Add(newNodeNEAT1);
                    currentBrainNodeID++;

                    numInputs++;
                    GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, compassSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1);
                    inputNodeList.Add(newNodeNEAT2);
                    currentBrainNodeID++;

                    numInputs++;
                    GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, compassSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2);
                    inputNodeList.Add(newNodeNEAT3);
                    currentBrainNodeID++;
                }
                List<AddonPositionSensor1D> positionSensor1DList = CheckForAddonPositionSensor1D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < positionSensor1DList.Count; j++) {
                    numInputs++;
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, positionSensor1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    inputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;
                }
                List<AddonPositionSensor3D> positionSensor3DList = CheckForAddonPositionSensor3D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < positionSensor3DList.Count; j++) {
                    numInputs++;
                    GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, positionSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    inputNodeList.Add(newNodeNEAT1);
                    currentBrainNodeID++;

                    numInputs++;
                    GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, positionSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1);
                    inputNodeList.Add(newNodeNEAT2);
                    currentBrainNodeID++;

                    numInputs++;
                    GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, positionSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2);
                    inputNodeList.Add(newNodeNEAT3);
                    currentBrainNodeID++;
                }
                List<AddonRotationSensor1D> rotationSensor1DList = CheckForAddonRotationSensor1D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < rotationSensor1DList.Count; j++) {
                    numInputs++;
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, rotationSensor1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    inputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;
                }
                List<AddonRotationSensor3D> rotationSensor3DList = CheckForAddonRotationSensor3D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < rotationSensor3DList.Count; j++) {
                    numInputs++;
                    GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, rotationSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    inputNodeList.Add(newNodeNEAT1);
                    currentBrainNodeID++;

                    numInputs++;
                    GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, rotationSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1);
                    inputNodeList.Add(newNodeNEAT2);
                    currentBrainNodeID++;

                    numInputs++;
                    GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, rotationSensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2);
                    inputNodeList.Add(newNodeNEAT3);
                    currentBrainNodeID++;
                }
                List<AddonVelocitySensor1D> velocitySensor1DList = CheckForAddonVelocitySensor1D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < velocitySensor1DList.Count; j++) {
                    numInputs++;
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, velocitySensor1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    inputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;
                }
                List<AddonVelocitySensor3D> velocitySensor3DList = CheckForAddonVelocitySensor3D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < velocitySensor3DList.Count; j++) {
                    numInputs++;
                    GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, velocitySensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    inputNodeList.Add(newNodeNEAT1);
                    currentBrainNodeID++;

                    numInputs++;
                    GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, velocitySensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1);
                    inputNodeList.Add(newNodeNEAT2);
                    currentBrainNodeID++;

                    numInputs++;
                    GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, velocitySensor3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2);
                    inputNodeList.Add(newNodeNEAT3);
                    currentBrainNodeID++;
                }
                List<AddonAltimeter> altimeterList = CheckForAddonAltimeter(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < altimeterList.Count; j++) {
                    numInputs++;
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, altimeterList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    inputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;
                }
                List<AddonEarBasic> earBasicList = CheckForAddonEarBasic(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < earBasicList.Count; j++) {
                    numInputs++;
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, earBasicList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    inputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;
                }
                List<AddonGravitySensor> gravitySensorList = CheckForAddonGravitySensor(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < gravitySensorList.Count; j++) {
                    numInputs++;
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, gravitySensorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    inputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;
                }
                List<AddonOscillatorInput> oscillatorInputList = CheckForAddonOscillatorInput(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < oscillatorInputList.Count; j++) {
                    numInputs++;
                    //Debug.Log("Oscillator: nodeIndex: " + currentBrainNodeID.ToString() + ", " + new Int3(oscillatorInputList[j].innov, currentBuildSegmentList[i].recursionNumber, 0).ToString());
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, oscillatorInputList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    inputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;                    
                }
                List<AddonValueInput> valueInputList = CheckForAddonValueInput(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < valueInputList.Count; j++) {
                    numInputs++;
                    //Debug.Log("Value: nodeIndex: " + currentBrainNodeID.ToString() + ", " + new Int3(valueInputList[j].innov, currentBuildSegmentList[i].recursionNumber, 0).ToString());
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, valueInputList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    inputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;                    
                }
                //Debug.Log(currentBuildSegmentList[i].sourceNode.ID.ToString() + " oscillatorInputList Count: " + oscillatorInputList.Count.ToString() + ", valueInputList Count: " + valueInputList.Count.ToString());
                List<AddonTimerInput> timerInputList = CheckForAddonTimerInput(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < timerInputList.Count; j++) {
                    numInputs++;
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.In, TransferFunctions.TransferFunction.Linear, timerInputList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    inputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;
                }                
                #endregion

                #region OUTPUTS:
                if (currentBuildSegmentList[i].sourceNode.ID != 0) {  // is NOT ROOT segment  -- Look into doing Root build BEFORE for loop to avoid the need to do this check
                    List<AddonJointMotor> jointMotorList = CheckForAddonJointMotor(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < jointMotorList.Count; j++) {
                        if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeX) {
                            numOutputs++;
                            GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, jointMotorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                            outputNodeList.Add(newNodeNEAT);
                            currentBrainNodeID++;
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeY) {
                            numOutputs++;
                            GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, jointMotorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                            outputNodeList.Add(newNodeNEAT);
                            currentBrainNodeID++;
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeZ) {
                            numOutputs++;
                            GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, jointMotorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                            outputNodeList.Add(newNodeNEAT);
                            currentBrainNodeID++;
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.DualXY) {
                            numOutputs++;
                            GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, jointMotorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                            outputNodeList.Add(newNodeNEAT1);
                            currentBrainNodeID++;

                            numOutputs++;
                            GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, jointMotorList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1);
                            outputNodeList.Add(newNodeNEAT2);
                            currentBrainNodeID++;
                        }
                    }
                    // %%%%%% DO I STILL NEED THIS SECTION???
                    // Check for if the segment currently being built is a Mirror COPY:
                    /*if (currentBuildSegmentList[i].isMirror) {
                        //Debug.Log("This is a MIRROR COPY segment - Wow!");
                        if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorX) {
                            // Invert the X-axis  (this will propagate down to all this segment's children
                            //newSegment.mirrorX = !newSegment.mirrorX;
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorY) {
                            //newSegment.mirrorY = !newSegment.mirrorY;
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.symmetryType == CritterJointLink.SymmetryType.MirrorZ) {
                            //newSegment.mirrorZ = !newSegment.mirrorZ;
                        }
                    }*/
                }

                List<AddonThrusterEffector1D> thrusterEffector1DList = CheckForAddonThrusterEffector1D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < thrusterEffector1DList.Count; j++) {
                    numOutputs++;
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, thrusterEffector1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    outputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;
                }
                List<AddonThrusterEffector3D> thrusterEffector3DList = CheckForAddonThrusterEffector3D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < thrusterEffector3DList.Count; j++) {
                    numOutputs++;
                    GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, thrusterEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    outputNodeList.Add(newNodeNEAT1);
                    currentBrainNodeID++;

                    numOutputs++;
                    GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, thrusterEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1);
                    outputNodeList.Add(newNodeNEAT2);
                    currentBrainNodeID++;

                    numOutputs++;
                    GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, thrusterEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2);
                    outputNodeList.Add(newNodeNEAT3);
                    currentBrainNodeID++;
                }
                List<AddonTorqueEffector1D> torqueEffector1DList = CheckForAddonTorqueEffector1D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < torqueEffector1DList.Count; j++) {
                    numOutputs++;
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, torqueEffector1DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    outputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;
                }
                List<AddonTorqueEffector3D> torqueEffector3DList = CheckForAddonTorqueEffector3D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < torqueEffector3DList.Count; j++) {
                    numOutputs++;
                    GeneNodeNEAT newNodeNEAT1 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, torqueEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    outputNodeList.Add(newNodeNEAT1);
                    currentBrainNodeID++;

                    numOutputs++;
                    GeneNodeNEAT newNodeNEAT2 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, torqueEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 1);
                    outputNodeList.Add(newNodeNEAT2);
                    currentBrainNodeID++;

                    numOutputs++;
                    GeneNodeNEAT newNodeNEAT3 = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, torqueEffector3DList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 2);
                    outputNodeList.Add(newNodeNEAT3);
                    currentBrainNodeID++;
                }
                List<AddonMouthBasic> mouthBasicList = CheckForAddonMouthBasic(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < mouthBasicList.Count; j++) {
                    // BLANK FOR NOW!!!
                }
                List<AddonNoiseMakerBasic> noiseMakerBasicList = CheckForAddonNoiseMakerBasic(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < noiseMakerBasicList.Count; j++) {
                    numOutputs++;
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, noiseMakerBasicList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    outputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;
                }
                List<AddonSticky> stickyList = CheckForAddonSticky(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < stickyList.Count; j++) {
                    numOutputs++;
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, stickyList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    outputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;
                }
                List<AddonWeaponBasic> weaponBasicList = CheckForAddonWeaponBasic(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < weaponBasicList.Count; j++) {
                    numOutputs++;
                    GeneNodeNEAT newNodeNEAT = new GeneNodeNEAT(currentBrainNodeID, GeneNodeNEAT.GeneNodeType.Out, TransferFunctions.TransferFunction.RationalSigmoid, weaponBasicList[j].innov, currentBuildSegmentList[i].recursionNumber, currentBuildSegmentList[i].isMirror, 0);
                    outputNodeList.Add(newNodeNEAT);
                    currentBrainNodeID++;
                }
                #endregion
                
                // CHECK FOR RECURSION:
                if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { // if the node being considered has recursions:
                    if (currentBuildSegmentList[i].recursionNumber < currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions) {
                        // if the current buildOrder's recursion number is less than the numRecursions there should be:
                        BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                        newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode;  // request a segment to be built again based on the current sourceNode
                        newSegmentInfo.recursionNumber = currentBuildSegmentList[i].recursionNumber + 1;  // increment num recursions
                        newSegmentInfo.isMirror = currentBuildSegmentList[i].isMirror;
                        nextBuildSegmentList.Add(newSegmentInfo);
                        //Debug.Log("newSegmentInfo recursion# " + newSegmentInfo.recursionNumber.ToString() + ", currentBuildList[i].recNum: " + currentBuildSegmentList[i].recursionNumber.ToString());
                        // If the node also has Symmetry:
                        if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                            // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                            BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                            newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode;  // uses same sourceNode, but tags as Mirror:
                            newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                            newSegmentInfoMirror.recursionNumber = newSegmentInfo.recursionNumber; //  !!!!!!!!!!!!! HIGHLY SUSPECT!!!!

                            nextBuildSegmentList.Add(newSegmentInfoMirror);
                        }
                    }
                    else {  // at the end of a recursion chain, so do not add any other pendingChild builds

                    }
                }
                // Figure out how many unique Child nodes this built node has:
                int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList.Count;
                //Debug.Log("numberOfChildNodes: " + numberOfChildNodes.ToString() + "currentBuildSegmentList[i].sourceNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + ", i: " + i.ToString());
                for (int c = 0; c < numberOfChildNodes; c++) {
                    // if NO symmetry:
                    // Check if Attaching to a recursion chain && if onlyattachToTail is active:
                    int childID = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList[c];

                    if (CritterNodeList[childID].jointLink.onlyAttachToTailNode) {
                        if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) {
                            if (currentBuildSegmentList[i].recursionNumber >= currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions) {
                                // Only build segment if it is on the end of a recursion chain:
                                BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                                newSegmentInfo.sourceNode = CritterNodeList[childID];
                                newSegmentInfo.isMirror = currentBuildSegmentList[i].isMirror;
                                //newSegmentInfo.parentSegment = newSegment;
                                nextBuildSegmentList.Add(newSegmentInfo);

                                if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                                    // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                                    BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                                    newSegmentInfoMirror.sourceNode = CritterNodeList[childID];
                                    newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                                    //newSegmentInfoMirror.parentSegment = newSegment;  // 
                                    nextBuildSegmentList.Add(newSegmentInfoMirror);
                                }
                            }
                        }
                        else {
                            // It only attaches to End nodes, but is parented to a Non-recursive segment, so proceed normally!!!
                            BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                            newSegmentInfo.sourceNode = CritterNodeList[childID];
                            newSegmentInfo.isMirror = currentBuildSegmentList[i].isMirror;
                            //newSegmentInfo.parentSegment = newSegment;
                            nextBuildSegmentList.Add(newSegmentInfo);

                            if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                                // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                                BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                                newSegmentInfoMirror.sourceNode = CritterNodeList[childID];
                                newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                                //newSegmentInfoMirror.parentSegment = newSegment;  // 
                                nextBuildSegmentList.Add(newSegmentInfoMirror);
                            }
                        }
                    }
                    else {  // proceed normally:
                        BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                        newSegmentInfo.sourceNode = CritterNodeList[childID];
                        newSegmentInfo.isMirror = currentBuildSegmentList[i].isMirror;
                        //newSegmentInfo.parentSegment = newSegment;
                        nextBuildSegmentList.Add(newSegmentInfo);

                        if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                            // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                            BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                            newSegmentInfoMirror.sourceNode = CritterNodeList[childID];
                            newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                            //newSegmentInfoMirror.parentSegment = newSegment;  // 
                            nextBuildSegmentList.Add(newSegmentInfoMirror);
                        }
                    }
                }
            }
            // After all buildNodes have been built, and their subsequent childNodes Enqueued, copy pendingChildQueue into buildNodesQueue
            currentBuildSegmentList.Clear();
            // SWAP LISTS:
            if (nextBuildSegmentList.Count > 0) {
                for (int j = 0; j < nextBuildSegmentList.Count; j++) {
                    currentBuildSegmentList.Add(nextBuildSegmentList[j]);
                }
                nextBuildSegmentList.Clear();  // empty this list for next depth-round
            }
            else {
                isPendingChildren = false;
            }
            if (currentDepth >= maxDepth) { // SAFEGUARD!! prevents infinite loop in case I mess something up
                isPendingChildren = false;
            }
            currentDepth++;
        }

        for(int i = 0; i < inputNodeList.Count; i++) {
            newNodeList.Add(inputNodeList[i]);
        }
        for (int i = 0; i < outputNodeList.Count; i++) {
            newNodeList.Add(outputNodeList[i]);
        }
        for (int i = 0; i < newNodeList.Count; i++) {
            newNodeList[i].id = i;  // Re-number nodes so that their list Index is always the same as their ID
        }

        return newNodeList;
    }
    public int[] CalculateNumberOfSegmentsInputsOutputs() {
        int numSegments = 0;
        int numInputs = 0;
        int numOutputs = 0;
        int[] retVal = new int[3];

        bool isPendingChildren = true;
        int currentDepth = 0; // start with RootNode
        int maxDepth = 20;  // safeguard to prevent while loop lock
        int nextSegmentID = 0;
        
        List<BuildSegmentInfo> currentBuildSegmentList = new List<BuildSegmentInfo>();  // keeps track of all current-depth segment build-requests, and holds important metadata
        List<BuildSegmentInfo> nextBuildSegmentList = new List<BuildSegmentInfo>();  // used to keep track of next childSegments that need to be built

        // ***********  Will attempt to traverse the Segments to be created, keeping track of where on each graph (nodes# & segment#) the current build is on.
        BuildSegmentInfo rootSegmentBuildInfo = new BuildSegmentInfo();
        rootSegmentBuildInfo.sourceNode = CritterNodeList[0];
        currentBuildSegmentList.Add(rootSegmentBuildInfo);  // ROOT NODE IS SPECIAL!
        
        // Do a Breadth-first traversal??
        while (isPendingChildren) {
            for (int i = 0; i < currentBuildSegmentList.Count; i++) { 
                numSegments++;
                nextSegmentID++;

                #region INPUTS
                // PhysAttrs would be here, but it has no inputs/outputs
                if (currentBuildSegmentList[i].sourceNode.ID != 0) {  // is NOT ROOT segment  -- Look into doing Root build BEFORE for loop to avoid the need to do this check                                                                      
                    List<AddonJointAngleSensor> jointAngleSensorList = CheckForAddonJointAngleSensor(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < jointAngleSensorList.Count; j++) {
                        // HINGE X X X X X
                        if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeX) {
                            if (jointAngleSensorList[j].measureVel[0]) {  // ALSO MEASURES ANGULAR VELOCITY:
                                numInputs = numInputs + 2;
                            }
                            else {  // Only Angle, no velocity:
                                numInputs++;
                            }
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeY) {
                            if (jointAngleSensorList[j].measureVel[0]) {
                                numInputs = numInputs + 2;
                            }
                            else {
                                numInputs++;
                            }
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeZ) {
                            if (jointAngleSensorList[j].measureVel[0]) {
                                numInputs = numInputs + 2;
                            }
                            else {
                                numInputs++;
                            }
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.DualXY) {
                            if (jointAngleSensorList[j].measureVel[0]) {
                                numInputs = numInputs + 4;
                            }
                            else {
                                numInputs = numInputs + 2;
                            }
                        }
                    }                    
                }
                List<AddonContactSensor> contactSensorList = CheckForAddonContactSensor(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < contactSensorList.Count; j++) {
                    numInputs++;
                }
                List<AddonRaycastSensor> raycastSensorList = CheckForAddonRaycastSensor(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < raycastSensorList.Count; j++) {
                    numInputs++;
                }
                List<AddonCompassSensor1D> compassSensor1DList = CheckForAddonCompassSensor1D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < compassSensor1DList.Count; j++) {
                    numInputs++;
                }
                List<AddonCompassSensor3D> compassSensor3DList = CheckForAddonCompassSensor3D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < compassSensor3DList.Count; j++) {
                    numInputs = numInputs + 3;
                }
                List<AddonPositionSensor1D> positionSensor1DList = CheckForAddonPositionSensor1D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < positionSensor1DList.Count; j++) {
                    numInputs++;
                }
                List<AddonPositionSensor3D> positionSensor3DList = CheckForAddonPositionSensor3D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < positionSensor3DList.Count; j++) {
                    numInputs = numInputs + 3;
                }
                List<AddonRotationSensor1D> rotationSensor1DList = CheckForAddonRotationSensor1D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < rotationSensor1DList.Count; j++) {
                    numInputs++;
                }
                List<AddonRotationSensor3D> rotationSensor3DList = CheckForAddonRotationSensor3D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < rotationSensor3DList.Count; j++) {
                    numInputs = numInputs + 3;
                }
                List<AddonVelocitySensor1D> velocitySensor1DList = CheckForAddonVelocitySensor1D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < velocitySensor1DList.Count; j++) {
                    numInputs++;
                }
                List<AddonVelocitySensor3D> velocitySensor3DList = CheckForAddonVelocitySensor3D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < velocitySensor3DList.Count; j++) {
                    numInputs = numInputs + 3;
                }
                List<AddonAltimeter> altimeterList = CheckForAddonAltimeter(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < altimeterList.Count; j++) {
                    numInputs++;
                }
                List<AddonEarBasic> earBasicList = CheckForAddonEarBasic(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < earBasicList.Count; j++) {
                    numInputs++;
                }
                List<AddonGravitySensor> gravitySensorList = CheckForAddonGravitySensor(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < gravitySensorList.Count; j++) {
                    numInputs++;
                }
                List<AddonOscillatorInput> oscillatorInputList = CheckForAddonOscillatorInput(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < oscillatorInputList.Count; j++) {
                    numInputs++;
                }
                List<AddonValueInput> valueInputList = CheckForAddonValueInput(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < valueInputList.Count; j++) {
                    numInputs++;
                }
                List<AddonTimerInput> timerInputList = CheckForAddonTimerInput(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < timerInputList.Count; j++) {
                    numInputs++;
                }
                #endregion

                #region OUTPUTS:
                if (currentBuildSegmentList[i].sourceNode.ID != 0) {  // is NOT ROOT segment  -- Look into doing Root build BEFORE for loop to avoid the need to do this check
                    List<AddonJointMotor> jointMotorList = CheckForAddonJointMotor(currentBuildSegmentList[i].sourceNode.ID);
                    for (int j = 0; j < jointMotorList.Count; j++) {
                        if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeX) {
                            numOutputs++;
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeY) {
                            numOutputs++;
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.HingeZ) {
                            numOutputs++;
                        }
                        else if (currentBuildSegmentList[i].sourceNode.jointLink.jointType == CritterJointLink.JointType.DualXY) {
                            numOutputs = numOutputs + 2;
                        }
                    }
                }
                List<AddonThrusterEffector1D> thrusterEffector1DList = CheckForAddonThrusterEffector1D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < thrusterEffector1DList.Count; j++) {
                    numOutputs++;
                }
                List<AddonThrusterEffector3D> thrusterEffector3DList = CheckForAddonThrusterEffector3D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < thrusterEffector3DList.Count; j++) {
                    numOutputs = numOutputs + 3;
                }
                List<AddonTorqueEffector1D> torqueEffector1DList = CheckForAddonTorqueEffector1D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < torqueEffector1DList.Count; j++) {
                    numOutputs++;
                }
                List<AddonTorqueEffector3D> torqueEffector3DList = CheckForAddonTorqueEffector3D(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < torqueEffector3DList.Count; j++) {
                    numOutputs = numOutputs + 3;
                }
                List<AddonMouthBasic> mouthBasicList = CheckForAddonMouthBasic(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < mouthBasicList.Count; j++) {
                    // BLANK FOR NOW!!!
                }
                List<AddonNoiseMakerBasic> noiseMakerBasicList = CheckForAddonNoiseMakerBasic(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < noiseMakerBasicList.Count; j++) {
                    numOutputs++;
                }
                List<AddonSticky> stickyList = CheckForAddonSticky(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < stickyList.Count; j++) {
                    numOutputs++;
                }
                List<AddonWeaponBasic> weaponBasicList = CheckForAddonWeaponBasic(currentBuildSegmentList[i].sourceNode.ID);
                for (int j = 0; j < weaponBasicList.Count; j++) {
                    numOutputs++;
                }
                #endregion
                
                
                // CHECK FOR RECURSION:
                if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) { // if the node being considered has recursions:
                    if(currentBuildSegmentList[i].recursionNumber < currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions) {
                        // if the current buildOrder's recursion number is less than the numRecursions there should be:
                        BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                        newSegmentInfo.sourceNode = currentBuildSegmentList[i].sourceNode;  // request a segment to be built again based on the current sourceNode
                        newSegmentInfo.recursionNumber = currentBuildSegmentList[i].recursionNumber + 1;  // increment num recursions
                        nextBuildSegmentList.Add(newSegmentInfo);
                        //Debug.Log("newSegmentInfo recursion# " + newSegmentInfo.recursionNumber.ToString() + ", currentBuildList[i].recNum: " + currentBuildSegmentList[i].recursionNumber.ToString());
                        // If the node also has Symmetry:
                        if (newSegmentInfo.sourceNode.jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                            // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                            BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                            newSegmentInfoMirror.sourceNode = currentBuildSegmentList[i].sourceNode;  // uses same sourceNode, but tags as Mirror:
                            newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                            newSegmentInfoMirror.recursionNumber = newSegmentInfo.recursionNumber; //  !!!!!!!!!!!!! HIGHLY SUSPECT!!!!
                            
                            nextBuildSegmentList.Add(newSegmentInfoMirror);
                        }
                    }
                    else {  // at the end of a recursion chain, so do not add any other pendingChild builds

                    }
                }
                // Figure out how many unique Child nodes this built node has:
                int numberOfChildNodes = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList.Count;
                //Debug.Log("numberOfChildNodes: " + numberOfChildNodes.ToString() + "currentBuildSegmentList[i].sourceNode: " + currentBuildSegmentList[i].sourceNode.ID.ToString() + ", i: " + i.ToString());
                for (int c = 0; c < numberOfChildNodes; c++) {
                    // if NO symmetry:
                    // Check if Attaching to a recursion chain && if onlyattachToTail is active:
                    int childID = currentBuildSegmentList[i].sourceNode.attachedChildNodesIdList[c];
                    
                    if (CritterNodeList[childID].jointLink.onlyAttachToTailNode) {
                        if (currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions > 0) {
                            if (currentBuildSegmentList[i].recursionNumber >= currentBuildSegmentList[i].sourceNode.jointLink.numberOfRecursions) {
                                // Only build segment if it is on the end of a recursion chain:
                                BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                                newSegmentInfo.sourceNode = CritterNodeList[childID];
                                //newSegmentInfo.parentSegment = newSegment;
                                nextBuildSegmentList.Add(newSegmentInfo);

                                if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                                    // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                                    BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                                    newSegmentInfoMirror.sourceNode = CritterNodeList[childID];
                                    newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                                    //newSegmentInfoMirror.parentSegment = newSegment;  // 
                                    nextBuildSegmentList.Add(newSegmentInfoMirror);
                                }
                            }
                        }
                        else {
                            // It only attaches to End nodes, but is parented to a Non-recursive segment, so proceed normally!!!
                            BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                            newSegmentInfo.sourceNode = CritterNodeList[childID];
                            //newSegmentInfo.parentSegment = newSegment;
                            nextBuildSegmentList.Add(newSegmentInfo);

                            if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                                // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                                BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                                newSegmentInfoMirror.sourceNode = CritterNodeList[childID];
                                newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                                //newSegmentInfoMirror.parentSegment = newSegment;  // 
                                nextBuildSegmentList.Add(newSegmentInfoMirror);
                            }
                        }
                    }
                    else {  // proceed normally:
                        BuildSegmentInfo newSegmentInfo = new BuildSegmentInfo();
                        newSegmentInfo.sourceNode = CritterNodeList[childID];
                        //newSegmentInfo.parentSegment = newSegment;
                        nextBuildSegmentList.Add(newSegmentInfo);

                        if (CritterNodeList[childID].jointLink.symmetryType != CritterJointLink.SymmetryType.None) {
                            // the child node has some type of symmetry, so add a buildOrder for a mirrored Segment:
                            BuildSegmentInfo newSegmentInfoMirror = new BuildSegmentInfo();
                            newSegmentInfoMirror.sourceNode = CritterNodeList[childID];
                            newSegmentInfoMirror.isMirror = true;  // This segment is the COPY, not the original
                            //newSegmentInfoMirror.parentSegment = newSegment;  // 
                            nextBuildSegmentList.Add(newSegmentInfoMirror);
                        }
                    }
                }
            }
            // After all buildNodes have been built, and their subsequent childNodes Enqueued, copy pendingChildQueue into buildNodesQueue
            currentBuildSegmentList.Clear();
            // SWAP LISTS:
            if (nextBuildSegmentList.Count > 0) {
                for (int j = 0; j < nextBuildSegmentList.Count; j++) {
                    currentBuildSegmentList.Add(nextBuildSegmentList[j]);
                }
                nextBuildSegmentList.Clear();  // empty this list for next depth-round
            }
            else {
                isPendingChildren = false;
            }
            if (currentDepth >= maxDepth) { // SAFEGUARD!! prevents infinite loop in case I mess something up
                isPendingChildren = false;
            }
            currentDepth++;
        }
        retVal[0] = numSegments;
        retVal[1] = numInputs;
        retVal[2] = numOutputs;
        return retVal;
    }