66import com .mojang .brigadier .exceptions .Dynamic2CommandExceptionType ;
77import com .mojang .brigadier .exceptions .DynamicCommandExceptionType ;
88import com .mojang .brigadier .exceptions .SimpleCommandExceptionType ;
9- import com .mojang .datafixers .util .Pair ;
109import com .mojang .serialization .Codec ;
1110import com .mojang .serialization .DataResult ;
1211import com .mojang .serialization .DynamicOps ;
4544
4645import java .lang .reflect .Modifier ;
4746import java .lang .reflect .ParameterizedType ;
47+ import java .util .HashMap ;
4848import java .util .HashSet ;
4949import java .util .Map ;
5050import java .util .Objects ;
5151import java .util .Set ;
52+ import java .util .StringJoiner ;
53+ import java .util .function .BiConsumer ;
5254import java .util .function .Consumer ;
5355import java .util .function .Function ;
54- import java .util .stream .Collectors ;
55- import java .util .stream .Stream ;
5656
5757import static com .mojang .serialization .DataResult .error ;
5858import static com .mojang .serialization .DataResult .success ;
@@ -359,68 +359,20 @@ static DataResult<DataComponentMap> tryMapOf(Context cx, @Nullable Object o) {
359359 case Map <?, ?> map -> {
360360 var builder = DataComponentMap .builder ();
361361
362- var failed = false ;
363- Stream .Builder <Pair <DataComponentType <?>, String >> errors = Stream .builder ();
364-
365362 Map <DataComponentType <?>, ?> wrapped = Objects .requireNonNull (cx .optionalMapOf (map , COMPONENT_TYPE , TypeInfo .NONE ));
363+ Map <DataComponentType <?>, String > errors = new HashMap <>();
366364
367365 for (var entry : wrapped .entrySet ()) {
368- var type = entry .getKey ();
369- var valueType = getTypeInfo (type );
370-
371- var value = entry .getValue ();
372- EvaluatorException evalError = null ;
373-
374- if (value == null || value instanceof Undefined ) {
375- continue ;
376- }
377-
378- // TODO: remove once shouldConvert check is in Rhino
379- if (valueType != TypeInfo .NONE && cx .canConvert (value , valueType )) {
380- try {
381- Object converted = cx .jsToJava (value , valueType );
382- if (converted != null ) {
383- //noinspection rawtypes, unchecked
384- builder .set ((DataComponentType ) type , converted );
385- continue ;
386- }
387- } catch (EvaluatorException e ) {
388- evalError = e ;
389- }
390- }
391-
392- var codec = type .codec ();
393-
394- if (codec == null ) {
395- failed = true ;
396- errors .add (Pair .of (type , "Component has non-serializable type" ));
397- continue ;
398- }
399-
400- switch (codec .parse (reg .json (), JsonUtils .of (cx , value ))) {
401- case DataResult .Success <?> success ->
402- //noinspection rawtypes, unchecked
403- builder .set ((DataComponentType ) type , success .value ());
404- case DataResult .Error <?> error -> {
405- failed = true ;
406- String message = evalError != null
407- ? "Failed to parse component from type wrappers and codec! Native: %s, Codec: %s" .formatted (evalError .details (), error .message ())
408- : "Failed to parse component from codec: %s!" .formatted (error .message ());
409- errors .add (Pair .of (type , message ));
410- }
411- }
366+ wrapEntry (cx , entry , null , builder ::set , errors ::put );
412367 }
413368
414- if (failed ) {
415- var msg = errors .build ().map (pair -> {
416- var type = pair .getFirst ();
417- var error = pair .getSecond ();
418-
369+ if (!errors .isEmpty ()) {
370+ var joiner = new StringJoiner ("; " );
371+ errors .forEach ((type , error ) -> {
419372 var id = reg .access ().registryOrThrow (Registries .DATA_COMPONENT_TYPE ).getKeyOrNull (type );
420-
421- return "'%s' -> %s" .formatted (id , error );
422- }).collect (Collectors .joining ("; " ));
423- yield error (() -> "Invalid component map format, errored input: [%s]" .formatted (msg ), builder .build ());
373+ joiner .add ("'%s' -> %s" .formatted (id , error ));
374+ });
375+ yield error (() -> "Invalid component map format, errored input: [%s]" .formatted (joiner .toString ()), builder .build ());
424376 } else {
425377 yield success (builder .build ());
426378 }
@@ -448,69 +400,20 @@ static DataResult<DataComponentPatch> tryPatchOf(Context cx, @Nullable Object o)
448400 case Map <?, ?> map -> {
449401 var builder = DataComponentPatch .builder ();
450402
451- var failed = false ;
452- Stream .Builder <Pair <DataComponentType <?>, String >> errors = Stream .builder ();
453-
454403 Map <DataComponentType <?>, ?> wrapped = Objects .requireNonNull (cx .optionalMapOf (map , COMPONENT_TYPE , TypeInfo .NONE ));
404+ Map <DataComponentType <?>, String > errors = new HashMap <>();
455405
456406 for (var entry : wrapped .entrySet ()) {
457- var type = entry .getKey ();
458- var valueType = getTypeInfo (type );
459-
460- var value = entry .getValue ();
461- EvaluatorException evalError = null ;
462-
463- if (value == null || value instanceof Undefined ) {
464- builder .remove (type );
465- continue ;
466- }
467-
468- // TODO: remove once shouldConvert check is in Rhino
469- if (valueType != TypeInfo .NONE && cx .canConvert (value , valueType )) {
470- try {
471- Object converted = cx .jsToJava (value , valueType );
472- if (converted != null ) {
473- //noinspection rawtypes, unchecked
474- builder .set ((DataComponentType ) type , converted );
475- continue ;
476- }
477- } catch (EvaluatorException e ) {
478- evalError = e ;
479- }
480- }
481-
482- var codec = type .codec ();
483-
484- if (codec == null ) {
485- failed = true ;
486- errors .add (Pair .of (type , "Component has non-serializable type" ));
487- continue ;
488- }
489-
490- switch (codec .parse (reg .json (), JsonUtils .of (cx , value ))) {
491- case DataResult .Success <?> success ->
492- //noinspection rawtypes, unchecked
493- builder .set ((DataComponentType ) type , success .value ());
494- case DataResult .Error <?> error -> {
495- failed = true ;
496- String message = evalError != null
497- ? "Failed to parse component from type wrappers and codec! Native: %s, Codec: %s" .formatted (evalError .details (), error .message ())
498- : "Failed to parse component from codec: %s!" .formatted (error .message ());
499- errors .add (Pair .of (type , message ));
500- }
501- }
407+ wrapEntry (cx , entry , builder ::remove , builder ::set , errors ::put );
502408 }
503409
504- if (failed ) {
505- var msg = errors .build ().map (pair -> {
506- var type = pair .getFirst ();
507- var error = pair .getSecond ();
508-
410+ if (!errors .isEmpty ()) {
411+ var joiner = new StringJoiner ("; " );
412+ errors .forEach ((type , error ) -> {
509413 var id = reg .access ().registryOrThrow (Registries .DATA_COMPONENT_TYPE ).getKeyOrNull (type );
510-
511- return "'%s' -> %s" .formatted (id , error );
512- }).collect (Collectors .joining ("; " ));
513- yield error (() -> "Invalid component map format, errored input: [%s]" .formatted (msg ), builder .build ());
414+ joiner .add ("'%s' -> %s" .formatted (id , error ));
415+ });
416+ yield error (() -> "Invalid component map format, errored input: [%s]" .formatted (joiner .toString ()), builder .build ());
514417 } else {
515418 yield success (builder .build ());
516419 }
@@ -527,6 +430,56 @@ static DataResult<DataComponentPatch> tryPatchOf(Context cx, @Nullable Object o)
527430 };
528431 }
529432
433+ private static void wrapEntry (
434+ Context cx ,
435+ Map .Entry <DataComponentType <?>, ?> entry ,
436+ @ Nullable Consumer <DataComponentType <?>> ifNull ,
437+ @ SuppressWarnings ("rawtypes" ) BiConsumer <DataComponentType , Object > builder ,
438+ BiConsumer <DataComponentType <?>, String > error
439+ ) {
440+ var reg = RegistryAccessContainer .of (cx );
441+
442+ var type = entry .getKey ();
443+ var valueType = getTypeInfo (type );
444+
445+ var value = entry .getValue ();
446+
447+ if (value == null || value instanceof Undefined ) {
448+ if (ifNull != null ) {
449+ ifNull .accept (type );
450+ }
451+
452+ return ;
453+ }
454+
455+ EvaluatorException evalError = null ;
456+
457+ if (valueType .shouldConvert () && cx .canConvert (value , valueType )) {
458+ try {
459+ Object converted = cx .jsToJava (value , valueType );
460+ if (converted != null ) {
461+ builder .accept (type , converted );
462+ return ;
463+ }
464+ } catch (EvaluatorException e ) {
465+ evalError = e ;
466+ }
467+ }
468+
469+ var codec = type .codec ();
470+
471+ if (codec != null ) {
472+ switch (codec .parse (reg .json (), JsonUtils .of (cx , value ))) {
473+ case DataResult .Success <?> success -> builder .accept (type , success .value ());
474+ case DataResult .Error <?> err -> error .accept (type , evalError != null
475+ ? "Failed to parse component from type wrappers and codec! Native: %s, Codec: %s" .formatted (evalError .details (), err .message ())
476+ : "Failed to parse component from codec: %s!" .formatted (err .message ()));
477+ }
478+ } else {
479+ error .accept (type , "Component has non-serializable type" );
480+ }
481+ }
482+
530483 private static <B , T > DataResult <T > fnToBuilder (Context cx , Class <B > builderType , BaseFunction fn , Function <B , T > build ) {
531484 try {
532485 B builder = Cast .to (cx .createInterfaceAdapter (TypeInfo .of (builderType ), fn ));
0 commit comments