prthm11 commited on
Commit
16fa0e2
·
verified ·
1 Parent(s): 7d7a14e

Update utils/block_relation_builder.py

Browse files
Files changed (1) hide show
  1. utils/block_relation_builder.py +137 -85
utils/block_relation_builder.py CHANGED
@@ -2508,8 +2508,8 @@ def process_scratch_blocks(all_generated_blocks, generated_output_json):
2508
 
2509
  # Initialize dictionaries to store and reuse generated unique IDs
2510
  # This prevents creating multiple unique IDs for the same variable/broadcast across different blocks
2511
- variable_id_map = defaultdict(lambda: generate_secure_token())
2512
- broadcast_id_map = defaultdict(lambda: generate_secure_token())
2513
 
2514
  # Define the mapping for input field names to their required integer types for shadows
2515
  input_type_mapping = {
@@ -2534,6 +2534,31 @@ def process_scratch_blocks(all_generated_blocks, generated_output_json):
2534
  "VALUE_STRING": 10 # Used internally for VALUE when it should be type 10
2535
  }
2536
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2537
  for block_id, gen_block_data in generated_output_json.items():
2538
  processed_block = {}
2539
  all_gen_block_data = all_generated_blocks.get(block_id, {})
@@ -2549,13 +2574,14 @@ def process_scratch_blocks(all_generated_blocks, generated_output_json):
2549
  if "mutation" in all_gen_block_data:
2550
  processed_block["mutation"] = all_gen_block_data["mutation"]
2551
 
 
 
2552
  # Process inputs
2553
  if "inputs" in all_gen_block_data:
2554
  for input_name, input_data in all_gen_block_data["inputs"].items():
 
2555
  if input_name == "BROADCAST_INPUT":
2556
- # Special handling for BROADCAST_INPUT (type 11)
2557
  if isinstance(input_data, dict) and input_data.get("kind") == "value":
2558
- # This is the new logic to handle a direct value for broadcast
2559
  menu_option = input_data.get("value", "message1")
2560
  broadcast_id = broadcast_id_map[menu_option]
2561
  processed_block["inputs"][input_name] = [
@@ -2567,23 +2593,26 @@ def process_scratch_blocks(all_generated_blocks, generated_output_json):
2567
  ]
2568
  ]
2569
  elif isinstance(input_data, list) and len(input_data) == 2 and isinstance(input_data[1], list) and len(input_data[1]) == 3 and input_data[1][0] == 11:
2570
- # Preserve existing well-formed type 11 structure
2571
  processed_block["inputs"][input_name] = input_data
2572
  else:
2573
- # Fallback for unexpected formats, try to use the original if possible
2574
- processed_block["inputs"][input_name] = gen_block_data["inputs"].get(input_name, [1, [11, "message1", generate_secure_token()]])
2575
-
2576
- elif isinstance(input_data, dict):
2577
- if input_data.get("kind") == "value":
 
 
 
 
 
2578
  # Determine the correct shadow type based on the input_name and opcode
2579
- shadow_type = input_type_mapping.get(input_name, 4) # Default to 4
2580
-
2581
- # Specific override for "NUM" in "looks_goforwardbackwardlayers"
2582
- if input_name == "NUM" and processed_block["opcode"] == "looks_goforwardbackwardlayers":
2583
  shadow_type = 7
2584
-
2585
- # Specific override for "VALUE" in "data_setvariableto"
2586
- if input_name == "VALUE" and processed_block["opcode"] == "data_setvariableto":
2587
  shadow_type = 10
2588
 
2589
  processed_block["inputs"][input_name] = [
@@ -2593,119 +2622,142 @@ def process_scratch_blocks(all_generated_blocks, generated_output_json):
2593
  str(input_data.get("value", ""))
2594
  ]
2595
  ]
2596
- elif input_data.get("kind") == "block":
2597
- # Case 3: Nested block input
 
 
2598
  nested_block_id = input_data.get("block", "")
2599
-
2600
  if nested_block_id in all_generated_blocks:
 
 
 
 
 
2601
  nested_block_opcode = all_generated_blocks[nested_block_id].get("op_code")
2602
-
2603
  if input_name in ["SUBSTACK", "CONDITION", "SUBSTACK2"]:
2604
- # These are control flow blocks, should always be type 2
2605
  processed_block["inputs"][input_name] = [2, nested_block_id]
2606
  elif nested_block_opcode in ["data_variable", "data_listcontents"]:
2607
- # It's a variable/list reporter, should be type 12 inside type 1
2608
  variable_name = all_generated_blocks[nested_block_id].get("fields", {}).get("VARIABLE", ["", ""])[0]
2609
  variable_id = all_generated_blocks[nested_block_id].get("fields", {}).get("VARIABLE", ["", ""])[1]
2610
  if not variable_id:
2611
  variable_id = variable_id_map[variable_name]
2612
  processed_block["inputs"][input_name] = [1, [12, variable_name, variable_id]]
2613
  elif input_name in ["TOUCHINGOBJECTMENU", "TO", "TOWARDS", "CLONE_OPTION", "SOUND_MENU", "KEY_OPTION", "OBJECT"]:
2614
- # These are menu/dropdown inputs that refer to another block/menu,
2615
- # and should be type 1, referring to a shadow block.
2616
  processed_block["inputs"][input_name] = [1, nested_block_id]
2617
  else:
2618
- # For other reporter blocks (like motion_xposition, operators),
2619
- # they should be type 3 when nested.
2620
- shadow_type_for_nested = input_type_mapping.get(input_name, 10) # Default to 10 for nested shadows
2621
- processed_block["inputs"][input_name] = [3, nested_block_id, [shadow_type_for_nested, ""]] # Empty shadow value
2622
  else:
2623
- # If the referenced block doesn't exist, treat as a broken reference for now
2624
- # or try to use original if available.
2625
- processed_block["inputs"][input_name] = gen_block_data["inputs"].get(input_name, [3, nested_block_id, [10, ""]]) # Fallback
2626
-
2627
- elif input_data.get("kind") == "menu":
2628
- # This handles menu inputs from all_gen_block_data that are not BROADCAST_INPUT
2629
- menu_option = input_data.get("option", "")
2630
- # These should typically be type 1 referring to a shadow block, or a direct value if no shadow block
2631
- # For simplicity, we'll try to get the block ID if it's a menu block.
2632
  if "block" in input_data:
2633
- processed_block["inputs"][input_name] = [1, input_data["block"]]
 
 
 
 
2634
  else:
2635
- # If it's a menu without a block reference, it might be a direct value in a shadow.
2636
- # This case is less common for menu 'kind'.
2637
- processed_block["inputs"][input_name] = [1, [10, menu_option]] # Default to type 10 for string menu options
2638
-
2639
-
2640
- elif isinstance(input_data, list):
2641
- # This branch handles existing list structures from all_gen_block_data (or generated_output_json if no all_gen_block_data)
2642
- # It needs to decide if it's a direct value, a block reference, or a special type (11, 12)
2643
 
 
 
 
 
2644
  if len(input_data) == 2:
2645
  first_val = input_data[0]
2646
  second_val = input_data[1]
2647
 
 
2648
  if isinstance(second_val, str) and second_val in all_generated_blocks:
2649
- # The second element is a block ID
 
 
 
 
2650
  nested_block_opcode = all_generated_blocks[second_val].get("op_code")
2651
 
2652
  if input_name in ["SUBSTACK", "CONDITION", "SUBSTACK2"]:
2653
- # These are control flow blocks, should always be type 2
2654
  processed_block["inputs"][input_name] = [2, second_val]
2655
  elif nested_block_opcode in ["data_variable", "data_listcontents"]:
2656
- # It's a variable/list reporter, should be type 12 inside type 1
2657
  variable_name = all_generated_blocks[second_val].get("fields", {}).get("VARIABLE", ["", ""])[0]
2658
  variable_id = all_generated_blocks[second_val].get("fields", {}).get("VARIABLE", ["", ""])[1]
2659
  if not variable_id:
2660
  variable_id = variable_id_map[variable_name]
2661
  processed_block["inputs"][input_name] = [1, [12, variable_name, variable_id]]
2662
  elif input_name in ["TOUCHINGOBJECTMENU", "TO", "TOWARDS", "CLONE_OPTION", "SOUND_MENU", "KEY_OPTION", "OBJECT"]:
2663
- # These are menu/dropdown inputs that refer to another block/menu,
2664
- # and should be type 1, referring to a shadow block.
2665
  processed_block["inputs"][input_name] = [1, second_val]
2666
  else:
2667
- # For other reporter blocks (like motion_xposition, operators),
2668
- # they should be type 3 when nested. Correct the first_val if it's not 3.
2669
  shadow_type_for_nested = input_type_mapping.get(input_name, 10)
 
2670
  processed_block["inputs"][input_name] = [3, second_val, [shadow_type_for_nested, ""]]
 
2671
 
2672
- elif isinstance(second_val, str):
2673
- # It's a value literal (e.g., "-240") that needs wrapping with a shadow type
2674
- shadow_type = input_type_mapping.get(input_name, 4) # Default to 4
2675
- if input_name == "NUM" and processed_block["opcode"] == "looks_goforwardbackwardlayers":
2676
  shadow_type = 7
2677
- if input_name == "VALUE" and processed_block["opcode"] == "data_setvariableto":
2678
  shadow_type = 10
2679
  processed_block["inputs"][input_name] = [1, [shadow_type, str(second_val)]]
2680
- else:
2681
- # Fallback for other 2-element lists (e.g., [1, [11, ...]]), copy as is
2682
- processed_block["inputs"][input_name] = input_data
 
 
2683
 
2684
  elif len(input_data) == 3 and isinstance(input_data[1], str) and isinstance(input_data[2], list):
2685
- # Case: [3, "block_id", [shadow_type, shadow_value]] - an already well-formed nested block
2686
- # or [1, "block_id", [shadow_type, shadow_value]] - an existing shadow for a direct value
2687
- # Preserve these if they conform to the rules, otherwise correct shadow type
2688
- if input_data[0] == 3 and input_data[1] in all_generated_blocks:
2689
- # This is a valid type 3 nested block, keep it as is
2690
- processed_block["inputs"][input_name] = input_data
2691
- elif input_data[0] == 1 and isinstance(input_data[1], list) and input_data[1][0] in [11, 12]:
2692
- # This is a type 11 or 12 structure, preserve it
2693
- processed_block["inputs"][input_name] = input_data
2694
- elif input_data[0] == 1 and isinstance(input_data[1], list) and len(input_data[1]) == 2:
2695
- # This is a type 1 with a shadow, re-evaluate shadow type
2696
- shadow_type = input_type_mapping.get(input_name, 4)
2697
- if input_name == "NUM" and processed_block["opcode"] == "looks_goforwardbackwardlayers":
2698
- shadow_type = 7
2699
- if input_name == "VALUE" and processed_block["opcode"] == "data_setvariableto":
2700
- shadow_type = 10
2701
- processed_block["inputs"][input_name] = [input_data[0], [shadow_type, str(input_data[1][1])]]
2702
- else:
2703
- # Fallback for other 3-element lists, copy as is
2704
- processed_block["inputs"][input_name] = input_data
 
 
 
 
 
 
 
 
 
 
 
 
 
2705
  else:
2706
- # Fallback for any other unexpected list formats, copy as is
2707
  processed_block["inputs"][input_name] = input_data
 
2708
 
 
 
2709
 
2710
  # Process fields
2711
  if "fields" in all_gen_block_data:
@@ -2751,7 +2803,7 @@ def process_scratch_blocks(all_generated_blocks, generated_output_json):
2751
 
2752
  # Check if TOUCHINGOBJECTMENU input exists and is a block reference
2753
  referenced_block_id = None
2754
- if "TOUCHINGOBJECTMENU" in all_gen_block_data["inputs"]:
2755
  input_val = all_gen_block_data["inputs"]["TOUCHINGOBJECTMENU"]
2756
  if isinstance(input_val, list) and len(input_val) > 1 and isinstance(input_val[1], str):
2757
  referenced_block_id = input_val[1]
@@ -2769,7 +2821,7 @@ def process_scratch_blocks(all_generated_blocks, generated_output_json):
2769
  else:
2770
  processed_block["fields"][field_name] = field_value
2771
 
2772
- # Remove unwanted keys from the processed block
2773
  keys_to_remove = ["functionality", "block_shape", "id", "block_name", "block_type"]
2774
  for key in keys_to_remove:
2775
  if key in processed_block:
 
2508
 
2509
  # Initialize dictionaries to store and reuse generated unique IDs
2510
  # This prevents creating multiple unique IDs for the same variable/broadcast across different blocks
2511
+ variable_id_map = defaultdict(lambda: generate_secure_token(20))
2512
+ broadcast_id_map = defaultdict(lambda: generate_secure_token(20))
2513
 
2514
  # Define the mapping for input field names to their required integer types for shadows
2515
  input_type_mapping = {
 
2534
  "VALUE_STRING": 10 # Used internally for VALUE when it should be type 10
2535
  }
2536
 
2537
+ # Explicit mapping of opcodes -> expected menu inputs that MUST be simple menu/shadow links ([1, block_id])
2538
+ explicit_menu_links = {
2539
+ "motion_goto": [("TO", "motion_goto_menu")],
2540
+ "motion_glideto": [("TO", "motion_glideto_menu")],
2541
+ "motion_pointtowards": [("TOWARDS", "motion_pointtowards_menu")],
2542
+ "sensing_keypressed": [("KEY_OPTION", "sensing_keyoptions")],
2543
+ "sensing_of": [("OBJECT", "sensing_of_object_menu")],
2544
+ "sensing_touchingobject": [("TOUCHINGOBJECTMENU", "sensing_touchingobjectmenu")],
2545
+ "control_create_clone_of": [("CLONE_OPTION", "control_create_clone_of_menu")],
2546
+ "sound_play": [("SOUND_MENU", "sound_sounds_menu")],
2547
+ "sound_playuntildone": [("SOUND_MENU", "sound_sounds_menu")],
2548
+ "looks_switchcostumeto": [("COSTUME", "looks_costume")],
2549
+ "looks_switchbackdropto": [("BACKDROP", "looks_backdrops")],
2550
+ }
2551
+
2552
+ # helper to check if this opcode+input_name is an explicit menu link
2553
+ def is_explicit_menu_opcode_input(opcode, input_name):
2554
+ if not opcode:
2555
+ return False
2556
+ pairs = explicit_menu_links.get(opcode, [])
2557
+ for inp, _menu in pairs:
2558
+ if inp == input_name:
2559
+ return True
2560
+ return False
2561
+
2562
  for block_id, gen_block_data in generated_output_json.items():
2563
  processed_block = {}
2564
  all_gen_block_data = all_generated_blocks.get(block_id, {})
 
2574
  if "mutation" in all_gen_block_data:
2575
  processed_block["mutation"] = all_gen_block_data["mutation"]
2576
 
2577
+ opcode = processed_block["opcode"] # convenience
2578
+
2579
  # Process inputs
2580
  if "inputs" in all_gen_block_data:
2581
  for input_name, input_data in all_gen_block_data["inputs"].items():
2582
+ # --- BROADCAST INPUT special handling (type 11) ---
2583
  if input_name == "BROADCAST_INPUT":
 
2584
  if isinstance(input_data, dict) and input_data.get("kind") == "value":
 
2585
  menu_option = input_data.get("value", "message1")
2586
  broadcast_id = broadcast_id_map[menu_option]
2587
  processed_block["inputs"][input_name] = [
 
2593
  ]
2594
  ]
2595
  elif isinstance(input_data, list) and len(input_data) == 2 and isinstance(input_data[1], list) and len(input_data[1]) == 3 and input_data[1][0] == 11:
2596
+ # Preserve well-formed existing type 11 structure
2597
  processed_block["inputs"][input_name] = input_data
2598
  else:
2599
+ # Fallback: try original generated_output_json value if present, else synthesize
2600
+ fallback = gen_block_data.get("inputs", {}).get(input_name,
2601
+ [1, [11, "message1", generate_secure_token(20)]])
2602
+ processed_block["inputs"][input_name] = fallback
2603
+ continue
2604
+
2605
+ # --- Input described as a dict (value, block, menu) ---
2606
+ if isinstance(input_data, dict):
2607
+ kind = input_data.get("kind")
2608
+ if kind == "value":
2609
  # Determine the correct shadow type based on the input_name and opcode
2610
+ shadow_type = input_type_mapping.get(input_name, 4) # default 4
2611
+
2612
+ # Specific overrides
2613
+ if input_name == "NUM" and opcode == "looks_goforwardbackwardlayers":
2614
  shadow_type = 7
2615
+ if input_name == "VALUE" and opcode == "data_setvariableto":
 
 
2616
  shadow_type = 10
2617
 
2618
  processed_block["inputs"][input_name] = [
 
2622
  str(input_data.get("value", ""))
2623
  ]
2624
  ]
2625
+ continue
2626
+
2627
+ if kind == "block":
2628
+ # nested block reference via dict
2629
  nested_block_id = input_data.get("block", "")
 
2630
  if nested_block_id in all_generated_blocks:
2631
+ # If this opcode+input_name is explicitly a menu -> force [1, nested_block_id]
2632
+ if is_explicit_menu_opcode_input(opcode, input_name):
2633
+ processed_block["inputs"][input_name] = [1, nested_block_id]
2634
+ continue
2635
+
2636
  nested_block_opcode = all_generated_blocks[nested_block_id].get("op_code")
2637
+
2638
  if input_name in ["SUBSTACK", "CONDITION", "SUBSTACK2"]:
 
2639
  processed_block["inputs"][input_name] = [2, nested_block_id]
2640
  elif nested_block_opcode in ["data_variable", "data_listcontents"]:
2641
+ # variable/list reporter inside a reporter -> [1, [12, name, id]]
2642
  variable_name = all_generated_blocks[nested_block_id].get("fields", {}).get("VARIABLE", ["", ""])[0]
2643
  variable_id = all_generated_blocks[nested_block_id].get("fields", {}).get("VARIABLE", ["", ""])[1]
2644
  if not variable_id:
2645
  variable_id = variable_id_map[variable_name]
2646
  processed_block["inputs"][input_name] = [1, [12, variable_name, variable_id]]
2647
  elif input_name in ["TOUCHINGOBJECTMENU", "TO", "TOWARDS", "CLONE_OPTION", "SOUND_MENU", "KEY_OPTION", "OBJECT"]:
2648
+ # menu/dropdown inputs that refer to another block/menu -> type 1, refer to block id
 
2649
  processed_block["inputs"][input_name] = [1, nested_block_id]
2650
  else:
2651
+ # other reporter blocks (like motion_xposition, operators) -> nested type 3
2652
+ shadow_type_for_nested = input_type_mapping.get(input_name, 10)
2653
+ processed_block["inputs"][input_name] = [3, nested_block_id, [shadow_type_for_nested, ""]]
 
2654
  else:
2655
+ # referenced block missing: fallback to original input format if available, else a safe fallback
2656
+ processed_block["inputs"][input_name] = gen_block_data.get("inputs", {}).get(input_name, [3, nested_block_id, [10, ""]])
2657
+ continue
2658
+
2659
+ if kind == "menu":
2660
+ # menu kind: either references a block or a direct value
 
 
 
2661
  if "block" in input_data:
2662
+ # If explicit menu, ensure we store as [1, block_id]
2663
+ if is_explicit_menu_opcode_input(opcode, input_name):
2664
+ processed_block["inputs"][input_name] = [1, input_data["block"]]
2665
+ else:
2666
+ processed_block["inputs"][input_name] = [1, input_data["block"]]
2667
  else:
2668
+ # direct value in menu -> type 1 with a string shadow (type 10)
2669
+ menu_option = input_data.get("option", "")
2670
+ processed_block["inputs"][input_name] = [1, [10, menu_option]]
2671
+ continue
 
 
 
 
2672
 
2673
+ # --- Input is a list already (various formats) ---
2674
+ if isinstance(input_data, list):
2675
+ # Common shapes:
2676
+ # [1, <value shadow>], [1, <block_id>], [3, <block_id>, [shadow_type, value]], etc.
2677
  if len(input_data) == 2:
2678
  first_val = input_data[0]
2679
  second_val = input_data[1]
2680
 
2681
+ # If the second element is a block id that exists
2682
  if isinstance(second_val, str) and second_val in all_generated_blocks:
2683
+ # If explicit menu mapping -> force [1, block_id]
2684
+ if is_explicit_menu_opcode_input(opcode, input_name):
2685
+ processed_block["inputs"][input_name] = [1, second_val]
2686
+ continue
2687
+
2688
  nested_block_opcode = all_generated_blocks[second_val].get("op_code")
2689
 
2690
  if input_name in ["SUBSTACK", "CONDITION", "SUBSTACK2"]:
 
2691
  processed_block["inputs"][input_name] = [2, second_val]
2692
  elif nested_block_opcode in ["data_variable", "data_listcontents"]:
 
2693
  variable_name = all_generated_blocks[second_val].get("fields", {}).get("VARIABLE", ["", ""])[0]
2694
  variable_id = all_generated_blocks[second_val].get("fields", {}).get("VARIABLE", ["", ""])[1]
2695
  if not variable_id:
2696
  variable_id = variable_id_map[variable_name]
2697
  processed_block["inputs"][input_name] = [1, [12, variable_name, variable_id]]
2698
  elif input_name in ["TOUCHINGOBJECTMENU", "TO", "TOWARDS", "CLONE_OPTION", "SOUND_MENU", "KEY_OPTION", "OBJECT"]:
 
 
2699
  processed_block["inputs"][input_name] = [1, second_val]
2700
  else:
 
 
2701
  shadow_type_for_nested = input_type_mapping.get(input_name, 10)
2702
+ # Ensure nested reporters use type 3
2703
  processed_block["inputs"][input_name] = [3, second_val, [shadow_type_for_nested, ""]]
2704
+ continue
2705
 
2706
+ # If the second element is a string literal value -> wrap with appropriate shadow type
2707
+ if isinstance(second_val, str):
2708
+ shadow_type = input_type_mapping.get(input_name, 4) # default 4
2709
+ if input_name == "NUM" and opcode == "looks_goforwardbackwardlayers":
2710
  shadow_type = 7
2711
+ if input_name == "VALUE" and opcode == "data_setvariableto":
2712
  shadow_type = 10
2713
  processed_block["inputs"][input_name] = [1, [shadow_type, str(second_val)]]
2714
+ continue
2715
+
2716
+ # fallback: preserve the input as-is
2717
+ processed_block["inputs"][input_name] = input_data
2718
+ continue
2719
 
2720
  elif len(input_data) == 3 and isinstance(input_data[1], str) and isinstance(input_data[2], list):
2721
+ # case: [3, "block_id", [shadow_type, shadow_value]] or
2722
+ # [1, "block_id", [shadow_type, shadow_value]] (rare)
2723
+ block_ref = input_data[1]
2724
+ if block_ref in all_generated_blocks:
2725
+ # If explicit menu mapping -> convert to [1, block_id]
2726
+ if is_explicit_menu_opcode_input(opcode, input_name):
2727
+ processed_block["inputs"][input_name] = [1, block_ref]
2728
+ continue
2729
+
2730
+ # keep already well-formed nested reporter [3, ...]
2731
+ if input_data[0] == 3:
2732
+ processed_block["inputs"][input_name] = input_data
2733
+ continue
2734
+
2735
+ # If it's a type 1 with a type shadow like [1, [11,...]] or [1, [12,...]] -> preserve
2736
+ if input_data[0] == 1 and isinstance(input_data[1], list) and input_data[1][0] in [11, 12]:
2737
+ processed_block["inputs"][input_name] = input_data
2738
+ continue
2739
+
2740
+ # if it's [1, [shadow_type, value]] then re-evaluate shadow type
2741
+ if input_data[0] == 1 and isinstance(input_data[1], list) and len(input_data[1]) == 2:
2742
+ shadow_type = input_type_mapping.get(input_name, 4)
2743
+ if input_name == "NUM" and opcode == "looks_goforwardbackwardlayers":
2744
+ shadow_type = 7
2745
+ if input_name == "VALUE" and opcode == "data_setvariableto":
2746
+ shadow_type = 10
2747
+ processed_block["inputs"][input_name] = [input_data[0], [shadow_type, str(input_data[1][1])]]
2748
+ continue
2749
+
2750
+ # fallback: preserve the list as-is
2751
+ processed_block["inputs"][input_name] = input_data
2752
+ continue
2753
+
2754
  else:
2755
+ # other unexpected list shapes -> preserve for now
2756
  processed_block["inputs"][input_name] = input_data
2757
+ continue
2758
 
2759
+ # If input_data didn't match any of the above -> try to fallback to original generated value if available
2760
+ processed_block["inputs"][input_name] = gen_block_data.get("inputs", {}).get(input_name, input_data)
2761
 
2762
  # Process fields
2763
  if "fields" in all_gen_block_data:
 
2803
 
2804
  # Check if TOUCHINGOBJECTMENU input exists and is a block reference
2805
  referenced_block_id = None
2806
+ if "TOUCHINGOBJECTMENU" in all_gen_block_data.get("inputs", {}):
2807
  input_val = all_gen_block_data["inputs"]["TOUCHINGOBJECTMENU"]
2808
  if isinstance(input_val, list) and len(input_val) > 1 and isinstance(input_val[1], str):
2809
  referenced_block_id = input_val[1]
 
2821
  else:
2822
  processed_block["fields"][field_name] = field_value
2823
 
2824
+ # Remove unwanted keys from the processed block (if somehow present)
2825
  keys_to_remove = ["functionality", "block_shape", "id", "block_name", "block_type"]
2826
  for key in keys_to_remove:
2827
  if key in processed_block: