{"record":{"id":"73fdbd63a01b0eec","repo":"egametang/ET","slug":"map-copy-not-running-mapinfo-mapname-line1-l","errorCode":null,"errorMessage":"map copy not running: {mapInfo.MapName} {line1} {line2}","messagePattern":"map copy not running: (.+?) (.+?) (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"Packages/cn.etetet.mapmanager/Scripts/Hotfix/Server/MergeLinesComponentSystem.cs","lineNumber":77,"sourceCode":"                    break;\n                }\n            }\n        }\n        \n        // line2合并到line1\n        public static async ETTask MergeLines(this MergeLinesComponent self, long line1, long line2)\n        {\n            MapInfo mapInfo = self.GetParent<MapInfo>();\n            Log.Debug($\"start merge lines: {mapInfo.MapName} {line1} {line2}\");\n         \n            EntityRef<MapInfo> mapInfoRef = mapInfo;\n            MapCopy mapCopy1 = mapInfo.GetChild<MapCopy>(line1);\n            MapCopy mapCopy2 = mapInfo.GetChild<MapCopy>(line2);\n            EntityRef<MapCopy> mapCopy1Ref = mapCopy1;\n\n            if (mapCopy1.Status != MapCopyStatus.WaitMerge || mapCopy2.Status != MapCopyStatus.WaitMerge)\n            {\n                throw new Exception($\"map copy not running: {mapInfo.MapName} {line1} {line2}\");\n            }\n            \n            MessageLocationSenderComponent messageLocationSender = self.Root().GetComponent<MessageLocationSenderComponent>();\n            MessageLocationSenderOneType messageLocationSenderOneType = messageLocationSender.Get(LocationType.Unit);\n            EntityRef<MessageLocationSenderOneType> messageLocationSenderOneTypeRef = messageLocationSenderOneType;\n            // 通知传送\n            foreach (long playerId in mapCopy2.Players.ToArray())\n            {\n                MapManager2Map_NotifyPlayerTransferRequest request = MapManager2Map_NotifyPlayerTransferRequest.Create();\n                mapInfo = mapInfoRef;\n                mapCopy1 = mapCopy1Ref;\n                request.MapName = mapInfo.MapName;\n                request.MapId = mapCopy1.Id;\n                messageLocationSenderOneType = messageLocationSenderOneTypeRef;\n                await messageLocationSenderOneType.Call(playerId, request);\n\n                mapInfo = mapInfoRef;\n                Log.Debug($\"merge lines transfer: {mapInfo.MapName} transfer {playerId} to line {line1}\");","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/egametang/ET/blob/5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f/Packages/cn.etetet.mapmanager/Scripts/Hotfix/Server/MergeLinesComponentSystem.cs#L59-L95","documentation":"Thrown by MergeLinesComponent.MergeLines when either MapCopy line1 or line2 is not in MapCopyStatus.WaitMerge status. Line merging requires both copies to have been explicitly set to WaitMerge before the merge can proceed. If either copy is still Running, Finished, or in any other state, the merge is rejected.","triggerScenarios":"MergeLines(line1, line2) is called when mapCopy1.Status != WaitMerge or mapCopy2.Status != WaitMerge. This means one or both copies were not transitioned to WaitMerge before the merge was initiated.","commonSituations":"A copy was not properly set to WaitMerge status before requesting a merge (e.g. still Running). Race condition: the copy's status changed between the merge request and execution. The merge was triggered on the wrong pair of copies. A copy was already merged or disposed and its status was not updated.","solutions":["Ensure both MapCopy instances are set to MapCopyStatus.WaitMerge before calling MergeLines.","Check the status of both copies before calling MergeLines and log/skip if either is not ready.","Investigate why the copy's status is not WaitMerge — look at the lifecycle code that should set it."],"exampleFix":"// before\nif (mapCopy1.Status != MapCopyStatus.WaitMerge || mapCopy2.Status != MapCopyStatus.WaitMerge)\n    throw new Exception($\"map copy not running: {mapInfo.MapName} {line1} {line2}\");\n// after: guard and log\nif (mapCopy1.Status != MapCopyStatus.WaitMerge || mapCopy2.Status != MapCopyStatus.WaitMerge)\n{\n    Log.Error($\"merge skipped, copies not in WaitMerge: {line1}({mapCopy1.Status}) {line2}({mapCopy2.Status})\");\n    return;\n}","handlingStrategy":"validation","validationCode":"// Before calling MergeLines, verify both copies are in WaitMerge status\nMapCopy copy1 = mapInfo.GetChild<MapCopy>(line1);\nMapCopy copy2 = mapInfo.GetChild<MapCopy>(line2);\nif (copy1 == null || copy2 == null) { Log.Error(\"Merge target copy not found\"); return; }\nif (copy1.Status != MapCopyStatus.WaitMerge || copy2.Status != MapCopyStatus.WaitMerge)\n{\n    Log.Error($\"Cannot merge: line {line1} status={copy1.Status}, line {line2} status={copy2.Status}\");\n    return;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always transition both MapCopy instances to WaitMerge before requesting a merge.","Check status before calling MergeLines and log the actual states to aid debugging.","Guard against concurrent merge requests that could change a copy's status mid-operation."],"tags":["map","server","merge","state-contract"],"backgroundTag":null,"analyzedSha":"5cab01f7a8bee5f49f4781eebe9e2b1c6d7ebe0f","analyzedAt":"2026-08-13T21:10:40.377Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}