Пример #1
0
        public void DoImplementation(bool skipPO = false)
        {
            m_oldSelection = selection;

            Bounds bounds = GetTotalBounds(false);

            foreach (InstanceState state in m_states)
            {
                if (skipPO && state is ProcState)
                {
                    continue;
                }
                if (state is BuildingState)
                {
                    continue;
                }

                if (state.instance.isValid)
                {
                    state.instance.Delete();
                }
            }

            // Remove buildings last so attached nodes are cleaned up
            foreach (InstanceState state in m_states)
            {
                if (skipPO && state is ProcState)
                {
                    continue;
                }
                if (!(state is BuildingState))
                {
                    continue;
                }

                if (state.instance.isValid)
                {
                    state.instance.Delete();
                }
            }

            UpdateArea(bounds);

            selection = new HashSet <Instance>();
            MoveItTool.m_debugPanel.UpdatePanel();
            MoveItTool.UpdatePillarMap();
        }
Пример #2
0
        public override void Undo()
        {
            if (m_clones == null)
            {
                return;
            }

            Bounds bounds = GetTotalBounds(false);

            foreach (Instance instance in m_clones)
            {
                instance.Delete();
            }

            m_clones = null;

            // Restore selection
            selection = m_oldSelection;
            MoveItTool.m_debugPanel.UpdatePanel();

            UpdateArea(bounds);
            MoveItTool.UpdatePillarMap();
        }
Пример #3
0
        public override void Do()
        {
            if (MoveItTool.POProcessing > 0)
            {
                return;
            }

            MoveItTool.instance.m_lastInstance = null;
            m_clones                 = new HashSet <Instance>();
            m_origToCloneUpdate      = new Dictionary <Instance, Instance>();
            m_nodeOrigToClone        = new Dictionary <ushort, ushort>();
            m_stateToClone           = new Dictionary <InstanceState, Instance>();
            m_InstanceID_origToClone = new Dictionary <InstanceID, InstanceID>();

            matrix4x.SetTRS(center + moveDelta, Quaternion.AngleAxis(angleDelta * Mathf.Rad2Deg, Vector3.down), Vector3.one);

            // Clone nodes first
            foreach (InstanceState state in m_states)
            {
                if (state is NodeState)
                {
                    Instance clone = state.instance.Clone(state, ref matrix4x, moveDelta.y, angleDelta, center, followTerrain, m_nodeOrigToClone, this);

                    if (clone != null)
                    {
                        m_clones.Add(clone);
                        m_stateToClone.Add(state, clone);
                        m_InstanceID_origToClone.Add(state.instance.id, clone.id);
                        m_origToCloneUpdate.Add(state.instance.id, clone.id);
                        m_nodeOrigToClone.Add(state.instance.id.NetNode, clone.id.NetNode);
                    }
                }
            }

            // Clone everything else except PO
            foreach (InstanceState state in m_states)
            {
                if (!(state is NodeState || state is ProcState))
                {
                    Instance clone = state.instance.Clone(state, ref matrix4x, moveDelta.y, angleDelta, center, followTerrain, m_nodeOrigToClone, this);

                    if (clone == null)
                    {
                        Log.Debug($"Failed to clone {state}");
                        continue;
                    }

                    m_clones.Add(clone);
                    m_stateToClone.Add(state, clone);
                    m_InstanceID_origToClone.Add(state.instance.id, clone.id);
                    m_origToCloneUpdate.Add(state.instance.id, clone.id);
                    ;
                    if (state is SegmentState segmentState)
                    {
                        MoveItTool.NS.SetSegmentModifiers(clone.id.NetSegment, segmentState);
                        if (segmentState.LaneIDs != null)
                        {
                            // old version does not store lane ids
                            var clonedLaneIds = MoveableSegment.GetLaneIds(clone.id.NetSegment);
                            DebugUtils.AssertEq(clonedLaneIds.Count, segmentState.LaneIDs.Count, "clonedLaneIds.Count, segmentState.LaneIDs.Count");
                            for (int i = 0; i < clonedLaneIds.Count; ++i)
                            {
                                var lane0 = new InstanceID {
                                    NetLane = segmentState.LaneIDs[i]
                                };
                                var lane = new InstanceID {
                                    NetLane = clonedLaneIds[i]
                                };
                                // Log.Debug($"Mapping lane:{lane0.NetLane} to {lane.NetLane}");
                                m_InstanceID_origToClone.Add(lane0, lane);
                            }
                        }
                    }
                }
            }

            // Clone PO
            foreach (InstanceState state in m_states)
            {
                if (state is ProcState)
                {
                    _ = state.instance.Clone(state, ref matrix4x, moveDelta.y, angleDelta, center, followTerrain, m_nodeOrigToClone, this);
                }
            }

            if (m_origToClone != null)
            {
                Dictionary <Instance, Instance> toReplace = new Dictionary <Instance, Instance>();

                foreach (Instance key in m_origToClone.Keys)
                {
                    toReplace.Add(m_origToClone[key], m_origToCloneUpdate[key]);
                    DebugUtils.Log("To replace: " + m_origToClone[key].id.RawData + " -> " + m_origToCloneUpdate[key].id.RawData);
                }

                ActionQueue.instance.ReplaceInstancesForward(toReplace);
            }

            m_origToClone = m_origToCloneUpdate;

            // Select clones
            selection = m_clones;
            MoveItTool.m_debugPanel.UpdatePanel();

            UpdateArea(GetTotalBounds(false));
            try
            {
                MoveItTool.UpdatePillarMap();
            }
            catch (Exception e)
            {
                DebugUtils.Log("CloneActionBase.Do failed");
                DebugUtils.LogException(e);
            }
        }
Пример #4
0
        protected HashSet <InstanceState> ProcessPillars(HashSet <InstanceState> states, bool makeClone)
        {
            if (!MoveItTool.advancedPillarControl)
            {
                return(states);
            }

            HashSet <ushort> nodesWithAttachments = new HashSet <ushort>();

            var watch = new System.Diagnostics.Stopwatch();

            watch.Start();
            foreach (InstanceState instanceState in states)
            {
                if (instanceState is NodeState ns && ((NetNode)(ns.instance.data)).m_building > 0 &&
                    ((buildingBuffer[((NetNode)(ns.instance.data)).m_building].m_flags & Building.Flags.Hidden) != Building.Flags.Hidden))
                {
                    nodesWithAttachments.Add(ns.instance.id.NetNode);
                    //Debug.Log($"Node {ns.instance.id.NetNode} found");
                }
            }
            HashSet <InstanceState> newStates = new HashSet <InstanceState>(states);

            foreach (InstanceState instanceState in states)
            {
                ushort buildingId = instanceState.instance.id.Building;
                if (instanceState is BuildingState originalState && MoveItTool.m_pillarMap.ContainsKey(buildingId) && MoveItTool.m_pillarMap[buildingId] > 0)
                {
                    ushort nodeId = MoveItTool.m_pillarMap[buildingId];
                    if (nodesWithAttachments.Contains(nodeId)) // The node is also selected
                    {
                        //Debug.Log($"Pillar {buildingId} for selected node {nodeId}");
                        continue;
                    }
                    MoveableBuilding original = (MoveableBuilding)instanceState.instance;
                    buildingBuffer[buildingId].m_flags |= Building.Flags.Hidden;
                    selection.Remove(original);
                    newStates.Remove(originalState);
                    BuildingState cloneState = null;
                    if (makeClone)
                    {
                        MoveableBuilding clone = original.Duplicate();
                        selection.Add(clone);
                        cloneState = (BuildingState)clone.SaveToState();
                        newStates.Add(cloneState);
                        Debug.Log($"Pillar {buildingId} for node {nodeId} duplicated to {clone.id.Building}");
                    }
                    else
                    {
                        Debug.Log($"Pillar {buildingId} for node {nodeId} hidden");
                    }
                    pillarsOriginalToClone.Add(originalState, cloneState);
                    original.isHidden = true;
                }
            }
            if (pillarsOriginalToClone.Count > 0)
            {
                MoveItTool.UpdatePillarMap();
            }
            states = newStates;
            watch.Stop();
            Debug.Log($"Pillars handled in {watch.ElapsedMilliseconds} ms\nSelected nodes:{nodesWithAttachments.Count}, total selection:{states.Count}, dups mapped:{pillarsOriginalToClone.Count}");
            PillarsProcessed = true;

            return(states);
        }
Пример #5
0
        public void UndoImplementation(bool reset = false)
        {
            if (m_states == null)
            {
                return;
            }

            Dictionary <Instance, Instance> toReplace   = new Dictionary <Instance, Instance>();
            Dictionary <ushort, ushort>     clonedNodes = new Dictionary <ushort, ushort>();

            var stateToClone           = new Dictionary <InstanceState, Instance>();
            var InstanceID_origToClone = new Dictionary <InstanceID, InstanceID>();

            Building[] buildingBuffer = BuildingManager.instance.m_buildings.m_buffer;

            // Recreate nodes
            foreach (InstanceState state in m_states)
            {
                try
                {
                    if (state.instance.id.Type == InstanceType.NetNode)
                    {
                        Instance clone = state.instance.Clone(state, null);
                        toReplace.Add(state.instance, clone);
                        stateToClone.Add(state, clone);
                        InstanceID_origToClone.Add(state.instance.id, clone.id);
                        clonedNodes.Add(state.instance.id.NetNode, clone.id.NetNode);
                        ActionQueue.instance.UpdateNodeIdInStateHistory(state.instance.id.NetNode, clone.id.NetNode);
                    }
                }
                catch (Exception e)
                {
                    Debug.Log($"Undo Bulldoze failed on {(state is InstanceState ? state.prefabName : "unknown")}\n{e}");
                }
            }

            // Recreate everything except nodes and segments
            foreach (InstanceState state in m_states)
            {
                try
                {
                    if (state.instance.id.Type == InstanceType.NetNode)
                    {
                        continue;
                    }
                    if (state.instance.id.Type == InstanceType.NetSegment)
                    {
                        continue;
                    }
                    if (state is ProcState)
                    {
                        continue;
                    }

                    Instance clone = state.instance.Clone(state, clonedNodes);
                    toReplace.Add(state.instance, clone);
                    stateToClone.Add(state, clone);
                    InstanceID_origToClone.Add(state.instance.id, clone.id);

                    if (state.instance.id.Type == InstanceType.Prop)
                    {
                        PropManager.instance.m_props.m_buffer[clone.id.Prop].FixedHeight = ((PropState)state).fixedHeight;
                    }
                    else if (state.instance.id.Type == InstanceType.Building)
                    {
                        // Add attached nodes to the clonedNode list so other segments reconnect
                        BuildingState buildingState = state as BuildingState;
                        List <ushort> origNodeIds   = new List <ushort>();

                        MoveableBuilding cb          = clone as MoveableBuilding;
                        ushort           cloneNodeId = ((Building)cb.data).m_netNode;

                        if (reset)
                        {
                            ushort cloneId = cb.id.Building;

                            buildingBuffer[cloneId].m_flags = buildingBuffer[cloneId].m_flags & ~Building.Flags.BurnedDown;
                            buildingBuffer[cloneId].m_flags = buildingBuffer[cloneId].m_flags & ~Building.Flags.Collapsed;
                            buildingBuffer[cloneId].m_flags = buildingBuffer[cloneId].m_flags & ~Building.Flags.Abandoned;
                            buildingBuffer[cloneId].m_flags = buildingBuffer[cloneId].m_flags | Building.Flags.Active;
                            Thread.Sleep(50);
                        }

                        if (cloneNodeId != 0)
                        {
                            int c = 0;
                            foreach (InstanceState i in buildingState.subStates)
                            {
                                if (i is NodeState ns)
                                {
                                    InstanceID instanceID = default;
                                    instanceID.RawData = ns.id;
                                    origNodeIds.Insert(c++, instanceID.NetNode);
                                }
                            }

                            c = 0;
                            while (cloneNodeId != 0)
                            {
                                ushort origNodeId = origNodeIds[c];

                                NetNode clonedAttachedNode = Singleton <NetManager> .instance.m_nodes.m_buffer[cloneNodeId];
                                if (clonedAttachedNode.Info.GetAI() is TransportLineAI)
                                {
                                    cloneNodeId = clonedAttachedNode.m_nextBuildingNode;
                                    continue;
                                }

                                if (clonedNodes.ContainsKey(origNodeId))
                                {
                                    Debug.Log($"Node #{origNodeId} is already in clone list!");
                                }

                                clonedNodes.Add(origNodeId, cloneNodeId);

                                cloneNodeId = clonedAttachedNode.m_nextBuildingNode;

                                if (++c > 32768)
                                {
                                    CODebugBase <LogChannel> .Error(LogChannel.Core, "Nodes: Invalid list detected!\n" + Environment.StackTrace);

                                    break;
                                }
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    Debug.Log($"Undo Bulldoze failed on {(state is InstanceState ? state.prefabName : "unknown")}\n{e}");
                }
            }

            // Recreate segments
            foreach (InstanceState state in m_states)
            {
                try
                {
                    if (state is SegmentState segmentState)
                    {
                        if (!clonedNodes.ContainsKey(segmentState.startNodeId))
                        {
                            InstanceID instanceID = InstanceID.Empty;
                            instanceID.NetNode = segmentState.startNodeId;

                            // Don't clone if node is missing
                            if (!((Instance)instanceID).isValid)
                            {
                                continue;
                            }

                            clonedNodes.Add(segmentState.startNodeId, segmentState.startNodeId);
                        }

                        if (!clonedNodes.ContainsKey(segmentState.endNodeId))
                        {
                            InstanceID instanceID = InstanceID.Empty;
                            instanceID.NetNode = segmentState.endNodeId;

                            // Don't clone if node is missing
                            if (!((Instance)instanceID).isValid)
                            {
                                continue;
                            }

                            clonedNodes.Add(segmentState.endNodeId, segmentState.endNodeId);
                        }

                        Instance clone = state.instance.Clone(state, clonedNodes);
                        toReplace.Add(state.instance, clone);
                        stateToClone.Add(state, clone);
                        InstanceID_origToClone.Add(state.instance.id, clone.id);
                        MoveItTool.NS.SetSegmentModifiers(clone.id.NetSegment, segmentState);
                    }
                }
                catch (Exception e)
                {
                    Debug.Log($"Undo Bulldoze failed on {(state is InstanceState ? state.prefabName : "unknown")}\n{e}");
                }
            }

            // clone integrations.
            foreach (var item in stateToClone)
            {
                foreach (var data in item.Key.IntegrationData)
                {
                    try
                    {
                        data.Key.Paste(item.Value.id, data.Value, InstanceID_origToClone);
                    }
                    catch (Exception e)
                    {
                        InstanceID sourceInstanceID = item.Key.instance.id;
                        InstanceID targetInstanceID = item.Value.id;
                        Debug.LogError($"integration {data.Key} Failed to paste from " +
                                       $"{sourceInstanceID.Type}:{sourceInstanceID.Index} to {targetInstanceID.Type}:{targetInstanceID.Index}");
                        DebugUtils.LogException(e);
                    }
                }
            }

            if (replaceInstances)
            {
                ReplaceInstances(toReplace);
                ActionQueue.instance.ReplaceInstancesBackward(toReplace);

                selection = new HashSet <Instance>();
                foreach (Instance i in m_oldSelection)
                {
                    if (i is MoveableProc)
                    {
                        continue;
                    }
                    selection.Add(i);
                }
                MoveItTool.m_debugPanel.UpdatePanel();
            }

            // Does not check MoveItTool.advancedPillarControl, because even if disabled now advancedPillarControl may have been active earlier in action queue
            foreach (KeyValuePair <BuildingState, BuildingState> pillarClone in pillarsOriginalToClone)
            {
                BuildingState originalState = pillarClone.Key;
                originalState.instance.isHidden = false;
                buildingBuffer[originalState.instance.id.Building].m_flags &= ~Building.Flags.Hidden;
                selection.Add(originalState.instance);
                m_states.Add(originalState);
            }
            if (pillarsOriginalToClone.Count > 0)
            {
                MoveItTool.UpdatePillarMap();
            }
        }
Пример #6
0
        public override void Do()
        {
            if (MoveItTool.POProcessing > 0)
            {
                return;
            }

            MoveItTool.instance.m_lastInstance = null;
            m_clones            = new HashSet <Instance>();
            m_origToCloneUpdate = new Dictionary <Instance, Instance>();
            m_nodeOrigToClone   = new Dictionary <ushort, ushort>();
            var stateToClone           = new Dictionary <InstanceState, Instance>();
            var InstanceID_origToClone = new Dictionary <InstanceID, InstanceID>();

            matrix4x.SetTRS(center + moveDelta, Quaternion.AngleAxis(angleDelta * Mathf.Rad2Deg, Vector3.down), Vector3.one);

            // Clone nodes first
            foreach (InstanceState state in m_states)
            {
                if (state is NodeState)
                {
                    Instance clone = state.instance.Clone(state, ref matrix4x, moveDelta.y, angleDelta, center, followTerrain, m_nodeOrigToClone, this);

                    if (clone != null)
                    {
                        m_clones.Add(clone);
                        stateToClone.Add(state, clone);
                        InstanceID_origToClone.Add(state.instance.id, clone.id);
                        m_origToCloneUpdate.Add(state.instance.id, clone.id);
                        m_nodeOrigToClone.Add(state.instance.id.NetNode, clone.id.NetNode);
                    }
                }
            }

            // Clone everything else except PO
            foreach (InstanceState state in m_states)
            {
                if (!(state is NodeState || state is ProcState))
                {
                    Instance clone = state.instance.Clone(state, ref matrix4x, moveDelta.y, angleDelta, center, followTerrain, m_nodeOrigToClone, this);

                    if (clone == null)
                    {
                        Debug.Log($"Failed to clone {state}");
                        continue;
                    }

                    m_clones.Add(clone);
                    stateToClone.Add(state, clone);
                    InstanceID_origToClone.Add(state.instance.id, clone.id);
                    m_origToCloneUpdate.Add(state.instance.id, clone.id);
                    ;
                    if (state is SegmentState segmentState)
                    {
                        MoveItTool.NS.SetSegmentModifiers(clone.id.NetSegment, segmentState);
                        if (segmentState.LaneIDs != null)
                        {
                            // old version does not store lane ids
                            var clonedLaneIds = MoveableSegment.GetLaneIds(clone.id.NetSegment);
                            DebugUtils.AssertEq(clonedLaneIds.Count, segmentState.LaneIDs.Count, "clonedLaneIds.Count, segmentState.LaneIDs.Count");
                            for (int i = 0; i < clonedLaneIds.Count; ++i)
                            {
                                var lane0 = new InstanceID {
                                    NetLane = segmentState.LaneIDs[i]
                                };
                                var lane = new InstanceID {
                                    NetLane = clonedLaneIds[i]
                                };
                                // Debug.Log($"Mapping lane:{lane0.NetLane} to {lane.NetLane}");
                                InstanceID_origToClone.Add(lane0, lane);
                            }
                        }
                    }
                }
            }

            // backward compatibility.
            // Clone NodeController after segments have been added.
            foreach (var item in stateToClone)
            {
                if (item.Key is NodeState nodeState)
                {
                    Instance clone  = item.Value;
                    ushort   nodeID = clone.id.NetNode;
                    MoveItTool.NodeController.PasteNode(nodeID, nodeState);
                }
            }

            // Clone TMPE rules // TODO remove when TMPE switches to integration
            foreach (var state in m_states)
            {
                if (state is NodeState nodeState)
                {
                    MoveItTool.TMPE.Paste(nodeState.TMPE_NodeRecord, InstanceID_origToClone);
                }
                else if (state is SegmentState segmentState)
                {
                    MoveItTool.TMPE.Paste(segmentState.TMPE_SegmentRecord, InstanceID_origToClone);
                    MoveItTool.TMPE.Paste(segmentState.TMPE_SegmentStartRecord, InstanceID_origToClone);
                    MoveItTool.TMPE.Paste(segmentState.TMPE_SegmentEndRecord, InstanceID_origToClone);
                }
            }

            // Clone PO
            foreach (InstanceState state in m_states)
            {
                if (state is ProcState)
                {
                    _ = state.instance.Clone(state, ref matrix4x, moveDelta.y, angleDelta, center, followTerrain, m_nodeOrigToClone, this);
                }
            }

            // clone integrations.
            foreach (var item in stateToClone)
            {
                foreach (var data in item.Key.IntegrationData)
                {
                    try
                    {
                        data.Key.Paste(item.Value.id, data.Value, InstanceID_origToClone);
                    }
                    catch (Exception e)
                    {
                        InstanceID sourceInstanceID = item.Key.instance.id;
                        InstanceID targetInstanceID = item.Value.id;
                        Debug.LogError($"integration {data.Key} Failed to paste from " +
                                       $"{sourceInstanceID.Type}:{sourceInstanceID.Index} to {targetInstanceID.Type}:{targetInstanceID.Index}");
                        DebugUtils.LogException(e);
                    }
                }
            }

            if (m_origToClone != null)
            {
                Dictionary <Instance, Instance> toReplace = new Dictionary <Instance, Instance>();

                foreach (Instance key in m_origToClone.Keys)
                {
                    toReplace.Add(m_origToClone[key], m_origToCloneUpdate[key]);
                    DebugUtils.Log("To replace: " + m_origToClone[key].id.RawData + " -> " + m_origToCloneUpdate[key].id.RawData);
                }

                ActionQueue.instance.ReplaceInstancesForward(toReplace);
            }

            m_origToClone = m_origToCloneUpdate;

            // Select clones
            selection = m_clones;
            MoveItTool.m_debugPanel.UpdatePanel();

            UpdateArea(GetTotalBounds(false));
            MoveItTool.UpdatePillarMap();
        }