5454public class LinOps implements DynamicOps <LinTag <?>> {
5555
5656 static final DynamicOps <LinTag <?>> INSTANCE = new LinOps ();
57- private static final LinTag <?> EMPTY_TAG = LinCompoundTag .of (Map .of ());
5857
5958 private LinOps () {
6059 }
6160
6261 @ Override
6362 public LinTag <?> empty () {
64- return EMPTY_TAG ;
63+ return LinEndTag . instance () ;
6564 }
6665
6766 @ Override
@@ -71,7 +70,7 @@ public LinTag<?> emptyList() {
7170
7271 @ Override
7372 public LinTag <?> emptyMap () {
74- return EMPTY_TAG ;
73+ return LinCompoundTag . builder (). build () ;
7574 }
7675
7776 @ Override
@@ -177,11 +176,68 @@ public DataResult<LinTag<?>> mergeToMap(final LinTag<?> map, final LinTag<?> key
177176 return DataResult .error (() -> "key is not a string: " + key , map );
178177 }
179178 if (map instanceof LinCompoundTag mapCompoundTag ) {
179+ if (value == empty ()) {
180+ return DataResult .success (mapCompoundTag );
181+ }
180182 return DataResult .success (mapCompoundTag .toBuilder ().put (keyStringTag .value (), value ).build ());
181183 }
184+ if (value == empty ()) {
185+ return DataResult .success (emptyMap ());
186+ }
182187 return DataResult .success (LinCompoundTag .builder ().put (keyStringTag .value (), value ).build ());
183188 }
184189
190+ @ Override
191+ public DataResult <LinTag <?>> mergeToMap (final LinTag <?> map , final MapLike <LinTag <?>> values ) {
192+ if (!(map instanceof LinCompoundTag ) && !(map instanceof LinEndTag )) {
193+ return DataResult .error (() -> "mergeToMap called with not a map: " + map , map );
194+ }
195+ final Iterator <Pair <LinTag <?>, LinTag <?>>> iterator = values .entries ().iterator ();
196+ if (!iterator .hasNext ()) {
197+ // if map is LinEndTag (returned by empty()) return a functional empty map
198+ return map == empty () ? DataResult .success (this .emptyMap ()) : DataResult .success (map );
199+ }
200+ LinCompoundTag .Builder resultBuilder = map instanceof LinCompoundTag compoundTag ?
201+ compoundTag .toBuilder () : LinCompoundTag .builder ();
202+ List <LinTag <?>> nonStringKeys = new ArrayList <>();
203+ iterator .forEachRemaining (entry -> {
204+ LinTag <?> key = entry .getFirst ();
205+ if (key instanceof LinStringTag keyStringTag ) {
206+ if (entry .getSecond () != empty ()) {
207+ resultBuilder .put (keyStringTag .value (), entry .getSecond ());
208+ }
209+ } else {
210+ nonStringKeys .add (key );
211+ }
212+ });
213+ return nonStringKeys .isEmpty () ? DataResult .success (resultBuilder .build ()) :
214+ DataResult .error (() -> "some keys are not strings: " + nonStringKeys );
215+ }
216+
217+ @ Override
218+ public DataResult <LinTag <?>> mergeToMap (final LinTag <?> map , final Map <LinTag <?>, LinTag <?>> values ) {
219+ if (!(map instanceof LinCompoundTag ) && !(map instanceof LinEndTag )) {
220+ return DataResult .error (() -> "mergeToMap called with not a map: " + map , map );
221+ }
222+ if (values .isEmpty ()) {
223+ return map == empty () ? DataResult .success (this .emptyMap ()) : DataResult .success (map );
224+ }
225+ LinCompoundTag .Builder resultBuilder = map instanceof LinCompoundTag compoundTag ?
226+ compoundTag .toBuilder () : LinCompoundTag .builder ();
227+ List <LinTag <?>> nonStringKeys = new ArrayList <>();
228+ values .forEach ((key , value ) -> {
229+ if (key instanceof LinStringTag keyStringTag ) {
230+ if (value != empty ()) {
231+ resultBuilder .put (keyStringTag .value (), value );
232+ }
233+ } else {
234+ nonStringKeys .add (key );
235+ }
236+ });
237+ return nonStringKeys .isEmpty () ? DataResult .success (resultBuilder .build ()) :
238+ DataResult .error (() -> "some keys are not strings: " + nonStringKeys );
239+ }
240+
185241 @ Override
186242 public DataResult <Stream <Pair <LinTag <?>, LinTag <?>>>> getMapValues (final LinTag <?> input ) {
187243 if (input instanceof LinCompoundTag tag ) {
@@ -241,7 +297,7 @@ public String toString() {
241297 @ Override
242298 public LinTag <?> createMap (final Stream <Pair <LinTag <?>, LinTag <?>>> map ) {
243299 LinCompoundTag .Builder builder = LinCompoundTag .builder ();
244- map .forEach (pair -> {
300+ map .filter ( pair -> pair . getSecond () != empty ()). forEach (pair -> {
245301 if (pair .getFirst () instanceof LinStringTag key ) {
246302 builder .put (key .value (), pair .getSecond ());
247303 return ;
@@ -309,7 +365,16 @@ public LinByteTag next() {
309365 @ Override
310366 public DataResult <Consumer <Consumer <LinTag <?>>>> getList (final LinTag <?> input ) {
311367 if (input instanceof LinListTag <?> tag ) {
312- return DataResult .success (consumer -> tag .value ().forEach (consumer ));
368+ return DataResult .success (consumer -> tag .value ().forEach (entry -> {
369+ // Handling of mixed lists: NbtOps doesn't need to do that here given the net.minecraft.nbt.ListTag unwraps the
370+ // entries on insertion. LinListTag doesn't allow mixed list content, so we unwrap on read.
371+ // the only location this is used currently should be components (i.e. sign text)
372+ if (entry instanceof LinCompoundTag compoundTag && compoundTag .value ().size () == 1 && compoundTag .value ().containsKey ("" )) {
373+ consumer .accept (compoundTag .value ().get ("" ));
374+ return ;
375+ }
376+ consumer .accept (entry );
377+ }));
313378 }
314379 if (input instanceof LinByteArrayTag tag ) {
315380 return DataResult .success (consumer -> {
@@ -570,7 +635,10 @@ protected LinCompoundTag.Builder initBuilder() {
570635
571636 @ Override
572637 protected LinCompoundTag .Builder append (final String key , final LinTag <?> value , final LinCompoundTag .Builder builder ) {
573- return builder .put (key , value );
638+ if (value != ops ().empty ()) {
639+ return builder .put (key , value );
640+ }
641+ return builder ;
574642 }
575643
576644 @ Override
0 commit comments