From 0c450b24ed1c36a9047a30cb6f45d063395c6a1f Mon Sep 17 00:00:00 2001
From: Andrei <amborn02@gmail.com>
Date: Sat, 8 Feb 2025 15:07:21 -0600
Subject: [PATCH] Teleport modal restored, and expanded undo/redo to include
 all placed and erase edits across each map element type (map object advanced
 actions WIP)

---
 src/components/gameMaster/mapEditor/Map.vue   | 115 ++++++++++++--
 .../mapEditor/mapPartials/MapEventTiles.vue   |  64 +++++++-
 .../mapEditor/mapPartials/MapTiles.vue        | 145 ++++++------------
 .../mapPartials/PlacedMapObjects.vue          |  25 ++-
 .../gameMaster/mapEditor/partials/Toolbar.vue |   1 +
 src/components/screens/MapEditor.vue          |  12 +-
 src/services/mapService.ts                    |   5 +
 7 files changed, 244 insertions(+), 123 deletions(-)

diff --git a/src/components/gameMaster/mapEditor/Map.vue b/src/components/gameMaster/mapEditor/Map.vue
index 2a926ae..7acceb7 100644
--- a/src/components/gameMaster/mapEditor/Map.vue
+++ b/src/components/gameMaster/mapEditor/Map.vue
@@ -1,30 +1,109 @@
 <template>
-  <MapTiles ref="mapTiles" v-if="tileMap && tileMapLayer" :tileMap :tileMapLayer />
-  <PlacedMapObjects ref="mapObjects" v-if="tileMap && tileMapLayer" :tileMap :tileMapLayer />
-  <MapEventTiles ref="eventTiles" v-if="tileMap" :tileMap />
+  <MapTiles ref="mapTiles" @createCommand="addCommand" v-if="tileMap && tileMapLayer" :tileMap :tileMapLayer />
+  <PlacedMapObjects ref="mapObjects" @createCommand="addCommand" v-if="tileMap && tileMapLayer" :tileMap :tileMapLayer />
+  <MapEventTiles ref="eventTiles" @createCommand="addCommand" v-if="tileMap" :tileMap />
 </template>
 
 <script setup lang="ts">
+
 import MapEventTiles from '@/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue'
 import MapTiles from '@/components/gameMaster/mapEditor/mapPartials/MapTiles.vue'
 import PlacedMapObjects from '@/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue'
 import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
-import { createTileLayer, createTileMap } from '@/services/mapService'
+import { cloneArray, createTileLayer, createTileMap, placeTiles } from '@/services/mapService'
 import { TileStorage } from '@/storage/storages'
 import { useScene } from 'phavuer'
-import { onBeforeUnmount, onMounted, onUnmounted, shallowRef, useTemplateRef } from 'vue'
+
+import { onBeforeUnmount, onMounted, onUnmounted, ref, shallowRef, useTemplateRef, watch } from 'vue'
+import type { MapEventTile, PlacedMapObject as PlacedMapObjectT } from '@/application/types'
 
 const tileMap = shallowRef<Phaser.Tilemaps.Tilemap>()
 const tileMapLayer = shallowRef<Phaser.Tilemaps.TilemapLayer>()
 
 const mapEditor = useMapEditorComposable()
-
 const scene = useScene()
 
 const mapTiles = useTemplateRef('mapTiles')
 const mapObjects = useTemplateRef('mapObjects')
 const eventTiles = useTemplateRef('eventTiles')
 
+//Record of commands
+let commandStack: EditorCommand[] = []
+let commandIndex = ref(0)
+
+let originTiles: string[][] = []
+let originEventTiles: MapEventTile[] = []
+let originObjects: PlacedMapObjectT[] = []
+
+//Command Pattern basic interface, extended to store what elements have been changed by each edit
+export interface EditorCommand {
+  apply: (elements: any[]) => any[]
+  type: 'tile' | 'map_object' | 'event_tile'
+  operation: 'draw' | 'erase' | 'place' | 'move' | 'delete' | 'rotate'
+}
+
+function applyCommands(tiles: any[], ...commands: EditorCommand[]): any[] {
+  let tileVersion = cloneArray(tiles)
+  for (let command of commands) {
+    tileVersion = command.apply(tileVersion)
+  }
+  return tileVersion
+}
+
+watch(() => commandIndex.value!, (val) => {
+  if (val !== undefined) {
+    update(commandStack.slice(0, val))
+  }
+})
+
+function update(commands: EditorCommand[]) {
+  if (!mapEditor.currentMap.value) return
+
+  const tileCommands = commands.filter((command) => command.type === 'tile')
+  const eventTileCommands = commands.filter((command) => command.type === 'event_tile')
+  const objectCommands = commands.filter((command) => command.type === 'map_object')
+
+  let modifiedTiles = applyCommands(originTiles, ...tileCommands)
+  placeTiles(tileMap.value!, tileMapLayer.value!, modifiedTiles)
+
+  mapEditor.currentMap.value.tiles = modifiedTiles
+  mapEditor.currentMap.value.mapEventTiles = applyCommands(originEventTiles, ...eventTileCommands)
+  mapEditor.currentMap.value.placedMapObjects = applyCommands(originObjects, ...objectCommands)
+}
+
+function addCommand(command: EditorCommand) {
+  commandStack = commandStack.slice(0, commandIndex.value)
+  commandStack.push(command)
+
+  if (commandStack.length >= 9) {
+    switch (commandStack[0].type) {
+      case 'tile':
+        originTiles = commandStack.shift()?.apply(originTiles) as string[][]
+        break
+      case 'map_object':
+        originObjects = commandStack.shift()?.apply(originObjects) as PlacedMapObjectT[]
+        break
+      case 'event_tile':
+        originEventTiles = commandStack.shift()?.apply(originEventTiles) as MapEventTile[]
+        break
+    }
+  }
+
+  commandIndex.value = commandStack.length
+}
+
+function undo() {
+  if (commandIndex.value > 0) {
+    commandIndex.value--
+  }
+}
+
+function redo() {
+  if (commandIndex.value <= 9 && commandIndex.value <= commandStack.length) {
+    commandIndex.value++
+  }
+}
+
 function handlePointerDown(pointer: Phaser.Input.Pointer) {
   if (!mapTiles.value || !mapObjects.value || !eventTiles.value) return
 
@@ -54,12 +133,12 @@ function handlePointerDown(pointer: Phaser.Input.Pointer) {
 function handleKeyDown(event: KeyboardEvent) {
   //CTRL+Y
   if (event.key === 'y' && event.ctrlKey) {
-    mapTiles.value!.redo()
+    redo()
   }
 
   //CTRL+Z
   if (event.key === 'z' && event.ctrlKey) {
-    mapTiles.value!.undo()
+    undo()
   }
 }
 
@@ -70,8 +149,19 @@ function handlePointerMove(pointer: Phaser.Input.Pointer) {
 }
 
 function handlePointerUp(pointer: Phaser.Input.Pointer) {
-  if (mapEditor.drawMode.value === 'tile') {
-    mapTiles.value?.finalizeCommand()
+  switch(mapEditor.drawMode.value) {
+    case 'tile':
+      mapTiles.value!.finalizeCommand()
+      break
+    case 'map_object':
+      mapObjects.value!.finalizeCommand()
+      break
+    case 'teleport':
+      eventTiles.value!.finalizeCommand()
+      break
+    case 'blocking tile':
+      eventTiles.value!.finalizeCommand()
+      break
   }
 }
 
@@ -79,6 +169,11 @@ onMounted(async () => {
   let mapValue = mapEditor.currentMap.value
   if (!mapValue) return
 
+  //Clone
+  originTiles = cloneArray(mapValue.tiles)
+  originObjects = cloneArray(mapValue.placedMapObjects)
+  originEventTiles = cloneArray(mapValue.mapEventTiles)
+
   const tileStorage = new TileStorage()
   const allTiles = await tileStorage.getAll()
   const allTileIds = allTiles.map((tile) => tile.id)
diff --git a/src/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue b/src/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue
index 40fdac3..4dc7812 100644
--- a/src/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue
+++ b/src/components/gameMaster/mapEditor/mapPartials/MapEventTiles.vue
@@ -3,22 +3,72 @@
 </template>
 
 <script setup lang="ts">
+
 import { MapEventTileType, type MapEventTile, type Map as MapT, type UUID } from '@/application/types'
 import { uuidv4 } from '@/application/utilities'
 import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
-import { getTile, tileToWorldX, tileToWorldY } from '@/services/mapService'
+import { cloneArray, getTile, tileToWorldX, tileToWorldY } from '@/services/mapService'
 import { Image } from 'phavuer'
-import { shallowRef } from 'vue'
+import { type EditorCommand } from '@/components/gameMaster/mapEditor/Map.vue'
 
 const mapEditor = useMapEditorComposable()
 
-defineExpose({ handlePointer })
+defineExpose({ handlePointer, finalizeCommand })
+
+const emit = defineEmits(['createCommand'])
 
 const props = defineProps<{
   tileMap: Phaser.Tilemaps.Tilemap
 }>()
 
-const tileLayer = shallowRef<Phaser.Tilemaps.TilemapLayer>()
+
+// *** COMMAND STATE ***
+
+let currentCommand: EventTileCommand | null = null
+
+class EventTileCommand implements EditorCommand {
+  public operation: 'draw' | 'erase' = 'draw'
+  public type: 'event_tile' = 'event_tile'
+  public affectedTiles: MapEventTile[] = []
+
+  apply(elements: MapEventTile[]) {
+    let tileVersion = cloneArray(elements) as MapEventTile[]
+    if (this.operation === 'draw') {
+      tileVersion = tileVersion.concat(this.affectedTiles)
+    }
+    else if (this.operation === 'erase') {
+      tileVersion = tileVersion.filter((v) => !this.affectedTiles.includes(v))
+    }
+    return tileVersion
+  }
+
+  constructor(operation: 'draw' | 'erase') {
+    this.operation = operation
+  }
+}
+
+function createCommandUpdate(tile: MapEventTile, operation: 'draw' | 'erase') {
+  if (!currentCommand) {
+    currentCommand = new EventTileCommand(operation)
+  }
+
+  //If position is already in, do not proceed
+  for (const priorTile of currentCommand.affectedTiles) {
+    if (priorTile.positionX === tile.positionX && priorTile.positionY == tile.positionY) return
+  }
+
+  currentCommand.affectedTiles.push(tile)
+}
+
+function finalizeCommand() {
+  if (!currentCommand) return
+  emit('createCommand', currentCommand)
+  currentCommand = null
+}
+
+
+// *** HANDLERS ***
+
 
 function getImageProps(tile: MapEventTile) {
   return {
@@ -44,7 +94,7 @@ function pencil(pointer: Phaser.Input.Pointer, map: MapT) {
   const newEventTile = {
     id: uuidv4() as UUID,
     mapId: map.id,
-    map: map.id,
+    map: map,
     type: mapEditor.drawMode.value === 'blocking tile' ? MapEventTileType.BLOCK : MapEventTileType.TELEPORT,
     positionX: tile.x,
     positionY: tile.y,
@@ -59,6 +109,8 @@ function pencil(pointer: Phaser.Input.Pointer, map: MapT) {
         : undefined
   }
 
+  createCommandUpdate(newEventTile, 'draw')
+
   map.mapEventTiles.push(newEventTile)
 }
 
@@ -77,6 +129,8 @@ function erase(pointer: Phaser.Input.Pointer, map: MapT) {
     else return
   }
 
+  createCommandUpdate(existingEventTile, 'erase')
+
   // Remove existing event tile
   map.mapEventTiles = map.mapEventTiles.filter((eventTile) => eventTile.id !== existingEventTile.id)
 }
diff --git a/src/components/gameMaster/mapEditor/mapPartials/MapTiles.vue b/src/components/gameMaster/mapEditor/mapPartials/MapTiles.vue
index 755b3ef..671e8b0 100644
--- a/src/components/gameMaster/mapEditor/mapPartials/MapTiles.vue
+++ b/src/components/gameMaster/mapEditor/mapPartials/MapTiles.vue
@@ -5,57 +5,70 @@
 <script setup lang="ts">
 import Controls from '@/components/utilities/Controls.vue'
 import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
-import { createTileArray, getTile, placeTile, placeTiles } from '@/services/mapService'
+import { cloneArray, createTileArray, getTile, placeTile, placeTiles } from '@/services/mapService'
 import { onMounted, ref, watch } from 'vue'
+import { type EditorCommand } from '@/components/gameMaster/mapEditor/Map.vue'
 
 const mapEditor = useMapEditorComposable()
 
-defineExpose({ handlePointer, finalizeCommand, undo, redo })
+defineExpose({ handlePointer, finalizeCommand })
+
+const emit = defineEmits(['createCommand'])
 
 const props = defineProps<{
   tileMap: Phaser.Tilemaps.Tilemap
   tileMapLayer: Phaser.Tilemaps.TilemapLayer
 }>()
 
-class EditorCommand {
+
+// *** COMMAND STATE ***
+
+let currentCommand: TileCommand | null = null
+
+class TileCommand implements EditorCommand {
   public operation: 'draw' | 'erase' = 'draw'
+  public type: 'tile' = 'tile'
   public tileName: string = 'blank_tile'
-  public affectedTiles: number[][]
+  public affectedTiles: number[][] = []
+
+  apply(elements: string[][]) {
+    let tileVersion = cloneArray(elements) as string[][]
+    for (const position of this.affectedTiles) {
+      tileVersion[position[1]][position[0]] = this.tileName
+    }
+    return tileVersion
+  }
 
   constructor(operation: 'draw' | 'erase', tileName: string) {
     this.operation = operation
     this.tileName = tileName
-    this.affectedTiles = []
   }
 }
 
-//Record of commands
-let commandStack: EditorCommand[] = []
-let currentCommand: EditorCommand | null = null
-let commandIndex = ref(0)
-let originTiles: string[][] = []
+function createCommandUpdate(x: number, y: number, tileName: string, operation: 'draw' | 'erase') {
+  if (!currentCommand) {
+    currentCommand = new TileCommand(operation, tileName)
+  }
 
-function pencil(pointer: Phaser.Input.Pointer) {
-  let map = mapEditor.currentMap.value
-  if (!map) return
+  //If position is already in, do not proceed
+  for (const vec of currentCommand.affectedTiles) {
+    if (vec[0] === x && vec[1] === y) return
+  }
 
-  // Check if there is a selected tile
-  if (!mapEditor.selectedTile.value) return
-
-  // Check if there is a tile
-  const tile = getTile(props.tileMapLayer, pointer.worldX, pointer.worldY)
-  if (!tile) return
-
-  // Place tile
-  placeTile(props.tileMap, props.tileMapLayer, tile.x, tile.y, mapEditor.selectedTile.value)
-
-  createCommandUpdate(tile.x, tile.y, mapEditor.selectedTile.value, 'draw')
-
-  // Adjust mapEditorStore.map.tiles
-  map.tiles[tile.y][tile.x] = mapEditor.selectedTile.value
+  currentCommand.affectedTiles.push([x, y])
 }
 
-function eraser(pointer: Phaser.Input.Pointer) {
+function finalizeCommand() {
+  if (!currentCommand) return
+  emit('createCommand', currentCommand)
+  currentCommand = null
+}
+
+
+// *** HANDLERS ***
+
+
+function draw(pointer: Phaser.Input.Pointer, tileName: string) {
   let map = mapEditor.currentMap.value
   if (!map) return
 
@@ -64,12 +77,12 @@ function eraser(pointer: Phaser.Input.Pointer) {
   if (!tile) return
 
   // Place tile
-  placeTile(props.tileMap, props.tileMapLayer, tile.x, tile.y, 'blank_tile')
+  placeTile(props.tileMap, props.tileMapLayer, tile.x, tile.y, tileName)
 
-  createCommandUpdate(tile.x, tile.y, 'blank_tile', 'erase')
+  createCommandUpdate(tile.x, tile.y, tileName, tileName === 'blank_tile' ? 'erase': 'draw')
 
   // Adjust mapEditorStore.map.tiles
-  map.tiles[tile.y][tile.x] = 'blank_tile'
+  map.tiles[tile.y][tile.x] = tileName
 }
 
 function paint(pointer: Phaser.Input.Pointer) {
@@ -113,10 +126,10 @@ function handlePointer(pointer: Phaser.Input.Pointer) {
   // Check if draw mode is tile
   switch (mapEditor.tool.value) {
     case 'pencil':
-      pencil(pointer)
+      draw(pointer, mapEditor.selectedTile.value!)
       break
     case 'eraser':
-      eraser(pointer)
+      draw(pointer, 'blank_tile')
       break
     case 'paint':
       paint(pointer)
@@ -124,70 +137,9 @@ function handlePointer(pointer: Phaser.Input.Pointer) {
   }
 }
 
-function createCommandUpdate(x: number, y: number, tileName: string, operation: 'draw' | 'erase') {
-  if (!currentCommand) {
-    currentCommand = new EditorCommand(operation, tileName)
-  }
 
-  //If position is already in, do not proceed
-  for (const vec of currentCommand.affectedTiles) {
-    if (vec[0] === x && vec[1] === y) return
-  }
+// *** LIFECYCLE ***
 
-  currentCommand.affectedTiles.push([x, y])
-}
-
-function finalizeCommand() {
-  if (!currentCommand) return
-  //Cut the stack so the current edit is the last
-  commandStack = commandStack.slice(0, commandIndex.value)
-  commandStack.push(currentCommand)
-  if (commandStack.length >= 9) {
-    originTiles = applyCommands(originTiles, commandStack.shift()!)
-  }
-
-  commandIndex.value = commandStack.length
-  currentCommand = null
-}
-
-function undo() {
-  if (commandIndex.value > 0) {
-    commandIndex.value--
-    updateMapTiles()
-  }
-}
-
-function redo() {
-  if (commandIndex.value <= 9 && commandIndex.value <= commandStack.length) {
-    commandIndex.value++
-    updateMapTiles()
-  }
-}
-
-function applyCommands(tiles: string[][], ...commands: EditorCommand[]): string[][] {
-  let tileVersion = cloneArray(tiles)
-  for (let command of commands) {
-    for (const position of command.affectedTiles) {
-      tileVersion[position[1]][position[0]] = command.tileName
-    }
-  }
-  return tileVersion
-}
-
-function updateMapTiles() {
-  if (!mapEditor.currentMap.value) return
-
-  let indexedCommands = commandStack.slice(0, commandIndex.value)
-  let modifiedTiles = applyCommands(originTiles, ...indexedCommands)
-
-  placeTiles(props.tileMap, props.tileMapLayer, modifiedTiles)
-  mapEditor.currentMap.value.tiles = modifiedTiles
-}
-
-//Recursive Array Clone
-function cloneArray(arr: any[]): any[] {
-  return arr.map((item) => (item instanceof Array ? cloneArray(item) : item))
-}
 
 watch(
   () => mapEditor.shouldClearTiles.value,
@@ -205,9 +157,6 @@ onMounted(async () => {
   if (!mapEditor.currentMap.value) return
   const mapState = mapEditor.currentMap.value
 
-  //Clone
-  originTiles = cloneArray(mapState.tiles)
-
   placeTiles(props.tileMap, props.tileMapLayer, mapState.tiles)
 })
 </script>
diff --git a/src/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue b/src/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue
index 515d79f..278a799 100644
--- a/src/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue
+++ b/src/components/gameMaster/mapEditor/mapPartials/PlacedMapObjects.vue
@@ -16,7 +16,7 @@ import { uuidv4 } from '@/application/utilities'
 import PlacedMapObject from '@/components/game/map/partials/PlacedMapObject.vue'
 import SelectedPlacedMapObjectComponent from '@/components/gameMaster/mapEditor/partials/SelectedPlacedMapObject.vue'
 import { useMapEditorComposable } from '@/composables/useMapEditorComposable'
-import { getTile } from '@/services/mapService'
+import { cloneArray, getTile } from '@/services/mapService'
 import { useScene } from 'phavuer'
 import { computed, onMounted, onUnmounted, ref } from 'vue'
 
@@ -27,7 +27,9 @@ const scene = useScene()
 const mapEditor = useMapEditorComposable()
 const map = computed(() => mapEditor.currentMap.value!)
 
-defineExpose({ handlePointer })
+defineExpose({ handlePointer, finalizeCommand })
+
+const emit = defineEmits(['createCommand'])
 
 const props = defineProps<{
   tileMap: Tilemap
@@ -71,6 +73,9 @@ function pencil(pointer: Phaser.Input.Pointer, map: MapT) {
 
   // Add new object to mapObjects
   map.placedMapObjects.push(newPlacedMapObject)
+
+  createCommandUpdate(newPlacedMapObject, 'place')
+
   mapEditor.selectedPlacedObject.value = newPlacedMapObject
 }
 
@@ -79,6 +84,8 @@ function eraser(pointer: Phaser.Input.Pointer, map: MapT) {
   const existingPlacedMapObject = findObjectByPointer(pointer, map)
   if (!existingPlacedMapObject) return
 
+  createCommandUpdate(existingPlacedMapObject, 'delete')
+
   // Remove existing object
   map.placedMapObjects = map.placedMapObjects.filter((placedMapObject) => placedMapObject.id !== existingPlacedMapObject.id)
 }
@@ -102,11 +109,15 @@ function objectPicker(pointer: Phaser.Input.Pointer, map: MapT) {
 function moveMapObject(id: string, map: MapT) {
   mapEditor.movingPlacedObject.value = map.placedMapObjects.find((object) => object.id === id) as PlacedMapObjectT
 
+  let t: Tile
+
   function handlePointerMove(pointer: Phaser.Input.Pointer) {
     if (!mapEditor.movingPlacedObject.value) return
     const tile = getTile(props.tileMap, pointer.worldX, pointer.worldY)
     if (!tile) return
 
+    t = tile
+
     mapEditor.movingPlacedObject.value.positionX = tile.x
     mapEditor.movingPlacedObject.value.positionY = tile.y
   }
@@ -116,6 +127,9 @@ function moveMapObject(id: string, map: MapT) {
   function handlePointerUp() {
     scene.input.off(Phaser.Input.Events.POINTER_MOVE, handlePointerMove)
     mapEditor.movingPlacedObject.value = null
+
+    createCommandUpdate(mapEditor.movingPlacedObject.value!, 'move',  new Vector2(t.x, t.y))
+    finalizeCommand()
   }
 
   scene.input.on(Phaser.Input.Events.POINTER_UP, handlePointerUp)
@@ -128,6 +142,13 @@ function rotatePlacedMapObject(id: string, map: MapT) {
 
 function deletePlacedMapObject(id: string, map: MapT) {
   let mapE = mapEditor.currentMap.value!
+
+  const foundObject = mapE.placedMapObjects.find((obj) => obj.id === id)
+  if (!foundObject) return
+
+  createCommandUpdate(foundObject, 'delete')
+  finalizeCommand()
+
   mapE.placedMapObjects = map.placedMapObjects.filter((object) => object.id !== id)
   mapEditor.selectedPlacedObject.value = null
 }
diff --git a/src/components/gameMaster/mapEditor/partials/Toolbar.vue b/src/components/gameMaster/mapEditor/partials/Toolbar.vue
index 78c8e73..42a5843 100644
--- a/src/components/gameMaster/mapEditor/partials/Toolbar.vue
+++ b/src/components/gameMaster/mapEditor/partials/Toolbar.vue
@@ -150,6 +150,7 @@ function handleClick(tool: string) {
   mapEditor.setTool(tool)
   selectPencilOpen.value = tool === 'pencil' ? !selectPencilOpen.value : false
   selectEraserOpen.value = tool === 'eraser' ? !selectEraserOpen.value : false
+
 }
 
 function cycleToolMode(tool: 'pencil' | 'eraser') {
diff --git a/src/components/screens/MapEditor.vue b/src/components/screens/MapEditor.vue
index 0f5bbdf..71cef1e 100644
--- a/src/components/screens/MapEditor.vue
+++ b/src/components/screens/MapEditor.vue
@@ -34,6 +34,7 @@ import { MapStorage } from '@/storage/storages'
 import { useGameStore } from '@/stores/gameStore'
 import { Game, Scene } from 'phavuer'
 import { ref, useTemplateRef } from 'vue'
+import teleportModal from '@/components/gameMaster/mapEditor/partials/TeleportModal.vue'
 
 const mapStorage = new MapStorage()
 const mapEditor = useMapEditorComposable()
@@ -41,6 +42,7 @@ const gameStore = useGameStore()
 
 const mapModal = useTemplateRef('mapModal')
 const mapSettingsModal = useTemplateRef('mapSettingsModal')
+const teleportSettings = useTemplateRef('teleportModal')
 
 const isLoaded = ref(false)
 
@@ -86,15 +88,9 @@ function save() {
   if (!currentMap) return
 
   const data = {
+    ...currentMap,
     mapId: currentMap.id,
-    name: currentMap.name,
-    width: currentMap.width,
-    height: currentMap.height,
-    tiles: currentMap.tiles,
-    pvp: currentMap.pvp,
-    mapEffects: currentMap.mapEffects,
-    mapEventTiles: currentMap.mapEventTiles,
-    placedMapObjects: currentMap.placedMapObjects.map(({ id, mapObject, isRotated, positionX, positionY }) => ({ id, mapObject, isRotated, positionX, positionY })) ?? []
+    placedMapObjects: currentMap.placedMapObjects.map(({ id, mapObject, depth, isRotated, positionX, positionY }) => ({ id, mapObject, depth, isRotated, positionX, positionY })) ?? []
   }
 
   gameStore.connection?.emit('gm:map:update', data, (response: MapT) => {
diff --git a/src/services/mapService.ts b/src/services/mapService.ts
index c07f9ee..fd4d1bf 100644
--- a/src/services/mapService.ts
+++ b/src/services/mapService.ts
@@ -151,3 +151,8 @@ export function createTileLayer(tileMap: Phaser.Tilemaps.Tilemap, tilesArray: st
 
   return layer
 }
+
+//Recursive Array Clone
+export function cloneArray(arr: any[]): any[] {
+  return arr.map((item) => (item instanceof Array ? cloneArray(item) : item))
+}
\ No newline at end of file