public void PlaceNewModularPiece(ModularPieceData Piece, Vector3 Scale, System.Func <ModularPlacableObject, bool> CanPlace, Vector3 RotationOffset = default(Vector3), Vector3 InitRotation = default(Vector3), Vector3 InitPosition = default(Vector3), object[] ExtraData = default(object[]), bool Interrupt = false)
        {
            ModularPlacableObject NewPlacableObject = (ModularPlacableObject)InitStoreItem(Piece, Scale, RotationOffset, InitRotation, InitPosition);

            PlaceModularPlacable(NewPlacableObject, (object[] data) => {
                // on object is placed
                ModularPiece PlacedPiece  = (ModularPiece)data.Find <ModularPiece>();                                                                  // get modular piece
                LocalGridSystem LocalGrid = (LocalGridSystem)data.Find <LocalGridSystem>();                                                            // get last local grid
                PlacePlacableObject.PlaceObjectCache Cache = (PlacePlacableObject.PlaceObjectCache)data.Find <PlacePlacableObject.PlaceObjectCache>(); // get last state cache
                PlacedPiece.InitializeEditable();                                                                                                      // initialize editable modular piece
                PlacedPiece.OnPlaced();                                                                                                                // call on placed callback

                // Economy
                int Price = GameManager.I.Economy.EvaluateModularPiece(Piece);
                GameManager.I.Economy.RemoveMoney(Price);
                GameManager.I.Economy.SpawnMoneyIndicator(PlacedPiece.transform.position, Price);

                // add piece to set
                GameManager.I.Modular.ScopedSet.AddModularPiece(PlacedPiece);

                // place new modular piece with last rotation
                PlaceNewModularPiece(Piece, Scale, CanPlace, PlacedPiece.RotationOffset.eulerAngles, PlacedPiece.NoneOffsettedRotation.eulerAngles, PlacedPiece.transform.position, new object[] { LocalGrid, Cache });
            }, CanPlace, (Data) => {
                // on canceled
                GameManager.I.Modular.ScopedSet.DeregisterPlacingObject(); // de register object
                ModularPlacableObject PlacableObject = (ModularPlacableObject)Data.Find <ModularPlacableObject>();
                PlacableObject.Destroy();                                  // destroy on cancle

                Statemachine.changeState(new ModularSpectate(), this);
            }, SnapTypes.Default, ExtraData, Interrupt);                              // place new created store modular piece
            GameManager.I.Modular.ScopedSet.RegisterPlacingObject(NewPlacableObject); // register new placable object to be placed inside building
        }
        public ModularPiece InitStoreItem(ModularPieceSaveData PieceSaveData)
        {
            ModularPieceData PieceData = GameManager.I.Modular.FindPiece(PieceSaveData.ID);             // find modular piece

            if (PieceData != null)
            {
                ModularPiece piece = InitStoreItem(PieceData, PieceSaveData.LocalScale, Vector3.zero, PieceSaveData.LocalEulerAngles, PieceSaveData.LocalPosition);
                piece.InitializeTextureData(PieceSaveData.TextureDataKeys);
                piece.InitializeColors(PieceSaveData.Colors);                  // initialize colors
                return(piece);
            }
            return(null);
        }
        public bool StrokeModularPlacable(ModularPieceData PieceData, System.Action <ModularPlacableObject> OnDeleted, System.Action <ModularPlacableObject> OnPlaced, System.Action <object[]> OnCancel, System.Func <StrokeType, ModularPlacableObject> InfoGetter, System.Func <StrokeType, ModularPlacableObject> InstanceGetter, System.Func <int, bool> CanPlace)
        {
            List <object> GenData = new List <object> ();

            GenData.Add(this);
            GenData.Add(OnCancel);
            GenData.Add(new System.Func <StrokeType, ModularPlacableObject>[] {
                InfoGetter,
                InstanceGetter
            });
            GenData.Add(CanPlace);
            GenData.Add(new System.Action <ModularPlacableObject>[] {
                OnPlaced,
                OnDeleted
            });
            GenData.Add(GameManager.I.Modular.FindStrokeSet(PieceData.Key));

            Statemachine.changeState(new StrokePlacableObject(), GenData);             // change to stroke placable object
            return(true);
        }
        public ModularPiece InitStoreItem(ModularPieceData Piece, Vector3 Scale, Vector3 RotationOffset = default(Vector3), Vector3 InitRotation = default(Vector3), Vector3 InitPosition = default(Vector3))
        {
            if (Piece != null)
            {
                GameObject obj = Piece.Prefab;                 // pick base object

                // instantiate item
                ModularPiece piece = GameObject.Instantiate(obj, InitPosition, Quaternion.identity).GetComponent <ModularPiece> ();
                piece.gameObject.name = Piece.Name;
                piece.InitializeID(Piece.Key);
                piece.InitializeTextureData();
                piece.InitializeColors();
                piece.transform.localScale    = Scale;
                piece.transform.localPosition = InitPosition;
                piece.NoneOffsettedRotation   = Quaternion.Euler(InitRotation);     // set rotation with rotation property
                piece.RotationOffset          = Quaternion.Euler(RotationOffset);   // set rotation offset
                piece.Initialize(GameManager.I.Modular.ScopedSet);                  // initialize piece data
                return(piece);
            }
            return(null);
        }
        }         // core function for init modular set

        public bool StrokeModularPlacable(ModularPieceData PieceData, System.Action <ModularPlacableObject> OnPlaced, System.Func <int, bool> CanPlace)
        {
            if (PieceData != null)
            {
                // init new modular set
                GameManager.I.Modular.ScopedSet = InitNewModularSet();
                GameManager.I.Modular.ScopedSet.InitializeEditable();

                // place
                HashSet <ModularSet> AffectedSets = new HashSet <ModularSet> ();
                if (PieceData.Prefab != null && PieceData.Prefab.GetComponent <StrokeModularPiece> () != null)
                {
                    StrokeModularPiece   StrokePiece = PieceData.Prefab.GetComponent <StrokeModularPiece> (); // get stroke piece from prefab
                    ModularStrokeSetData StrokeSet   = GameManager.I.Modular.FindStrokeSet(PieceData.Key);
                    if (StrokeSet != null)                                                                    // if there is found a strokeset
                    {
                        return(StrokeModularPlacable(PieceData, (ModularPlacableObject Placable) => {         // on deleted
                            if (typeof(ModularPiece).IsAssignableFrom(Placable.GetType()))
                            {
                                ModularPiece Piece = (ModularPiece)Placable;
                                ModularSet ParentSet = Piece.ParentSet;
                                if (ParentSet != null)
                                {
                                    bool NotDestoryed = ParentSet.RemoveModularPiece(Piece);                   // remove piece from set
                                    if (!AffectedSets.Contains(ParentSet))                                     // add set to affected sets
                                    {
                                        AffectedSets.Add(ParentSet);
                                    }
                                    else if (!NotDestoryed)
                                    {
                                        AffectedSets.Remove(ParentSet);
                                    }
                                }
                            }
                        }, OnPlaced, (object[] Data) => {                     // on cancel
                            if (!AffectedSets.Contains(GameManager.I.Modular.ScopedSet))
                            {
                                AffectedSets.Add(GameManager.I.Modular.ScopedSet);
                            }
                            foreach (ModularSet Set in AffectedSets)
                            {
                                Set.FinalizeSet(Management.GameManager.I.Modular.ModularPieceLayer);
                            }                            // Update render sets of affected modular sets
                            Statemachine.changeState(new ModularSpectate(), this);
                        }, (StrokeType Type) => {        // return information
                            return StrokeSet.FindStrokePieceComponent(Type);
                        }, (StrokeType Type) => {        // return new instance
                            ModularPieceData Piece = StrokeSet.FindPiece(Type);
                            if (Piece == null)
                            {
                                Piece = PieceData;
                            }
                            var Object = InitStoreItem(Piece, Vector3.one);
                            Object.InitializeEditable();
                            GameManager.I.Modular.ScopedSet.AddModularPiece(Object);                             // add piece to set
                            return Object;
                        }, CanPlace));
                    }
                }
            }
            return(false);
        }