private Module GetRandomMatchingTile(ModuleConnector mainExit, bool deadendNeeded)
    {
        //module tags match at least one exittag and have an exit that matches the current module and modules that match deadendneeded
        Debug.Log("MainExit " + mainExit.tag + " of tile " + mainExit.transform.parent.name);
        var possibleModules = Modules.Where(e => e.hasTag(mainExit.tags) &&
                                            (e.tags & mainExit.tags) != TileTagsEnum.DeadEnd &&
                                            e.GetComponentsInChildren <ModuleConnector>().
                                            Where(d => d.hasTag(mainExit.GetComponentInParent <Module>().tags) && (d.tags & mainExit.GetComponentInParent <Module>().tags) != TileTagsEnum.DeadEnd).Count() > 0 &&
                                            e.hasTag(TileTagsEnum.DeadEnd) == deadendNeeded);

        if (possibleModules.Count() > 0)
        {
            return(Helper.GetRandom <Module>(possibleModules.ToArray()));
        }
        else
        {
            return(Helper.GetRandom <Module>(Modules.Where(e => e.hasTag(FALLBACK_TAG) && !e.hasTag(TileTagsEnum.DeadEnd)).ToArray()));
        }
    }
    //BUILD PATHS
    private void BuildMainPath()
    {
        while (mainPath.Count() < genParams.mainPathRooms)
        {
            if (LastCount == mainPath.Count())
            {
                timesSameIteration++;
            }
            else
            {
                timesSameIteration = 0;
            }

            if (timesSameIteration >= 5)
            {
                Backtrack(2);

                timesSameIteration = 0;
            }
            LastCount = mainPath.Count();

            var mainExits           = mainPath.Last().GetExits();
            var mainExitToMatch     = Helper.GetRandom(mainPath.Last().GetExits().Where(e => e.IsMatched() != true).ToArray());
            var newMainModulePrefab = GetRandomMatchingTile(mainExitToMatch, false);
            var newMainModule       = (Module)Instantiate(newMainModulePrefab);
            newMainModule.gameObject.name = CurrentRooms + "";
            var newModuleExitToMatch = GetRandomExitWithTag(newMainModule, mainExitToMatch.GetComponentInParent <Module>().tags);
            MatchExits(mainExitToMatch, newModuleExitToMatch);

            if (CollisionDetection(newMainModule, mainExitToMatch.GetComponentInParent <Module>()))
            {
                newMainModule.gameObject.SetActive(false);
                Debug.Log("Gameobject " + newMainModule.name + " disabled");
                Destroy(newMainModule.gameObject);
                newMainModule = null;
            }
            if (newMainModule != null)
            {
                mainExitToMatch.SetMatched(true);
                mainExitToMatch.setOtherSide(newModuleExitToMatch);
                newModuleExitToMatch.SetMatched(true);
                newModuleExitToMatch.setOtherSide(mainExitToMatch);
                mainPath.Add(newMainModule);
                newMainModule.transform.parent = moduleHolder.transform;
                pendingExits.AddRange(mainExits.Where(e => !e.IsMatched()));
                CurrentRooms++;
            }
        }

        var             endModulePrefab = Database.getEndRoom();
        var             endModule       = Instantiate(endModulePrefab);
        ModuleConnector finalMainExit   = null;

        try {
            finalMainExit = GetRandomExitWithTag(mainPath.Last(), endModule.tags);
        } catch (IndexOutOfRangeException e) {
            Debug.LogWarning(e);
            BuildBridgeForFinal(mainPath.Last());
            finalMainExit = GetRandomExitWithTag(mainPath.Last(), endModule.tags);
        }

        ModuleConnector finalExitToMatch = GetRandomExitWithTag(endModule, finalMainExit.GetComponentInParent <Module>().tags);

        MatchExits(finalMainExit, finalExitToMatch);

        endModule.gameObject.name = "Final";
        CurrentRooms++;
        mainPath.Add(endModule);

        if (CollisionDetection(endModule, finalMainExit.GetComponentInParent <Module>()))
        {
            Backtrack(3);
            BuildMainPath();
        }
        else
        {
            finalMainExit.SetMatched(true);
            finalMainExit.setOtherSide(finalExitToMatch);
            finalExitToMatch.SetMatched(true);
            finalExitToMatch.setOtherSide(finalMainExit);
            endModule.transform.parent = moduleHolder.transform;
            pendingExits.AddRange(finalMainExit.GetComponentInParent <Module>().GetExits().Where(e => e.IsMatched() != true));
            pendingExits.AddRange(endModule.GetExits().Where(e => e.IsMatched() != true));
        }
    }
    private bool FindMatchingModuleWithExits(int exits, ModuleConnector exitToMatch, Module otherModule)
    {
        List <Collider> colliderList = new List <Collider> {
            exitToMatch.GetComponentInParent <Module>().GetComponent <BoxCollider>()
        };

        foreach (ModuleConnector exit in otherModule.GetExits().Where(e => e.IsMatched() && e.getOtherSide() != null))
        {
            var exitOfModuleToMatch = exit.getOtherSide();
            colliderList.Add(exitOfModuleToMatch.
                             GetComponentInParent <Module>().
                             GetComponent <BoxCollider>());
        }
        otherModule.gameObject.SetActive(false);
        var possibleModules = Modules.Where(e => e.GetExits().Count() == exits);
        List <ModuleConnector> exitsToMatch = new List <ModuleConnector>();

        exitsToMatch.Add(exitToMatch);
        foreach (ModuleConnector exit in otherModule.GetExits().Where(e => e.IsMatched() && e.getOtherSide() != null))
        {
            exitsToMatch.Add(exit.getOtherSide());
        }
        for (int i = 0; i < possibleModules.Count(); i++)
        {
            int rotations = 0;

            Module testedModulePrefab = possibleModules.ElementAt(i);
            Module testedModule       = Instantiate(testedModulePrefab);
            while (rotations < 4)
            {
                Debug.Log("Testing Module " + testedModule.name + " at " + (90 * rotations) + "°");
                var exitsLeftToMatch = exitsToMatch;
                foreach (ModuleConnector testedModuleExit in testedModule.GetExits())
                {
                    exitsLeftToMatch = exitsLeftToMatch.Except(exitsLeftToMatch.Where(e => e.transform.forward == -testedModuleExit.transform.forward &&
                                                                                      e.hasTag(testedModule.tags) &&
                                                                                      (e.GetComponentInParent <Module>().tags & testedModuleExit.tags) != TileTagsEnum.DeadEnd &&
                                                                                      (e.tags & testedModule.tags) != TileTagsEnum.DeadEnd &&
                                                                                      testedModuleExit.hasTag(e.GetComponentInParent <Module>().tags))).ToList();
                }
                if (exitsLeftToMatch.Count() > 0)
                {
                    //Debug.Log(exitsLeftToMatch.Count());
                    exitsLeftToMatch = exitsToMatch;
                    testedModule.transform.Rotate(Vector3.up, 90);
                    rotations++;
                }
                else
                {
                    var testedModuleExits = testedModule.GetExits();

                    testedModule.gameObject.transform.position -=
                        (testedModule.GetExits().First().transform.position -
                         exitsToMatch.Where(e => e.transform.forward == -testedModuleExits.First().transform.forward).First().transform.position);
                    exitsToMatch.ForEach(e => e.SetMatched(true));
                    exitsToMatch.ForEach(e => e.setOtherSide(testedModuleExits.Where(d => - d.transform.forward == e.transform.forward).First()));
                    testedModuleExits.ToList().
                    ForEach(e => e.setOtherSide(
                                exitsToMatch.Where(d => - d.transform.forward == e.transform.forward)
                                .First()));
                    testedModuleExits.ToList().ForEach(e => e.SetMatched(true));
                    allModules.Add(testedModule);
                    if (mainPath.Contains(otherModule))
                    {
                        int index = mainPath.IndexOf(otherModule);
                        mainPath.Insert(index, testedModule);
                    }
                    testedModule.gameObject.name             = "Endroom " + CurrentRooms + "(" + otherModule.gameObject.name + ")";
                    testedModule.gameObject.transform.parent = moduleHolder.transform;
                    Debug.Log("Matching suceess: " + testedModule.gameObject.name);
                    return(true);
                }
            }
            Destroy(testedModule.gameObject);
        }
        return(false);
    }
    private void EndRoomCollisionHandling(Module newModule, ModuleConnector currentModuleConnector)
    {
        var newModuleCollider     = newModule.GetComponent <BoxCollider>();
        var currentModuleCollider = currentModuleConnector.GetComponentInParent <Module>().GetComponent <BoxCollider>();
        var possibleCollisions    = Physics.OverlapSphere(newModuleCollider.bounds.center, newModuleCollider.bounds.extents.magnitude);
        var relevantCollisions    = possibleCollisions.Where(e => e != newModuleCollider && e != currentModuleCollider && e.GetComponent <Module>() != null).ToList();
        int intersects            = 0;

        foreach (var collision in relevantCollisions)
        {
            if (newModuleCollider.bounds.Intersects(collision.bounds))
            {
                intersects++;
                Debug.Log("Relevante Collision für Tile " + newModule.name + ":" + collision.gameObject.name);
            }
        }
        Debug.Log("Relevante Collisions für Anschluss an Tile " + currentModuleConnector.transform.parent.name + ":" + intersects);
        if (intersects > 0)
        {
            var outDistance = 0f;
            //float maxDistance = newModuleCollider.bounds.size.z+currentModuleCollider.bounds.extents.z;
            //Debug.Log("MaxRayDistance for " + currentModuleCollider.name + ": " + maxDistance);
            var modulesInExitDirection = relevantCollisions.Where(e => e.bounds.
                                                                  IntersectRay(new Ray(currentModuleCollider.bounds.center, currentModuleConnector.transform.forward), out outDistance) &&
                                                                  outDistance <= 6 &&
                                                                  newModuleCollider.bounds.Intersects(e.bounds)).ToList();

            if (modulesInExitDirection.Count() > 0)
            {
                if (modulesInExitDirection.Count() > 1)
                {
                    Debug.Log("Need to sort raycast intersects");
                    var currentModuleConnectorPosition = currentModuleConnector.transform.position;

                    modulesInExitDirection.ForEach(e => Debug.Log("Intersected Module: " + e.transform.name +
                                                                  " ; Distance: " + (e.ClosestPoint(currentModuleConnectorPosition) - currentModuleConnectorPosition).magnitude));

                    modulesInExitDirection
                    .Sort((e1, e2) => (e1.ClosestPoint(currentModuleConnectorPosition) - currentModuleConnectorPosition).magnitude
                          .CompareTo((e2.ClosestPoint(currentModuleConnectorPosition) - currentModuleConnectorPosition).magnitude));
                }
                Module adjacentModule = modulesInExitDirection.First().GetComponentInParent <Module>();
                Debug.Log("Colliding Module to work with: " + adjacentModule.name);


                int exits = adjacentModule.GetExits().Where(e => e.IsMatched()).Count();
                newModule.gameObject.SetActive(false);
                Debug.Log("DeadEnd " + newModule.name + " disabled");
                Destroy(newModule.gameObject);
                bool exitsFit = checkIfExitsFitDirectly(currentModuleConnector, adjacentModule);
                bool matched  = false;

                Debug.Log("Exits to find: " + (exits + 1));
                if (!exitsFit && adjacentModule.tag != "immutable")
                {
                    matched = FindMatchingModuleWithExits(exits + 1, currentModuleConnector, adjacentModule);
                }
                Debug.Log("Endroommatching: " + (matched | exitsFit));
                if (matched)
                {
                    adjacentModule.gameObject.SetActive(false);
                    //Destroy(adjacentModule.gameObject);
                }
                else
                {
                    Debug.Log("No Match Case");
                    buildDeadendOutOfCurrentRoom(currentModuleConnector);
                    adjacentModule.gameObject.SetActive(true);
                }
            }
            else
            {
                Debug.Log("No Frontal Collision");
                newModule.transform.parent = moduleHolder.transform;
                allModules.Add(newModule);
                currentModuleConnector.SetMatched(true);
                var matchedExit = newModule.GetExits().First();
                currentModuleConnector.setOtherSide(matchedExit);
                matchedExit.SetMatched(true);
                matchedExit.setOtherSide(currentModuleConnector);
            }
        }
        else
        {
            Debug.Log("No Collision");
            newModule.transform.parent = moduleHolder.transform;
            allModules.Add(newModule);
            currentModuleConnector.SetMatched(true);
            var matchedExit = newModule.GetExits().First();
            currentModuleConnector.setOtherSide(matchedExit);
            matchedExit.SetMatched(true);
            matchedExit.setOtherSide(currentModuleConnector);
        }
        //currentModuleConnector.gameObject.SetActive(false);
        pendingExits.Remove(currentModuleConnector);
        CurrentRooms++;
    }