@@ -5,10 +5,12 @@ import dev.slne.surf.cloud.api.common.player.ppdc.PersistentPlayerDataAdapterCon
55import dev.slne.surf.cloud.api.common.player.ppdc.PersistentPlayerDataContainerView
66import dev.slne.surf.cloud.api.common.player.ppdc.PersistentPlayerDataType
77import dev.slne.surf.cloud.api.common.util.toObjectSet
8+ import it.unimi.dsi.fastutil.objects.ObjectArrayList
89import it.unimi.dsi.fastutil.objects.ObjectSet
910import net.kyori.adventure.key.Key
1011import net.kyori.adventure.nbt.*
1112import org.jetbrains.annotations.Unmodifiable
13+ import java.util.*
1214
1315abstract class PersistentPlayerDataContainerViewImpl : PersistentPlayerDataContainerView {
1416
@@ -112,8 +114,11 @@ abstract class PersistentPlayerDataContainerViewImpl : PersistentPlayerDataConta
112114 }
113115
114116 override fun snapshot (): PersistentPlayerDataContainerViewImpl {
117+ val tag = deepCopy(toTagCompound())
118+
119+
115120 val tagCopy = CompoundBinaryTag .builder() // TODO: deep copy
116- .put(toTagCompound() )
121+ .put(tag )
117122 .build()
118123
119124 return object : PersistentPlayerDataContainerViewImpl () {
@@ -122,4 +127,81 @@ abstract class PersistentPlayerDataContainerViewImpl : PersistentPlayerDataConta
122127 }
123128 }
124129
130+
131+ /* *
132+ * Creates a deep copy of the provided `CompoundBinaryTag` without using recursion.
133+ *
134+ * This function iterates through the tree structure of the `CompoundBinaryTag` in a non-recursive manner
135+ * to build a complete copy. It avoids stack overflow issues that can occur with deeply nested structures
136+ * when using a recursive approach.
137+ *
138+ * @param root The root `CompoundBinaryTag` to be deep copied.
139+ * @return A deep copy of the specified `CompoundBinaryTag`.
140+ */
141+ private fun deepCopy (root : CompoundBinaryTag ): CompoundBinaryTag {
142+ data class Frame (
143+ val entries : List <Pair <String , BinaryTag >>,
144+ var idx : Int ,
145+ val builder : CompoundBinaryTag .Builder ,
146+ val parent : Frame ? ,
147+ val parentKey : String?
148+ )
149+
150+ fun entriesOf (tag : CompoundBinaryTag ): List <Pair <String , BinaryTag >> {
151+ val list = ObjectArrayList <Pair <String , BinaryTag >>(tag.size())
152+ tag.forEach { (k, v) -> list.add(k to v) }
153+ return list
154+ }
155+
156+ val stack = ArrayDeque <Frame >()
157+ stack.addLast(
158+ Frame (
159+ entries = entriesOf(root),
160+ idx = 0 ,
161+ builder = CompoundBinaryTag .builder(),
162+ parent = null ,
163+ parentKey = null
164+ )
165+ )
166+
167+ var result: CompoundBinaryTag ? = null
168+
169+ while (stack.isNotEmpty()) {
170+ val top = stack.removeLast()
171+
172+ while (top.idx < top.entries.size) {
173+ val (key, value) = top.entries[top.idx++ ]
174+
175+ if (value is CompoundBinaryTag ) {
176+ stack.addLast(top)
177+ stack.addLast(
178+ Frame (
179+ entries = entriesOf(value),
180+ idx = 0 ,
181+ builder = CompoundBinaryTag .builder(),
182+ parent = top,
183+ parentKey = key
184+ )
185+ )
186+
187+ break
188+ } else {
189+ top.builder.put(key, value)
190+ }
191+ }
192+
193+
194+ if (top.idx >= top.entries.size) {
195+ val built = top.builder.build()
196+ if (top.parent == null ) {
197+ result = built
198+ } else {
199+ val parent = top.parent
200+ parent.builder.put(requireNotNull(top.parentKey), built)
201+ }
202+ }
203+ }
204+
205+ return requireNotNull(result)
206+ }
125207}
0 commit comments